Agent API v1
Status: live contract for the implemented Agent API resources.
The Agent API is the JSON surface under /agent_api/v1, organized around an Agent's work: discovering usable models, managing conversations and content, and coordinating execution and results. The resource pages below describe the implemented requests, responses, authority rules, and lifecycle behavior of each endpoint family.
For a first integration, follow Build an Agent API client. Use orchestration to choose between a task branch, a child conversation, a standalone loop, and scheduled work; use lifecycle hooks to run an executor tool at an execution boundary. These guides describe the current product alongside the resource reference below.
A conversation/work WebUI uses its Agent application's control surface, whose kernel client calls this family. Human personal settings and administrator system settings belong to the Platform API; browser use of that family is confined to settings pages.
Requests
Requests are bearer-only. Send Authorization: Bearer <credential> and Accept: application/json. Requests with JSON bodies also send Content-Type: application/json. The family uses Rails HTTP-token grammar, so Token is accepted as an alternative scheme; Bearer is the recommended form.
Resource public_id values and references to them are UUIDv7 strings. Model references, provider identifiers, tool names, and task keys use their resource's own vocabulary. Resource timestamps ending in *_at use whole-second ISO 8601 UTC (2026-09-05T12:00:00Z) unless their resource contract specifies another precision. In particular, the authored timestamp strings inside scheduled-job rules retain six fractional digits.
Cookies are never accepted here, in either direction: this family has no browser session, and a browser session never authorizes it.
Authentication and planes
One bearer resolves to exactly one authorization plane, fixed when the credential was minted. There is no scope vocabulary — the plane is the whole of a credential's authority axis.
| Plane | Prefix | What it is | What it reaches |
|---|---|---|---|
member | sk-cybros-api-v1- | the acting User's member/data authority | member resources, including Profile |
executor_transport | sk-cybros-api-v1- | proof of one delivery address at one epoch | executor resources, including Executor |
A credential presented to the other plane's endpoint is fenced with 401. It is never accepted with a degraded principal, and the response never says why a credential was refused: a wrong-plane credential, a revoked one, a fenced one, and an expired one are deliberately indistinguishable. The remedy is the same for all of them — present a live credential of the right plane, or reconnect.
Protected-resource authentication failures include WWW-Authenticate: Bearer realm="Nexus". The challenge is the same for missing and rejected credentials; the JSON error remains unauthorized.
A connection issues whichever credentials its branch produced, and the token response names the plane of the one it leads with (see the device flow):
- an agent connection yields both planes: it always produces the profile's one delivery address, so the program holds a member credential and a transport credential. That address is capability, not a promise of queued work: a conversational or role-play Agent may validly receive zero Tasks;
- a runner or tools-provider connection yields the transport plane alone, because that executor is a delivery address rather than a principal.
An executor bootstrap therefore never calls a member endpoint. A runner has no member credential and must still be able to learn which address it is, which is exactly what Executor answers.
The two planes have independent lifecycles by design. A member credential dies with that User's authority. For an Agent, full member authority requires the Profile to be active and steward_live? to pass: its same-Account steward is active and the Profile's applied_steward_shutdown_generation equals the steward's managed_resource_shutdown_generation. Removing an Agent synchronously revokes its member access and Agent-application transport credentials. The TaskExecutor address remains active, but its old credentials return 401; related work is force-stopped asynchronously. An independent Runner's registration and credentials are unaffected. Restore does not wait for that cleanup or revive old credentials; reconnect may restore the same Profile and re-pair its retained address with fresh credentials.
Removing the controlling Human additionally advances the existing durable shutdown generation. The Profile-side mismatch immediately fences member/data authority and new admission even when no executor exists. Profile convergence removes the Profile and acknowledges that snapshot, applying the Agent credential cut and asynchronous force-stop above. A managed executor has a separate applied_human_shutdown_generation; while it lags, the executor accepts no new work and exact bound transport may remain only while bounded asynchronous shutdown reaches data-safe terminal/evidence state, after which its epoch is fenced and its generation is acknowledged. That retained-transport rule does not preserve an Agent application's credentials after its Profile is removed. Transport may also die by explicit revocation of its token, lineage, or address, expiry, or an epoch advance. A program holding both may therefore find one plane dead and the other alive during ordinary coordination; that is not a contradiction.
Errors
Controller-handled failures use one JSON envelope, shared with the Platform API:
{
"error": {
"code": "unauthorized",
"message": "Unauthorized"
}
}| Status | Code | Meaning |
|---|---|---|
401 | unauthorized | the credential is missing, or not accepted on this plane |
429 | rate_limited | the caller's budget is spent; Retry-After is a whole number of seconds |
Profile and Executor are singular self-resources named by the presented credential, so neither can 404. Identifier-scoped resources such as Workspaces and Store entries document their 404 posture on their resource pages: a scoped-finder miss and an inaccessible or tombstoned record read identically.
An unhandled application or upstream failure is not part of this contract: a 5xx body may be JSON, non-JSON, or empty. Classify it from the status.
Commands and retries
Use the documented resource and command endpoints for mutations. A 201 response identifies a completed resource creation; 202 accepts work whose execution is observed separately. Neither a successful input submission nor an executor claim means its turn or task has finished. Executor progress has an explicit exception: its 202 acknowledges an ephemeral frame, which may have been dropped for cadence and is never durable work.
Where a resource accepts Idempotency-Key, reuse that key and the same request after a lost response. Scope, lifetime, request matching, and current authority checks belong to the resource's contract. Do not assume every POST is retryable or that every replay changes the status to 200.
Workspace and Conversation creation, Conversation forks, Input creation, and StoreEntry creation on Workspace/Conversation hosts replay the original status and body. These receipt-backed responses carry Idempotency-Replayed: false for execution and Idempotency-Replayed: true for an authorized replay. The Ruby SDK uses this header for the corresponding replayed? results. AgentRun and InferenceRequest creation have their own documented replay responses; task settlement uses its claim token and terminal receipt.
HTTP limit parameters use each resource's documented default when omitted or null. Body fields filtered out by Strong Parameters retain the family's omitted-field semantics. Malformed, nonpositive, and above-maximum accepted scalar values return 400 parameter_invalid; they are never silently clamped. Ordinary keyset lists, timeline windows, event replay, executor traces, and memory search retain their own bounds and cursor semantics.
HTTP and realtime
HTTP owns business commands, current state, and retained event replay. ActionCable reduces delivery latency; an open socket is not proof that work is available, that execution succeeded, or that every frame arrived.
| Feed | Purpose | Recovery |
|---|---|---|
events | Durable resource events with a resource-scoped sequence | HTTP event replay after the last consumed cursor; rebuild from current resources if retention has removed history. |
lifecycle | A filtered view of durable state changes and requests for intervention | The same resource's HTTP event replay, filtering the returned events as needed. |
transcript | Text deltas, resets, and settled text snapshots | Read the current turn variant or task output over HTTP. These frames have no replay log. |
progress | Temporary tool and process output | Resume with future frames; use the durable task result for the final outcome. |
| Executor inbox notifications | work_available and work_canceled hints | Poll the HTTP inbox and the held claim's status. |
Available feeds and payloads differ by resource; use the resource page's channel identifier and subscription parameters. In particular, a Conversation-hosted AgentRun publishes on its Conversation's stream.
For a durable follower, wait for subscription confirmation and buffer live events while draining HTTP replay from the saved cursor through the first response's committed watermark. Merge by resource identity and sequence, discard duplicates, and advance the saved cursor only after consumption succeeds. Keep the server's cursor opaque; a watermark is a drain boundary, not a cursor to invent. Reconnect repeats the same recovery. The Ruby SDK's durable feed implements this coordination.
Durable events and text frames are separate feeds: a terminal status can arrive before, after, or without its final text snapshot. If a client has terminal status but no settled text, read the authoritative text over HTTP and replace the accumulated draft. Check the turn, variant, or task identity again before applying an asynchronous read, so a previous answer cannot overwrite a newer selection. A retained-event gap likewise requires current state reconciliation; replay cannot reconstruct expired events.
An executor keeps polling even while subscribed. Drain each bounded inbox scan to its end, then start the next scan from the beginning; notifications only bring that scan forward. Claim, extend, commit, and cancel decisions remain HTTP operations. See Executor inbox for claim recovery and Conversations for the feed payloads and retention rules.
Rate limits
Budgets are per resource, not per family: each endpoint family holds its own counter, so exhausting one leaves the others untouched. Each carries two fixed one-minute counters:
- every request first charges a broad source-IP backstop, one hundred times that resource's ordinary budget;
- the ordinary resource budget defaults to 6,000 requests per minute. After credential resolution, an accepted credential is keyed by its non-secret
AccessToken.public_id; a missing, malformed, unknown, expired, revoked, or wrong-plane credential falls back to the source IP.
The default accommodates parallel agents sharing one credential. It is an admission budget, not a throughput guarantee. Resources with a different request cadence or rendering cost declare their own:
| Resource | Per minute | Why |
|---|---|---|
Conversation, AgentRun, and InferenceRequest events | 6,000 | Supports event replay and bounded polling; realtime subscriptions reduce polling demand. |
| Store entries (profile, workspace, conversation) | 6,000 | Application state commits before external effects; reads and writes share the resource budget. |
inference_requests | 6,000 | Carries every create plus bounded list/read polling; one list page returns up to 100 current projections, while its forward keyset cursor does not revisit older in-flight rows. |
Executor claim status (GET) | 600 | Recovers missed cancellation notifications for concurrent held claims; the claim POST has a separate 6,000/minute budget. |
Executor progress | 10,000 | Also limited to one frame per key per 250 ms per kernel process; excess cadence is acknowledged and dropped. |
| Upload thumbnail and preview generation | 30 | Bounds derivative generation independently of ordinary upload reads. |
| everything else | 6,000 | Including the write-free inference_requests/input_estimate advisory and inference_requests/{id}/cancellation. |
Neither key contains the raw Authorization header, bearer secret, token digest, or lookup secret. Header spelling variants for one accepted credential therefore share one budget, and arbitrary invalid Authorization values cannot create fresh buckets. Different valid credentials behind one NAT have independent ordinary budgets. The source-IP backstop is the deliberate coarse ceiling: it permits one hundred callers each exhausting the ordinary allowance on that resource, but an exceptionally large shared NAT may still share this abuse-control limit. Either exhausted counter returns the 429 envelope above with Retry-After: 60.
Read semantics
Every resource here is a composed read of a moment, never a live handle. Each independently measured block carries its own measured_at, and a client must not treat one as a precondition for a later write — the command endpoint evaluates its own authority.
Successful authentication may refresh the credential's non-authoritative last_used_at sample. Executor authentication, and an exact-current refresh bound to that same address and epoch, may independently stamp the executor's last_seen_at at most once per minute. That field means only “current-epoch address contact”; it is not online status, health, credential readiness, Task success, or a delivery gate, and stamping it does not itself change the refresh family's last_used_at. presence beside it is the live, pong-verified executor socket — online while an executor-inbox subscription is open, offline with a last_seen_at, not_yet_seen never — display only, never a delivery gate. Reading never extends, rotates, or repairs anything.
Resources
- Profile — member plane: who this credential acts as, the handle it answers to, and its own store. Its own pages carry the configuration, named agent definitions, memory and prompt documents.
- Runs — member plane: the task-grained DAG surface, its doors and its adjudication verbs. Its own pages carry the rest: steps, tools, orchestration, statuses and failure, approval, compaction and feeds.
- Prompt assembly — what an assembled turn compiles: the block order, the slots and their macros, and the template grammar.
- Tool assembly — Agent member plane: read the tool declarations and environment for explicit sources and a selected Runner.
- Conversations — member plane: the conversation resource, its answerer and access carrier, lists, archive, delete, subagents, forks and side conversations. Its own pages carry inputs with their fields and kernel mail, turns, context, memory and feeds.
- Conversation history — member plane: keyword search and bounded reads of visible historical context.
- Conversation reasoning — member plane: the stored reasoning window of a completed candidate.
- Execution retention — what remains readable after completed execution details expire.
- Schedules — member plane: one-time or recurring instructions, independent child executions, and asynchronous result callbacks.
- Workspaces — member plane: the Workspace collection, owner management, the serial lifecycle, the room's character and its own memory scope.
- Store entries — member plane: the bounded namespaced JSON current-value store on a workspace, a conversation, and the acting principal's own profile.
- InferenceRequests — member plane: direct model calls, input estimation, execution state, usage, replay, and realtime events.
- Uploads — stage attachments for conversation inputs and InferenceRequests, and read authorized input files or executor-produced captures.
- Models and model providers — member plane: which models this account can run, and the provider lanes that gate them; read-only discovery. Human administrators manage provider state on the Platform API.
- Executor — executor transport plane: which delivery address this credential is, the three executor kinds, what it serves, and the captures it publishes; and, on the member plane, the discovery of the executors a principal may address (
GET /agent_api/v1/executors). - Executor inbox — executor transport plane: the inbox it claims from and commits to, deadline extension, expiry, push, progress frames, operator requests, lifecycle hook tasks and delegated compaction.
- Executor operations — executor transport plane: child work accepted and observed under an existing claim.
- Ingress speakers — member plane: Agent-controlled external voices posted through the conversation input door.