Skip to main content

Identity

Status: Beta Companion docs: Scopes and assets · Identities API · Identity and RBAC

Give each autonomous AI agent its own non-human identity, or NHI. This lets you trace the agent, limit its access, issue a short-lived token, and stop its spend without sharing a human login.

Create an identity

The smallest identity needs a label:

from trinitite import Trinitite

tr = Trinitite()
nhi = tr.identity.create(label="refund-agent")

print(nhi.nhi_id)
print(nhi.label)
print(nhi.status)

The returned NhiHandle wraps the created identity. It gives you typed fields plus actions for that identity.

Add limits and ownership when you create it:

nhi = tr.identity.create(
label="refund-agent",
principal_user_id="usr_support_lead",
privilege_tier=2,
workload_id="refund-service",
workload_attestation_hash="sha256:replace_me",
max_spawn_depth=2,
)
FieldDefaultPurpose
labelRequiredHuman-readable agent name
principal_user_idNoneHuman owner for accountability
privilege_tier1Access tier from 1 through 3
workload_idNoneWorkload that runs the agent
workload_attestation_hashNoneIntegrity value for that workload
max_spawn_depthNoneLimit for child-agent chains
parent_nhi_idNoneParent identity for a child agent

Start with the lowest privilege tier that can do the job. This keeps an AI helper useful while limiting the impact of a bad prompt, tool, or credential.

Read an identity

Fetch an identity by ID:

nhi = tr.identity.get("nhi_123")

if not nhi.ok:
raise RuntimeError(nhi.body)

print(nhi.nhi_id)
print(nhi.label)
print(nhi.privilege_tier)
print(nhi.principal_user_id)
print(nhi.workload_id)
print(nhi.max_spawn_depth)
print(nhi.parent_nhi_id)
print(nhi.status)
print(nhi.scopes)
print(nhi.last_used_at)

List managed identities when you need an estate view:

response = tr.identity.list()

if response.ok:
for row in response.body.get("identities", []):
print(row["nhi_id"], row["label"])

Mint a short-lived token

Mint a Just-In-Time token only when the agent needs to act:

token_response = nhi.mint_token(
ttl_seconds=300,
task_correlation_id="refund-4821",
allowed_network_cidr="10.0.0.0/8",
)

if not token_response.ok:
raise RuntimeError(token_response.body)

jit_token = token_response.body["plaintext_token"]

The service limits token life to 30 through 900 seconds. The plaintext token is returned once and is meant for one use. Keep it in memory, send it only to Trinitite, and do not log it.

For an advanced proxy request, pass both identity headers:

proxy_response = tr.client_transport.request(
"POST",
"/v1/proxy/chat/completions",
json={
"model": "gpt-4o",
"messages": [
{"role": "user", "content": "Summarize refund ticket 4821."}
],
},
extra_headers={
"X-Trinitite-Credential-Id": "cred_openai_prod",
"X-Trinitite-Nhi-Id": nhi.nhi_id,
"X-Trinitite-Nhi-Token": jit_token,
},
)

The Trinitite API key still authenticates the application. The NHI ID and JIT token identify the agent inside that application.

Add a spend limit

Open an economic session for one identity:

session_response = nhi.economic_session(
spend_limit_usd=10.00,
)

if not session_response.ok:
raise RuntimeError(session_response.body)

session_id = session_response.body["session_id"]

When the session reaches its limit, later proxy calls for that NHI return HTTP 429 and mark the economic breaker as tripped.

An authorized operator can trip or reset the session:

trip_response = tr.identity.trip_session(
session_id,
reason="Unexpected spend pattern",
)

reset_response = tr.identity.reset_session(session_id)

List active sessions for one identity:

sessions = tr.identity.economic_sessions(
nhi_id=nhi.nhi_id,
active_only=True,
)

This gives AI teams a hard cost boundary without turning off every other agent.

Review tool attempts

Query the tool-attempt feed by identity:

attempts = tr.identity.tool_attempts(
nhi_id=nhi.nhi_id,
limit=50,
)

if attempts.ok:
for attempt in attempts.body.get("attempts", []):
print(attempt)

The feed helps you connect an AI action to the identity that tried it. Pair this with a narrow privilege tier and short token life to reduce risk.

Use the agent shortcut

Use tr.agent(...) when you want a goal scope and identity settings in one call:

support = tr.agent(
"support-bot",
goal="Resolve support tickets within policy",
identity="support-bot",
privilege_tier=2,
nhi_scopes=["tickets:read", "tickets:write"],
max_spawn_depth=2,
nhi_ttl=300,
)

client = support.client(
"openai",
credential="cred_openai_prod",
)

The service creates the scope and resolves or mints its NHI. The returned value is a ScopeHandle, so model and tool assets can bind to the same goal.

Use tr.identity.create(...) when identity lifecycle is the main task. Use tr.agent(...) when the agent's goal and assets should be set up together.

Revoke an identity

Revoke the identity when the agent is retired or a credential may be exposed:

response = nhi.delete(
reason="Refund agent retired",
)

if not response.ok:
raise RuntimeError(response.body)

You can also revoke by ID:

response = tr.identity.delete(
"nhi_123",
reason="Credential response",
)

Where to go next

  • Scopes and assets: bind the identity's model and tools to one goal.
  • Result: read the verdict and identity context from governed work.
  • Identities API: use the HTTP identity contract directly.