An agent in TRUSTIVAN is a workload — the same workload_identities row a CI credential is, with kind = 'agent' — delegated a slice of a human’s own authority, never a permission of its own. This page states exactly what is enforced on that delegation (a rule a request cannot get past), what is only observed (a fact surfaced for a person to review, that never refuses anything), and what is not built.

Identity and credentials

An agent authenticates with a twa_ workload credential: a 12-character prefix used to look the credential up, and a 52-character secret, hashed before storage. Rotation mints a new secret for the same prefix — the prefix is never secret and never rotates, so a caller that has cached it by prefix keeps working through a rotation instead of failing until it is updated out of band. A credential has an outer lifetime of at most twelve hours. Within it, a session bounds one run of work to a stated purpose, for at most four hours, and never longer than the credential’s own remaining life.

Enforced: the tool allowlist

Registering an agent does not grant it anything. An agent declares a set of tools — at most 64 — and each tool names, at most, one permission it requires to be invoked. A tool is a narrowing, never a source of authority: declaring a tool that requires a permission the agent’s delegator does not currently hold is not an error, it is a tool that will be refused the moment it is invoked, on that specific call, with that refusal recorded. Every invocation goes through one gate, server-side, on every call:
  1. Is the tool declared? An undeclared tool is refused and quarantines the agent — see below.
  2. Is the tool disabled? An operator can switch off a single tool without touching the rest of the agent’s inventory.
  3. Is the named session live — this agent’s own, not ended, not expired?
  4. Does the delegation, intersected with the delegator’s current role, actually hold what the tool requires? A demotion narrows this on the very next action; nothing is cached.
  5. Is the tool irreversible? If so, a human must have proven presence in the last five minutes by spending a single-use approval token issued at POST /agents/{id}/approvals for exactly this agent, tool and resource. The agent cannot claim a human is present itself — that field is set only by the server, only after consuming the token.
Every one of these five checks yields a decision — allow, step_up, deny, quarantine or revoke — and every decision is written, permitted or refused, to an append-only trail no application role may edit or delete. “Was this permitted last March, and why” is answerable from that trail alone.

Enforced: blast-radius containment

Quarantine stops an agent’s entire credential, reversibly. It triggers automatically on:
  • an invocation naming an undeclared tool,
  • an invocation naming a session that is not this agent’s own, or
  • any decision the broker marks terminal with a halt obligation.
It can also be triggered manually by an operator (policies:manage-equivalent permission workloads:manage), and it is never available to an agent against itself or a peer. Only a human lifts it — there is no automatic expiry, on the reasoning that a quarantine nobody looked at should never silently end. Quarantine is distinct from revocation: revocation ends the credential permanently (the kill switch, DELETE /api/v1/agents/{id}, which calls the same workload revocation the job plane checks on every request), quarantine suspends it while the credential survives. Tenant and permission boundaries are structural, not merely tested as a happy path: an agent’s authority is computed as delegation ∩ delegator's CURRENT role, is scoped to one organization by the same row-level security every tenant table carries, and revocation is checked on the credential itself — so a revoked agent is refused everywhere it authenticates, including scheduled jobs on the job plane, not only interactive API calls.

Observed, not enforced: behavioural signals

GET /agents/{id}/signals reports facts computed over an agent’s own recorded action history. Every action a signal fires on already passed the enforcement above — a signal never refuses anything, and it is not a second authorization path. Three kinds are computed today: volume_spike uses a fixed threshold, not a per-agent baseline — the simplest rule that is still evidence rather than noise. It will produce a false positive for an agent whose normal workload is genuinely this busy, and a false negative for a slower one that never reaches the ceiling in a single minute.

Limitations — stated, not implied

Two signals a mature design should eventually carry are not built:
  • Credential used from a new network source. An agent’s actions do not record a source address today, so there is nothing to compare “new” against.
  • Action outside a declared schedule. A tool declares what it does; it does not declare when it is expected to run.
Both would need a new column on the action trail before they could be built honestly, and this page will stop naming them as a limitation the day a release actually computes them — not before. Lifecycle and offboarding: an agent is owned by the human who delegated it (delegator_user_id, never null), and offboarding that human revokes every workload they delegated, agents included — not merely removes them from a listing.