Agents API
The agents API is small on purpose: list, mint, revoke. There is no token rotation endpoint and no rotate-in-place operation. Replacing a credential means revoking the old agent and minting a new row, ID, and token.
Revocation uses the DELETE route but retains the agent row as a durable tombstone.
It sets revoked_at and overwrites the token hash. The database change commits
before the brain makes a best-effort attempt to kick active
sockets locally and across replicas. Subsequent authentication with the old
token fails even if a kick is delayed or lost. There is no separate restart or
detail endpoint; worker control happens through the commands API (restart-worker, pool-resize, etc.).
List agents
Section titled “List agents”GET /api/v1/projects/{slug}/agentsRole: viewer. Returns a list of AgentPublic:
[ { "id": "...", "project_id": "...", "name": "web-01", "state": "online", "protocol_version": "2", "framework_adapter": "django", "engine_adapters": ["celery"], "scheduler_adapters": ["celery-beat"], "capabilities": {}, "last_seen_at": "...", "last_connect_at": "...", "created_at": "...", "is_outdated": false }]is_outdated is true when the agent connected at least once and its last advertised protocol_version is older than the brain's CURRENT_PROTOCOL. Never-connected agents report false.
Mint agent (returns token + HMAC secret)
Section titled “Mint agent (returns token + HMAC secret)”POST /api/v1/projects/{slug}/agentsRole: admin. CSRF-protected and requires a fresh MFA verification. The fresh
MFA gate makes minting browser-session-only; an API key is rejected.
{"name": "billing-worker-02"}(project_id, name) is unique among live agents; a duplicate returns 409
with "error": "conflict". Response (shown once -- save both):
{ "agent": { /* AgentPublic */ }, "token": "<43 URL-safe base64 characters; no prefix>", "hmac_secret": "<urlsafe-base64, 32 raw bytes>"}The hmac_secret is the per-project signing key. It is HMAC-derived from the
current brain master secret and is not persisted by the brain. Consequently,
rotating Z4J_SECRET requires re-credentialing every agent. Adding the old
master to Z4J_PREVIOUS_SECRETS keeps the old bearer token acceptable during
the rotation window, but does not make an old hmac_secret valid: the
handshake can succeed and the first signed data frame then fails HMAC.
Operators paste both values into the agent configuration; the agent refuses to
start without hmac_secret.
Revoke agent
Section titled “Revoke agent”DELETE /api/v1/projects/{slug}/agents/{agent_id}Role: admin. CSRF-protected and requires fresh MFA. Soft-revokes the token
and retains the agent row because events.agent_id is non-null and uses
ON DELETE RESTRICT; tasks have no agent foreign key. The tombstone is hidden
from the agent list and cannot reconnect or receive new work. Revocation keeps
the original name initially. Minting the same name later moves that tombstone
into a reserved namespace under its row lock, then inserts a new agent row.
The replacement does not reuse the revoked row or its ID.