AI agents
Read as MarkdownSee every agent that is running
The fleet and the asset inventory: which agents somebody declared, which ones Anectico found on its own, what needs review, and which credential each one is using.
You cannot govern an agent you cannot see. Govern → Fleet answers “what is running”, and Govern → Inventory answers “and what do we know about it” — including the records nobody created on purpose.
Declared and discovered are different things
Every record in the inventory carries one of two badges, and the difference is the point of the page.
| Badge | What it means |
|---|---|
| Declared | A person registered this agent. Its name is an identity somebody chose. |
| Discovered | Telemetry created this record because something was running that nobody declared. Its name is evidence, not an identity. |
A discovered record is not an error and not an accusation — it is what an agent looks like before anybody has reviewed it. It behaves like any other record: you can read its activity, see which credential produced its telemetry, and contain it. What it has not had is a decision.
Every discovered record also opens a review signal, so “we found something” and “somebody dealt with it” stay separate questions. See What needs review.
Fleet
Govern → Fleet lists the agents, workflows and A2A peers in the active project, busiest first, with the last 24 hours of activity beside each one: how many runs, and how many of those ended as anything other than completed. A live containment shows as a badge on the row, and open review signals show as a count.
Activity the fleet cannot account for
Anectico matches a run to an inventory record by the stable observed identity carried with the run, not by its display name. Two agents may therefore use the same name without absorbing each other’s runs. View runs carries every observed identity currently attributed to that inventory record into the run list; the name remains a label. The run link therefore stays on the selected agent after a rename and does not widen to another same-named agent. Person and account selectors are retained when that list opens an individual run.
There are still two gaps, and the page states them rather than hides them:
- Runs that named an agent with no record in this project. The record may live in another environment, or the inventory has not caught up with a new agent yet.
- Runs that carried no mapped observed identity and reported no agent name at all. Nothing can
attribute those to an inventory record. The fix is in your instrumentation: set an agent name
(
gen_ai.agent.nameoragent.name) on the spans your agent emits, and the discovery path can create and map the record.
If either number is non-zero, the fleet says so at the top. A page that quietly dropped those runs would show a calm fleet over a busy one.
The list uses cursor pagination. Its 24-hour activity window ends at the first page’s read snapshot,
and the opaque continuation keeps later pages on that same window. has_more comes from the same
ordered population as the page, rather than from a count taken at another instant. The totals at the
top describe the complete measured population, not only the rows loaded so far.
The window selects a run when any of its steps started during those 24 hours. Once selected, the fleet folds the complete run, including an earlier root, so its stable identity and terminal outcome do not disappear merely because the execution crossed the window boundary.
An empty fleet is a successful measurement with zero agents. If inventory or activity cannot be
measured, the read fails instead of returning an empty, apparently healthy fleet. Containment is a
separate permission: without it, containment_visibility is WITHHELD, which is not evidence that
no agents are contained.
Inventory
Govern → Inventory is the whole registry, not only the agents: agents, workflows, tools, models, MCP servers, A2A peers, gateways, model routers, prompts, retrieval corpora, memory stores, sandboxes, skills, workload identities and policies. Filter by kind, and by origin — all, declared or discovered. “All” is the default deliberately: it is a different question from “declared”, and starting at “declared” would hide exactly the records worth looking at.
What gets discovered from telemetry, and what does not
Four kinds appear on their own, from standard agent telemetry, with nothing to configure:
| Kind | Discovered from | Identity |
|---|---|---|
| Agent | A declared agent id or name, else the emitting service | Per project and environment |
| Workflow | A declared workflow name on a span that also names its agent | Scoped to that agent — two agents’ main are two workflows |
| Tool | A declared tool name, with its type | Shared across the project: one tool, however many agents call it |
| Model | The provider plus the model that actually served the call | Shared across the project |
A model that was requested and then replaced by a different served model does not become its own row. The row is the model that ran; the substitution is still visible on the call itself.
Every other kind has to be declared. Nothing in today’s telemetry conventions identifies an MCP server, a sandbox, a prompt, a retrieval corpus or a policy in a way that stays the same between calls — an MCP session id, for instance, changes every time a client reconnects, so a row keyed on it would be a new row per reconnect rather than a record of the server. Rather than guess, Anectico records nothing for those kinds. An empty filtered page means “nothing was recorded”, and for those kinds it always will until they are declared.
Which agent uses this tool
A tool and a model are one shared record however many agents call them, so the caller is recorded as a link rather than folded into the record. Select a tool or a model and Anectico lists the agents observed using it; select an agent and it lists the workflows, tools and models that agent uses.
The link is only recorded when a single span named both — the tool and the agent running it. Some frameworks do not repeat the agent’s identity on a tool call, so an empty list means “no telemetry linked them”, never “unused”.
Each row carries its lifecycle state, its review decision, its assessed risk tier, its environment and when it was last seen.
What produced this agent’s telemetry
Select Attribution on any row. Anectico lists each observed identity that maps to that asset and the credentials seen producing telemetry under it, with a sighting count and a last-seen time — so a credential used once and one on today’s hot path are distinguishable before you act.
Three of the answers are not API keys, and each means something different:
| What you see | What it means |
|---|---|
| An API key id | A containment or a revocation can act on this. |
| A signed-in person’s session | There is no key to revoke; the control is that person’s access. |
| A development-only trust setting | No credential was presented at all, and nothing can revoke it. Outside development, this means that setting is on where it should not be. |
| Nothing recorded | Not the same as “no credential was used” — nobody recorded one for this identity. A containment naming this asset may reach nothing. |
This is the read to run before containing an agent: containment is only a request until something can name the credential to stop. See Revoke an agent’s access.
What needs review
The Review queue tab collects six conditions that need a person to decide what happens next:
| Signal | What it means | What to do | What clears it |
|---|---|---|---|
| Undeclared agent discovered | Something is running that nobody registered. | Declare it, or contain it. | Recording a review decision on the asset |
| No review decision | An asset has been in the inventory past the review window and nobody has approved or rejected it. | Decide. | Recording a review decision on the asset |
| No owner | An asset has been in the inventory past the same window with neither an owner team nor an owner principal. | Name an owner. | Setting either owner field |
| Configuration disagrees with its attestation | The configuration in the field is not the one that was attested. | Find out which is right. | Registering a matching configuration |
| No registered configuration to compare | Nobody can tell whether it drifted, because no configuration was ever registered. | Register one. | Registering one |
| Credential seen on a killed agent | Telemetry authenticated by the named API-key id resolved to the named agent while the named kill containment was active. |
Inspect the key and containment, then revoke the key or lift the containment as appropriate. | Revoking the key, or lifting the containment |
“No registered configuration” is not a quieter version of “disagrees with its attestation”. “We cannot see this” reported as “this is clean” is the failure the separate signal exists to prevent. The same reasoning separates the review and owner gaps: they are answered by different people through different writes, and an asset can have either without the other.
The review and owner windows exist so that discovery is not itself an alert. A newly discovered asset is given a grace period — 24 hours unless your deployment shortens it — before either gap is raised. Retiring an asset clears both, because a retired asset needs no owner and no decision.
Discovered assets appear above those signals with their lifecycle, current review decision, owner
team and owner principal. If you have agents:write, use Approve or Reject to record a
decision. A reason is required. After the write, the row shows the reviewer, reason and review time
so the decision never becomes an unexplained badge. An approval does not lift a quarantine: a
quarantined asset remains visibly Quarantined until its lifecycle is changed through the
separate containment workflow.
Use Set owner to replace the asset’s team and principal assignments. Both current values open in the form. Leaving a value untouched keeps it; deliberately clearing one input removes only that assignment when you save. The Assets tab can filter the resulting inventory by review decision, owner team and owner principal.
The killed-agent signal is observable in this queue and through the review-signals API. Its opening
and clearing are sent to enabled notification channels, and an alert rule using the
review_signals source can target its project, kind, severity, or subject. It never disables a key
on its own. Repeated spans from the same key under the same containment refresh one row without
re-sending the opening, and the row closes when that key is revoked or the containment is lifted.
The same queue also carries a seventh condition, opened by labelling a memory item quarantined rather than by telemetry discovery: see Memory provenance and quarantine for what that label means and how it is set.
Every condition in the queue has both an opening and a clearing, and both are sent to enabled
notification channels — so an alert rule using the review_signals source can page while a
condition is open and stop on its own when somebody deals with it, without anybody clearing the
alert by hand.
Who authorized what
The Delegations tab shows the authority graph: who granted an agent the right to act, for what purpose, and on what evidence. Each edge is either Declared — a delegation somebody wrote down — or Observed — one a signed action receipt proves actually happened. Those are not the same claim, and an exercised delegation must never read as an approved one.
Revoked edges are hidden by default: a reviewer asking what an agent can do should not be shown history unless they ask for it.
Permissions
Reading the fleet, the inventory, the review queue and the delegation graph needs agents:read,
which every role from viewer up holds. The containment badge additionally needs
quarantine:request or quarantine:approve — without either, the rest of the page still renders.
Registering a deployment, a configuration or an attested manifest, assigning an asset owner, or
recording an asset review needs agents:write. See
Permission scopes.
The same answers over the API
GET /api/v1/fleet?project_id={projectId}&limit=100
GET /api/v1/assets?kind=agent&shadow=true
GET /api/v1/assets?kind=tool&related_asset_id={agentAssetId}
GET /api/v1/assets/{assetId}
PUT /api/v1/assets/{assetId}/ownership
POST /api/v1/assets/{assetId}/reviews
PUT /api/v1/assets/{assetId}/data-classification
GET /api/v1/assets/{assetId}/attribution
GET /api/v1/review-signals?status=open
GET /api/v1/authority-edges
GET /api/v1/authority-edges?include_revoked=true
POST /api/v1/authority-edges/{edgeId}/revoke
The same fleet contract is available without a browser:
anectico fleet list --limit 100
MCP clients can call list_agent_fleet directly. Both use the same opaque next_cursor and
has_more values as the REST response, so an automation never has to recreate the join. Each fleet
row also returns its sorted observation_keys; use those immutable values, rather than name, when
selecting that row’s runs.
related_asset_id answers the usage question in whichever direction you ask it: pass an agent’s id
to list what that agent uses, or a tool’s or model’s id to list the agents using it. Combine it with
kind to narrow. Leave it off for no narrowing at all — it never widens a page.
shadow is three-valued: leave it off for both kinds, true for discovered records only, false
for declared ones. Every one of these is scoped to a project — pass project_id or you will read an
empty inventory rather than the whole workspace. Full parameters and response shapes are in the
REST API reference.
/authority-edges answers which delegations exist — who may act through what, for what purpose, how
often it has been exercised and when it last was. The revoke route withdraws one of them with a
required reason; the withdrawal is attributed to your credential, the edge keeps its sighting
history, and it drops out of the default read until you pass include_revoked=true. Using a
withdrawn delegation does not restore it — it raises a review signal instead. See
Revoke an agent’s access.
The ownership route replaces owner_team and owner_principal; empty values deliberately clear an
assignment. The review route accepts unreviewed, approved or rejected with a required reason
and a required risk tier — unassessed, low, medium, high or critical. The response records
who reviewed it and when. Approval is independent of containment, so approving a quarantined asset
never restores its lifecycle state.
The risk tier is part of the review because it is part of the same judgement: the same reviewer, at
the same moment, saying how much is at stake. An asset carries unassessed until somebody reviews
it, and a reviewer who has not assessed the blast radius records unassessed deliberately rather
than leaving the field out. That is what makes ?risk_tier=high mean “a person put this here”.
The data classification is NOT part of the review, for the mirror-image reason. It says what the
asset handles rather than how the review went, and it changes when the asset’s data flows change —
which happens without anybody reopening an approval. So it is its own route, and it records its own
classified_by, classification_reason and classified_at rather than borrowing the reviewer’s.
Accepted values are unclassified, public, internal, confidential and restricted. An asset
carries unclassified until somebody classifies it, and a classifier who examined it and found
nothing to classify records unclassified deliberately — the difference between the two is whether
classified_by is set. Classifying an asset changes no approval state, risk tier, owner or
lifecycle state.
The CLI exposes the inventory and the ownership and review writes without a browser, including bulk ownership and review. The classification route has no CLI subcommand yet; drive it over REST:
anectico asset list --origin shadow --approval-state unreviewed --limit 200 -o json
anectico asset list --risk-tier high --risk-tier critical -o json
anectico asset own <asset-id> [<asset-id>...] --owner-team platform
anectico asset review <asset-id> [<asset-id>...] \
--approval-state approved --risk-tier high --reason "Matched the reviewed deployment"
asset list returns the raw page, so .assets[].asset_id can be selected with jq and passed to
either write through xargs; use --cursor for later pages. A bulk write continues after an item
failure, reports every asset in input order, and exits non-zero if any item failed. Ownership is a
complete replacement: an omitted owner flag clears that field, at least one owner flag must be
explicit, and supplying both as empty values clears both deliberately. The commands require
agents:write. A successful HTTP status is not enough on its own: the response must confirm the
requested asset and new governance fields, or that item is reported with an unknown outcome.