Agent registry
One record per agent, and it is the record the gateway enforces against.
On this page
An inventory nobody enforces against is a spreadsheet with better formatting
Most businesses discover their agent estate twice: once in a spreadsheet somebody assembles for an audit, and once in an incident. The spreadsheet lists the agents your team remembered; the incident involves the one they did not. That gap is structural rather than careless — an inventory maintained beside the runtime is updated by whoever remembers, while the runtime is updated by whoever ships, and the two diverge from the first week.
The questions an auditor actually asks are field-shaped. ISO/IEC 42001 A.4.2 asks for an AI system inventory. EU AI Act Art 26(1) asks that a system be used in accordance with its instructions, which requires a declared purpose to compare behaviour against. Art 26(2) asks that oversight be assigned to competent persons, which requires a named human per agent rather than a team alias. Each of those is answered by a field on the record — and each field is only worth having if it is the field the enforcement path reads, because a purpose nothing consults is a sentence in a document.
The second failure is quieter and shows up at review time. An access review that records agent X holds role Y certifies almost nothing, because role Y is editable and the review does not say what was in it. Six months later a named reviewer’s attestation sits beside a permission set they never saw, and nothing in the record distinguishes the two situations. Token Observe treats that as the defining problem of recertification rather than a detail of it.
How it actually works
Step 2 of the request path. The order is load-bearing rather than incidental: it is encoded in the evaluator, and the reason each step sits where it does is the reason the guarantee holds.
- 01
Register the record
POST /api/agents with name, owner email, team and declared purpose. Status defaults to draft and risk tier to limited, so a record can exist before anyone decides to run it. Role ids are validated against the authoritative role rows inside the writing transaction and an unresolvable id is refused, naming the unknown ids — a dangling role id would otherwise reduce the agent to deny-by-default silently, which reads as a policy decision rather than a typo. - 02
Issue a credential
POST /api/agents/:id/keys returns a prefixed bearer token carrying 32 bytes of randomness in base64url, and it is the only copy that will ever exist. Token Observe stores its SHA-256 and a 16-character display prefix, which is the scheme plus six characters of the secret. Minting is admin-only: it hands out gateway authority for an agent, and that is the single most privileged action in the registry. - 03
Point the agent at the gateway
Change one base URL and one key. The agent presents its token on Authorization: Bearer, or on x-api-key for the Anthropic dialect. Step 1 of the request path digests the presented token, looks it up by digest, and re-compares in constant time, so a storage layer that ever answered a prefix match could not be turned into a byte-at-a-time oracle. - 04
The gateway resolves this record, not a copy of it
Step 2 loads the agent, its roles, the active kill switches and its recent spend window. Step 6, the single decision point, is what reads them, in a fixed order: engaged kill switches first, then the lifecycle check, deny-by-default RBAC, the budget and rate-limit ceilings, and finally the policies whose scope selects this subject — matched on agent id, on team (case-insensitively) and on tag (case-sensitively). - 05
Edit, and have the edit recorded
PATCH applies to the agent’s next governed request. Every change writes an audit row naming which of fourteen diffed fields moved — routing and the on-behalf-of requirement are not among them, so an edit to either is recorded without being named — alongside the new status and the previous one; a transition into suspended is also published as an agent.suspended event, because suspension is an operational fact other systems page and ticket on rather than something only an auditor reads later. - 06
Recertify against an exact configuration
An operator submits the agent’s updatedAt and the snapshot digest they inspected. The route checks both before writing the audit intent, and the store compares the whole canonical snapshot again inside the insert transaction. A concurrent edit — including one in the same clock tick — returns a typed 409 conflict rather than certifying configuration nobody read. - 07
Suspend, retire or revoke
Suspension flips the status, and the evaluator refuses that agent on its lifecycle check — after the kill-switch check and before RBAC, budgets or any policy runs. The refusal is taken at step 6 rather than at the door, so the attempt is still recorded against the trace opened at step 3 instead of vanishing. Revoking a key is one write and takes effect on the next authentication attempt. Retiring an agent and suspending it both free licensed capacity, and neither is ever refused on licence grounds.
What one agent record holds, and why each field is on it
Four fields are required — name, owner email, team and declared purpose — and the last two are the ones worth arguing about in the meeting. The owner email is the human accountable for a thing that is not a human, and it is lower-cased on write so accountability does not fork on capitalisation. The declared purpose is the field a regulator asks for; it is required rather than optional, capped at 4,000 characters, and it is carried verbatim into every recertification snapshot.
Everything else on the record exists because some part of the request path reads it. That is the test the registry is designed around: a field that nothing consults is documentation, and documentation drifts.
- Risk tier
- minimal, limited or high, defaulting to limited. It is displayed in the console, carried into the review snapshot, and is what a deployer’s ISO/IEC 42001 A.5.3 risk assessment attaches to. It is not, today, a policy-scope dimension: policy scope matches on agent id, team and tag, so a rule that should bite on your high-risk agents is written against a tag you set rather than against the tier.
- Team and tags
- Kill switches and policy scope both match on team case-insensitively, and on tags case-sensitively. The asymmetry is deliberate and worth knowing before you name things: Finance and finance are the same team to a kill switch, while pci and PCI are two different tags to a policy.
- Data policy
- Three independent booleans — require zero data retention, require no training on payloads, require a serving region — rather than one ZDR flag. Providers genuinely differ on each: a provider may retain but not train, or train but not retain, and EU region pinning is orthogonal to both. A single flag would overpromise, and routing at step 8 honours all three separately.
- Routing ceiling
- maxTier is a ceiling and not a target: an agent capped at standard never reaches a reasoning model however the router scores the task, which is what stops a cheap classifier quietly costing frontier prices. allowDowngrade is off by default, because silently serving a different model than the caller asked for has to be opted into. A PATCH merges the two field by field rather than replacing the object, since raising a ceiling and permitting a downgrade are separate decisions often made by separate people.
- On-behalf-of requirement
- Off by default. When on, a call from this agent naming no human principal is refused — but only where the on-behalf-of mask is switched on for the install at all, because requiring a header that changes no decision would be theatre. Set it on an agent acting inside one person’s authority, such as a copilot or a ticket triager, where an unattributed call is the anomaly rather than the norm.
- Metadata
- Free-form key/value strings, each value up to 2,000 characters: repository URL, ticket, environment, DPIA or FRIA reference. It is the field EU AI Act Art 26(9) evidence hangs off, and it travels verbatim into every recertification snapshot, where a named reviewer attests it and the snapshot digest seals it, rather than living only in the console. Note what that does not mean: the compliance export bundle is assembled from traces, approvals, audit entries and a chain verification, so the route from this field to an auditor is the review record rather than that bundle.
POST /api/agents
{
"name": "support-triage",
"ownerEmail": "priya.shah@example.com",
"team": "Support",
"purpose": "Draft first-response replies to customer tickets for a human to send.",
"riskTier": "limited",
"status": "active",
"roleIds": ["rol_2Fq8xN"],
"tags": ["customer-data"],
"budget": { "perRequestUsd": 0.5, "dailyUsd": 25, "monthlyUsd": 400 },
"dataPolicy": { "requireNoTraining": true, "requireRegion": "eu" },
"metadata": { "dpia": "DPIA-2026-014", "repo": "git.example.com/support-triage" }
}
201 agt_7Qk2Zpv4 status: active riskTier: limitedLifecycle, credentials, and what revocation actually does
There are four lifecycle states — draft, active, suspended, retired — and only active survives the evaluator’s lifecycle check. The four are held as a runtime list from which the type is derived, so a validation schema cannot start rejecting a state the domain still accepts. Seats governing developer subscriptions use the same four states and the same type, deliberately, because a second vocabulary would need a mapping that could only lose information at the exact point where losing it means failing open.
Credentials are write-once. The create-key response carries the only copy of the plaintext that will ever exist, alongside a warning that says so; Token Observe stores the SHA-256 and never logs, echoes or audits the secret itself. The audit row for a key records the agent, the display prefix and the expiry — never the token. Key lifetimes are optional and capped at 3,650 days.
Revocation is one write, and the effect is immediate on the next authentication attempt: any process still holding the key starts failing. Unknown, revoked and expired keys are three different operational events and are logged as three different events, but the caller receives one identical message for all of them, because telling someone their key merely expired confirms it was once valid.
Every rejection at the door is also folded into an hourly roll-up that the shadow-AI radar reads, which is how somebody is holding a credential we do not recognise becomes a finding rather than a log line nobody greps for. That roll-up records the reason and, where the credential resolved to a real key, the key and agent id. It deliberately stores neither the presented token nor a digest of it: a digest of a live secret is an offline oracle against that secret.
- Issuing a key
- Admin rank. Creating and editing agents is operator rank. Reading the registry is viewer rank. The console mirrors these ranks in what it offers, and the server remains authoritative.
- Last used
- Recorded on each successful authentication as fire-and-forget hygiene telemetry, so a key nobody has presented for six months is visible as such. Losing that write never fails the request it belongs to.
- No admin bearer token
- Control-plane access is session-only. An earlier revision of the API contract documented an admin bearer mode that was never implemented; the claim was removed rather than the feature added, because every control-plane action being attributable to a named person is what makes the audit log evidence.
Recertification binds a named human to an exact configuration
A recertification is an append-only attestation by one named reviewer over one exact governance-bearing configuration. The snapshot covers name, owner, team, lifecycle status, role ids, the effective role grants, framework, tags, purpose, risk tier, budgets, rate limits, data policy, routing, the on-behalf-of requirement and metadata. Presentation-only description and storage timestamps are excluded, because a review invalidated by someone fixing a typo in a description trains reviewers to click through.
The part that does the work is the role grant. Each referenced role is bound by name, permission count and a SHA-256 over its normalised permissions — not merely by its stable identifier. That is what makes the attestation mean something six months later: editing a role changes the live digest immediately and marks every affected review stale, while the historical snapshot of what was actually attested is left untouched. Ordering is normalised where it grants no different authority — role ids, tags and permission actions are de-duplicated and sorted — so harmless reordering does not manufacture staleness and dilute the signal.
The write is guarded twice. The route refuses unless the submitted updatedAt and snapshot digest match what the server holds, and then the store re-derives the entire canonical snapshot inside the insert transaction and compares it again. On PostgreSQL that transaction takes a write lock on the agent row and a share lock on its roles; the share lock is not belt and braces, because a lock on the agent takes no lock at all on the roles table, and a role update committing in that window would be recorded as immutable evidence for a permission set that no longer exists.
Validity is 1 to 3,650 days through the API, and the console offers 30, 90, 180 or 365. A snapshot larger than 64 KB is refused with a message telling the operator to reduce governance metadata, rather than being silently truncated into evidence that omits part of what was reviewed.
POST /api/agents/agt_7Qk2Zpv4/recertifications
{
"expectedAgentUpdatedAt": "2026-08-14T09:12:44.108Z",
"expectedSnapshotDigest": "9f1c4b…c4a2",
"validForDays": 90,
"reason": "Q3 access review. Owner confirmed. Refund tool grant removed."
}
409 conflict
agent agt_7Qk2Zpv4 changed after the review began;
reload and review the current configurationWhy a review can be shown as invalid, and why that is the honest answer
Two digests are stored. The snapshot digest is a SHA-256 over the canonical JSON of the configuration attested. The record digest is a second SHA-256, under its own domain separator, over the review id, agent id, reviewer id and email, the review and expiry times, the note and the snapshot digest — so the identity of the reviewer is bound to the thing reviewed rather than sitting beside it in a column.
SHA-256 alone does not resist someone who can write to the database, and Token Observe says so rather than implying otherwise. Before the review row is inserted, a durable audit intent is appended to the hash-chained log, and the review stores the exact sequence number and hash of that entry. On an install with no audit HMAC key configured, this proves internal consistency and carries the audit chain’s documented database-writer limit. Under the production-required HMAC configuration, the indexed entry must verify within its checkpoint-established MAC epoch and bind the same record digest, snapshot digest and expiry, and a review whose binding fails is presented as an audit binding mismatch rather than as evidence.
One consequence is deliberately awkward and is published as such: first HMAC initialisation does not retroactively authenticate isolated entries from the earlier unkeyed chain. A review created before the first keyed checkpoint therefore becomes invalid and has to be repeated. Promoting a legacy row without verifying its descendant path would let a database writer rewrite both the row and the domain record referencing it, so Token Observe asks for the human decision again rather than inventing a replacement for it.
An agent’s team is mutable, and history is filtered on the team captured in each review rather than projected onto today’s. A viewer scoped to the old team may read the reviews captured while the agent belonged there, but receives neither its current configuration nor its current posture; a viewer of the new team sees the current configuration and only the history from teams they may read. The paginated fleet register — the whole-estate view — requires an explicit organisation-wide evidence scope, because it cannot be honestly projected onto one team.
- never
- No named reviewer has ever attested this agent.
- current / due / overdue
- The latest review verifies and is in date, is inside the due window, or is past its validity. The window is 30 days, and the fleet register accepts a different one per query; the single-agent view always answers on the 30-day default.
- stale
- The review verifies, but the live configuration digest no longer matches the one attested. Any edit that touches a governance-bearing field, or any edit to a role the agent references, produces this immediately; an edit to the description or a storage timestamp does not, because neither is in the snapshot.
- invalid
- The stored snapshot’s canonical digest no longer matches its recorded digest, the record digest no longer matches the reviewer identity and times it seals, or the audit binding does not hold. Never presented as current.
Who can read what, and where a licence can and cannot bind
Reading the registry needs viewer rank. Spend figures and recertification evidence are additionally gated on the reader’s team scopes, which are kept separate from their role for a specific reason: a viewer for Finance must not gain Engineering’s evidence merely because both are viewers. The scope check is applied at detail and export endpoints as well as at the list, because scoping the list alone leaves the detail URL as a way around the boundary.
The licensed ceiling on simultaneously active agents binds in exactly two places: creating an agent already in the active state, and the transition into active. Suspending, retiring, or editing an already-active agent is how an install that is over its ceiling gets back under it, so none of those is ever refused on licence grounds — a limit that blocked its own remedy would be an outage wearing a licence’s clothes. Draft, suspended and retired agents consume no capacity at all.
Entitlements never reach the governed request path. Being over a ceiling is reported, not retroactively enforced, which is also what makes a downgrade safe: an install that drops from 50 licensed agents to 10 keeps running all 50 and shows as over-ceiling, rather than silently losing 40 agents. And the ceiling is not a technical enforcement mechanism in the first place — deleting the licence file returns the install to an unlimited unlicensed fallback with every control still enforcing. What it produces is evidence: the source of the terms in force, the reason a licence was not used, a boot warning, and an audit row for every refusal. A true-up is argued from that record.
- Reading the fleet register
- Organisation-wide evidence scope only. A whole-estate recertification view filtered to one team would report the posture of a fraction of the estate as the posture of the organisation.
- The audit diff
- An edit names the fields that changed: name, description, owner, team, status, roles, framework, tags, budget, rate limits, data policy, purpose, risk tier and metadata. A change to routing or to the on-behalf-of requirement is audited as an edit but is not named in that list; the recertification digest, which does cover both, is what catches it.
- Registry search
- Matches name, description and owner email, lower-cased on both sides so behaviour is identical on SQLite and PostgreSQL. It does not search declared purpose, tags or metadata.
What this does not do
Stated here rather than discovered during an evaluation. Every line below closes off a reasonable assumption a reader would otherwise carry into a proof of concept.
- Token Observe does not discover your agents for you. Registering one is a deliberate act by a named person; anything calling a model without a record here is the shadow-AI radar’s problem, not the registry’s.
- There is no recertification notification scheduler, and an overdue agent is never suspended automatically. Turning a compliance calendar into an availability control needs a per-install grace period, an escalation owner and a dry-run path before it can be a default.
- A recertification is not a signature. It is a hash record bound to a keyed audit entry, so on an install with no audit HMAC key configured it evidences internal consistency and nothing about a determined database writer.
- The licensed agent ceiling is not enforcement. Deleting the licence file returns the install to an unlimited fallback with every control still running; what the ceiling produces is a visible, audited record of an install operating past its terms.
- Risk tier is recorded and reviewed, but it is not a policy-scope dimension. Policies match on agent id, team and tag, so a rule intended for high-risk agents is written against a tag you maintain.
If one of those limits is the thing that decides it for you, say so and you will get a straight answer about whether it is on the roadmap or out of scope.
Talk it throughWhat this leans on
Agent permissions
Deny by default, explicit deny wins, and delegation intersects — so an agent cannot borrow authority it was never granted.
Spend controls
Hard USD ceilings, per-minute rate limits and a kill switch, all decided before the request leaves your network.
Audit chain
Every administrative act hash-chained; seal it under a key held off the box, and anchor it with a signature your auditor can check alone.
What happens to a running agent when someone edits its record?
The change applies to that agent’s next governed request. There is no redeployment and no propagation step, because the gateway resolves the record at step 2 of every request rather than working from an exported copy. A suspension therefore takes effect on the next call, which is refused with a typed 403 naming the lifecycle state, and it is published as an agent.suspended event as well as audited, so paging and ticketing systems learn about it without polling. The edit itself writes an audit row carrying which fields changed, the new status and the previous one.
Does an expired recertification stop the agent?
No, and that is a deliberate limit rather than an oversight. Token Observe derives and exposes the posture — never, current, due, overdue, stale or invalid — in the console and in a paginated fleet register, but it does not run a notification scheduler and does not auto-suspend. Automatic suspension would turn a compliance calendar into an availability control, which needs an explicit per-install grace period, a named escalation owner and a dry-run path rather than a surprising default. The existing lifecycle API is the enforcement action, taken by a person whose decision is audited.
Why does editing a role make an agent’s review stale?
Because the review attests what the agent could actually do, not which identifiers it referenced. The snapshot binds each role’s name, permission count and a SHA-256 over its normalised permissions, so widening a role changes the live digest and marks every agent that references it stale on the next read. The alternative — binding role ids only — would let a reviewer’s name sit beside a permission set they never saw. Ordering is normalised first, so reordering tags or actions grants no different authority and produces no false staleness.
Who can mint an agent credential, and what if the token is lost?
Minting and revoking keys are admin-only, because a key is gateway authority for that agent. The response to a create is the single copy of the plaintext that will ever exist: Token Observe stores its SHA-256 and a 16-character display prefix, and cannot show or recover the secret again. If it is lost, revoke that key and issue a new one — revocation is one write and takes effect on the next authentication attempt. Optional expiry is available at creation, capped at 3,650 days, and last-used timestamps make dormant keys visible.
How do developer subscription seats relate to registered agents?
They are separate entities on purpose, because they differ on the thing a registry record is for — the credential. An agent holds a machine identity Token Observe issued, presents it to the gateway, and can have it revoked in one write. A seat holds a person’s vendor subscription, which Token Observe never sees and cannot rotate or revoke, so its enforcement is delegated to a hook on a machine it does not own. What they share is everything above the credential: roles, policies, kill switches, teams, tags and lifecycle, decided by the same evaluator against the same policy rows.
Can the registry run without a licence file?
Yes. An absent, expired, forged or unreadable licence leaves every control enforcing exactly as before — the gateway, RBAC, redaction, approvals, budgets, rate limits, the flight recorder, the audit chain and the kill switch are present in every tier and are never gated. What a licence problem may do is refuse to add capacity, with a typed error naming the reason. The unlicensed fallback is unlimited and is reported loudly as the fallback, because a licence problem that degraded a customer’s safety controls is the one failure mode a governance product cannot have.
Prefer to ask a person? Write to us →
Bring us the agent you are least comfortable with.
Write to hello@tenhaw.com with what your agents do, which providers they call and what would have to be true for you to put something in front of them. James Rooney replies. You will get a straight answer about whether Token Observe fits, including when it does not.
no form · no qualification step · no sales desk · the other three ways in