Skip to content

Publish inventory with the Python SDK

Use this when Trust3 cannot discover your AI assets for you — agents you built yourself, or anything else that is code rather than a registered cloud resource. You add the Trust3 collector SDK to your own application, describe your agents, tools and models, and push that description to Trust3. They appear in the portal under AI Assets, ready for policies.

This is useful on its own. Publishing an inventory gives you the asset list, ownership and policy coverage, with no trace collection involved. If you also want to see each agent's real activity, monitoring adds that on top later — it needs more from your runtime plane, and you do not need any of it to get started here.

This is a change to your application code. Nothing is configured in the portal for it.


Before you begin

You need a runtime plane, because that is where the API key comes from — but only for the key. Basic Config is enough, and it is the shorter path: three steps, no storage, DNS, ingress or IAM role.

You need Where it comes from
Python 3.9 or later The application that runs your agents
Trust3 API key The x-pcloud-key value from the Deploy step of runtime plane creation

Create the runtime plane before you write any code

The API key is generated during runtime plane creation and shown once. Start at Basic setup if you do not have a runtime plane yet.

Choose Advanced setup instead only if you already know you want trace monitoring as well — that needs storage, DNS, ingress and an IAM role, none of which this page uses. Both paths produce the same key, so starting with Basic costs you nothing here.

Getting the API key

On the runtime plane's Deploy step, click the eye icon on the curl command and copy the value of the x-pcloud-key header. The same string appears as --password in the Helm command. It is displayed only once, so it should already be in your password manager — if it is not, you have to regenerate it, which invalidates the current key and means redeploying the runtime agent.

It is a runtime-plane credential, not a per-application key

The same value authenticates the runtime agent, downloads the runtime plane's values.yaml, and doubles as the Helm --password. It carries no expiry and is not scoped to one application, so treat it as shared infrastructure: keep it in your application's secret store rather than in source control or CI logs, and give it to as few applications as you can.


Step 1 — Install the SDK

Bash
pip3 install trust3-ai-collector-sdk

Step 2 — Decide what to publish

You publish a snapshot: a set of assets plus the relationships between them.

Asset kinds

Asset kind Use it for Appears in governance as
AGENT Each agent you run AIAgent
TOOL Each tool an agent can call MCPServer
MODEL Each unique provider:model pair Model
CONNECTOR Integrations the agent reaches (JIRA, GitLab, Slack …) MCPServer
IDENTITY Owners and users Identity
SCHEDULE Scheduled jobs CloudResource
PLATFORM, DATA_ASSET, RESOURCE Other assets you want governed —

Relationship kinds

Relationship kind Meaning
CAN_INVOKE Agent → tool it exposes, or orchestrator → sub-agent
USES_MODEL Agent → the LLM it uses
HAS_ACCESS_TO Owner or user → agent
RUNS_ON Schedule → the agent it targets

Using a kind outside these values is rejected by governance with an HTTP 422.

The same agent has three spellings — they are all the same thing

You write AssetKind.AGENT in code, the portal calls it AIAgent, and the generated identifier contains ai_agent. Expect to see all three; nothing has gone wrong. The same pattern applies to the other kinds.


Step 3 — Write the publish code

The snapshot below is not a standalone script you run once by hand. It belongs in your application's startup path, so the inventory refreshes every time you deploy — see When to run it.

To try it first, put it in a file such as publish_inventory.py, set the API key it reads, and run it directly:

Bash
export TRUST3_API_KEY=<your runtime plane API key>
python3 publish_inventory.py
Python
import json, os
from trust3_ai_collector_sdk import (
    Asset, AssetKind,
    InventoryClient, InventoryClientConfig,
    InventorySnapshot,
    Relationship, RelationshipKind,
)

snap = InventorySnapshot(
    source="my_platform",          # namespaces every asset id
    account="prod.example.com",    # the deployment this inventory describes
    vendor="Acme Corp",
    product_name="My Platform",
    environment="prod",            # dev / test / stage / prod
)

snap.assets += [
    Asset(
        kind=AssetKind.AGENT,
        id="billing_agent",
        name="Billing Agent",          # ← the name traces are matched on
        description="Answers billing questions",
        owners=["ops-team@example.com"],
        provider="openai",
        model_name="gpt-4o",
        properties={
            # The topics this agent is allowed to answer on — see below
            "provenance_json": json.dumps({"categories": ["billing", "customer_support"]}),
        },
    ),
    Asset(kind=AssetKind.MODEL, id="openai:gpt-4o", name="gpt-4o", provider="openai"),
    Asset(kind=AssetKind.TOOL, id="lookup_invoice", name="lookup_invoice"),
]

snap.relationships += [
    Relationship(kind=RelationshipKind.USES_MODEL,
                 from_id="billing_agent", from_kind=AssetKind.AGENT,
                 to_id="openai:gpt-4o",   to_kind=AssetKind.MODEL),
    Relationship(kind=RelationshipKind.CAN_INVOKE,
                 from_id="billing_agent",  from_kind=AssetKind.AGENT,
                 to_id="lookup_invoice",   to_kind=AssetKind.TOOL),
]

config = InventoryClientConfig(
    api_key=os.environ["TRUST3_API_KEY"],
)

with InventoryClient(config) as client:
    result = client.submit(snap)
    print(f"{result.assets_pushed} assets, {result.relationships_pushed} relationships "
          f"— status={result.status} governance={result.governance_status}")

TRUST3_API_KEY is a convention, not a requirement

The SDK does not read environment variables itself — you pass api_key to InventoryClientConfig explicitly. The name above is just a tidy way to keep the key out of your source code; use whatever your application already uses for configuration.

Keep source and account stable

They namespace every id you publish, so an agent with id billing_agent becomes my_platform:prod.example.com:ai_agent:billing_agent in governance.

Changing either one creates a parallel set of assets rather than updating the existing ones. Pick values you can keep, and use environment to distinguish dev from prod rather than changing account.

Name your agents carefully

The name field is what monitoring matches traces against, so:

  • give each agent a unique name
  • use the same string in your tracing configuration
  • avoid renaming an agent unless you also change the tracing side at the same time

Step 4 — Declare the topics an agent may answer on

provenance_json is where you declare an agent's allowed scope: a list of topics it is expected to answer on. Anything outside that list can be flagged as off-topic.

Python
"provenance_json": json.dumps({"categories": ["billing", "customer_support"]})

It is a JSON document stored as text inside the properties map, which is why it is wrapped in json.dumps(...) rather than written as a plain list.

The categories are free text — you choose the vocabulary. There is no fixed list and nothing validates them, so two rules follow:

  • Use the same strings your policy uses. Matching is exact, so project managemant will never match project management. A typo silently produces wrong verdicts rather than an error.
  • Describe what the agent is for. Everything not covered by the list becomes off-topic, so an over-narrow list flags legitimate traffic.

Off-topic detection needs three things, not one

Declaring categories is necessary but not sufficient. All three must hold:

  1. The agent declares categories via provenance_json — this step.
  2. Enable trace classification is on in the collector's Monitoring section, with a classifier provider, model, and API key — see Monitoring → trace classification.
  3. An active Off Topic policy exists in the Trust3 portal and covers this asset type. Off topic is a Runtime rule on a Cost Governance policy — see Policies.

An agent with no categories can never be flagged off-topic, however it is used. With classification on but no policy in place, categories are recorded but nothing acts on them.


When to run it

A snapshot is a full, idempotent push — governance upserts what it receives, so re-sending the same snapshot is safe and changes nothing.

The recommended pattern is to push on application startup, once your agent registry is built. That keeps the inventory current without any scheduling of its own, and a renamed or retired agent is reflected the next time you deploy.

Make the push non-fatal. Governance being unreachable should never stop your application from booting:

Python
1
2
3
4
5
try:
    with InventoryClient(config) as client:
        result = client.submit(snap)
except Exception:
    logger.warning("Trust3 inventory push failed", exc_info=True)   # carry on booting

Gate it behind a flag, so the same image runs unchanged in environments that should not publish — for example a TRUST3_AI_COLLECTOR_ENABLED variable, checked alongside the host and key before doing anything.


Handle errors

Python
1
2
3
4
5
6
7
8
from trust3_ai_collector_sdk.errors import InventoryValidationError, InventoryTransportError

try:
    result = client.submit(snap)
except InventoryValidationError as e:
    print(f"rejected (HTTP {e.status_code}): {e.response_text}")
except InventoryTransportError as e:
    print(f"failed after retries: {e}")

InventoryValidationError means governance rejected the payload — the message tells you what was wrong. InventoryTransportError means the request never succeeded after the SDK's automatic retries.


Verify

  1. Run your application, or the standalone script.
  2. Check the printed result. It reports how many assets and relationships were pushed and the governance HTTP status; a 2xx means governance accepted them.
  3. In the Trust3 portal, open AI Assets. Your agents, tools, and models appear there, one row per asset, named with the name you published.

If assets appear, your inventory is published. To see real activity against these assets, continue with Monitoring flowing against them.


Troubleshooting

Nothing appears in AI Assets

The push has not run, or it failed silently because you wrapped it in a bare except. Log the result of client.submit() and catch the two specific error types above.

HTTP 401 or 403

The API key is wrong. It must be the runtime plane's x-pcloud-key value, copied whole, with no surrounding whitespace or quotes.

HTTP 422

The payload was rejected. Almost always an asset or relationship kind outside the enumerated values listed above. The error message names the offending field.

Duplicate sets of the same agents

source or account changed between pushes. Both namespace every asset id, so a change creates a new parallel set rather than updating the existing one. Set them back to the original values and re-push.

Assets appear, but never show any activity

That is the monitoring half, and the usual cause is the name-matching rule. See Monitoring → troubleshooting.