Skip to content

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.).

GET /api/v1/projects/{slug}/agents

Role: 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.

POST /api/v1/projects/{slug}/agents

Role: 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.

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.