Move an agent or one of its routines on the ladder
const url = 'http://localhost:11044/api/v1/agents/example/stage';const options = { method: 'POST', headers: {'X-Embabel-Api-Key': '<X-Embabel-Api-Key>', 'Content-Type': 'application/json'}, body: '{"routine":"example","stage":"off"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url http://localhost:11044/api/v1/agents/example/stage \ --header 'Content-Type: application/json' \ --header 'X-Embabel-Api-Key: <X-Embabel-Api-Key>' \ --data '{ "routine": "example", "stage": "off" }'Off never fires; observing runs with writes suppressed; on may write. Lowering is always allowed.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The agent’s name, as the list returns it
Request Bodyrequired
Section titled “Request Bodyrequired”stage is off, observing or on (case-insensitive; any other value is read as off). With routine, the name of one routine the agent holds, only that routine moves (404 when it holds none of that name); without it, the whole agent does. Lowering is always allowed. 409 when anything above off is asked for while every agent is halted, when raising by a sponsor where only owners may or while the agent still needs something, and when the whole agent is raised to on before each duty has passed a test run of its signed version. Raising an agent nobody sponsors makes the caller its sponsor
A move on the stage ladder for an agent, or for one routine it holds; sent to POST /agents/{name}/stage
object
Name of one routine the agent holds, to move only that routine; null or absent moves the agent as a whole
Stage to move to: off (never fires), observing (runs with writes suppressed) or on (may write). An unrecognised value reads as off
Responses
Section titled “Responses”The agent after the change
The agent after a stage change or signature, or why the change was refused; answered by POST /agents/{name}/stage and POST /agents/{name}/sign
object
The agent after the change; null when it was refused
object
What it may do on its own, verb by verb, as declared and as the Gatekeeper enforces it; null when it declares none, which leaves every verb at act
object
Level for every effect not named in verbs: act (the default), request or never. An unrecognised level reads as request
Gatekeeper rules it only tries: authority, sensitive, egress or review. Each is evaluated and recorded on the run, but the call goes through
Namespaces its routines may reach. When set, a call to any API or MCP server not listed is refused, read or write; reading the world’s graph and raising a request never are. Null reaches everything
Whether an independent reviewer reads each write it may make on its own first, and may refuse it; a model call per write. False by default
Level by verb, named as the gateway names it (for example odoo_partnerMessagePost): act, request or never
object
The hard limits it runs within, as declared; null when it declares none
object
Most of its runs that may be in progress at once
ISO-8601 date (yyyy-MM-dd), read in the user’s zone, after which it stands down until re-signed with a later one. A date that does not parse stands it down too
Most requests for people to approve that one run may raise
Most runs it may start in any rolling hour; skipped runs do not count
Percent of each source’s declared rate it may take, keyed by bucket (a producer’s cost.bucket, else its name), with * for every bucket not named. Only sources that declare a rate are paced
object
Most model spend across a day, in US cents
Most model spend one run may make, in US cents
Most writes it may make on its own in a day
The duties it keeps, each with what its latest check found
A duty on an agent’s card (AgentView.duties): a condition the agent keeps true, with what its latest check and latest passing test run found
object
When the latest check ran, as an ISO-8601 instant; null when it has not been checked
Six-field cron cadence it is checked on; null when it is only checked on demand
Name of the view or DERIVE label whose rows are the violations
When the current lapse began, as an ISO-8601 instant; null when it is not lapsed or has not been checked
The duty’s name within its agent, as POST /agents/{name}/duties/{duty}/check takes it
Why the latest check could not tell, when its state is unknown; otherwise null
The stage it runs at (off, observing or on): its own declared stage, else the agent’s
The latest check’s state: upheld, lapsed, neglected or unknown; null when it has not been checked
The latest check in words: “upheld”, “lapsed since …”, “neglected: …”, “unknown:
When this duty last passed a test run, as an ISO-8601 instant; null when it never has
The signed agent version that test run checked; going on duty needs it to be the current one. Null when it was never tested
The condition in the sponsor’s words: an Always or a Never
Zone the cadence is read in, as a zone ID such as Europe/London; null reads it in the user’s own zone
How many violating rows the latest check found; 0 when it has not been checked
Whose account it calls each API with, keyed by API name: own-account or on-behalf-of. An API not named is called on its sponsor’s behalf
object
The job in one sentence, as declared; for a gathered agent, a sentence saying where its routines came from
The agent’s name, unique in this world. A gathered agent is named after its realm, or personal for your own routines; one that collides with a declared agent takes a -routines suffix
What must be fixed before it can go on duty, one phrase each (“a sponsor”, “a job”, a missing routine or sweep view, a signature, …). Empty when nothing stands in the way
Usernames of its operators, as declared; empty for a realm-shipped or gathered agent
Where it was declared: “world”, the name of the realm that ships it, or “migrated” for an agent gathered from existing routines
Usernames of its owners: they may sign it, put it back on duty after a sponsor stands it down, and move a Gatekeeper rule from observe to enforce. Empty for a realm-shipped agent until the world declares some
Slug of the personality it speaks through; null when it declares none
Its scheduling priority and model fallbacks, as declared; null is business priority with no fallbacks
object
Fallback model names keyed by LLM role. A check whose models and fallbacks all fail is held as unknown, never as upheld
object
Interactive, business (the default) or background. Background work takes half of each source it declares no share for; a conversation is interactive whatever is declared
The routines it holds, in declared order; a gathered agent’s are sorted by name
A routine on an agent’s card (AgentView.routines): a TypeScript action or realm-scheduled function, with the stage chosen for it and the stage it actually fires at
object
The action’s own description; empty when the routine does not exist in this world
The stage dispatch actually honours for it (off, observing or on). Lower than stage when something the agent still needs holds it back; off for a missing routine
True when the agent names a routine that does not exist in this world
The action’s name, as the agent names it
The stage chosen for this routine (off, observing or on): a stored override, else its declared stage, else the agent’s, before the agent’s own standing is applied
What fires it, in words: “when
“Ask me about…”: when people and other agents should come to it. Empty when not declared
When the latest version was signed, as an ISO-8601 instant string; null when it has never been signed
Username of whoever signed the latest version; null when it has never been signed
Username of the person who answers for it: as declared, else as recorded when someone adopted it; null while nobody has, which keeps it off duty
The stage chosen for the agent: off, observing or on. A stage set through POST /agents/{name}/stage overrides the declared one; what actually fires is each routine’s firing
Lifecycle state: draft, submitted, active, suspended or retired. Only an active agent goes on duty; retired is final
The cold materializations it keeps filled, as declared. Each one buys producer fetches and model judgements for as long as it runs, so this is what a sponsor signs for
A sweep: a cold materialization an agent keeps filled by running a saved view pass after pass, under a budget, until a pass buys nothing
object
Most units of paid work (a producer fetch, or a group of an inline judgement) one pass may buy; null takes the host’s default
The sweep’s name within its agent; part of the fill’s identity, so starting it twice is one fill
Name of a saved view of this world that takes no arguments: the query each pass runs
What the world holds now that the signed version does not, one sentence per change. Dispatch runs the signed version, so none of these take effect until it is signed again
Its latest signed version; 0 for an agent never signed, or one gathered from routines
Why the change was refused, in words; null when it was made
Example
{ "agent": { "authority": { "default": "act", "observe": [ "authority" ], "verbs": { "additionalProperty": "act" } }, "duties": [ { "stage": "off", "state": "upheld" } ], "identity": { "additionalProperty": "own-account" }, "qos": { "priority": "interactive" }, "routines": [ { "firing": "off", "stage": "off" } ], "stage": "off", "state": "draft" }}No authenticated principal
A refusal with a machine-readable code and a plain-language message. ApiErrorAdvice answers it for a failed validation, a missing resource or a conflicting state, and some controllers answer it directly
object
Machine-readable key to branch on, such as validation_failed, unknown_field, not_found or conflict. Open: a surface may answer codes of its own
Extra context where there is some, such as the fields a body may carry; null otherwise
A plain-language explanation, written to be shown. Never carries an exception message
The body the servlet error dispatch answers for a status raised by an exception rather than written by the endpoint. Every failure except 404, which answers the not-found HTML page
object
The status’s standard reason phrase, such as Bad Request or Forbidden
The request path that failed
The HTTP status code, repeated from the status line
Example generated
{ "code": "example", "detail": "example", "message": "example"}No such agent, or no such routine on it
Refused, with the reason: what the agent still needs, or a sponsor raising what only owners may
The agent after a stage change or signature, or why the change was refused; answered by POST /agents/{name}/stage and POST /agents/{name}/sign
object
The agent after the change; null when it was refused
object
What it may do on its own, verb by verb, as declared and as the Gatekeeper enforces it; null when it declares none, which leaves every verb at act
object
Level for every effect not named in verbs: act (the default), request or never. An unrecognised level reads as request
Gatekeeper rules it only tries: authority, sensitive, egress or review. Each is evaluated and recorded on the run, but the call goes through
Namespaces its routines may reach. When set, a call to any API or MCP server not listed is refused, read or write; reading the world’s graph and raising a request never are. Null reaches everything
Whether an independent reviewer reads each write it may make on its own first, and may refuse it; a model call per write. False by default
Level by verb, named as the gateway names it (for example odoo_partnerMessagePost): act, request or never
object
The hard limits it runs within, as declared; null when it declares none
object
Most of its runs that may be in progress at once
ISO-8601 date (yyyy-MM-dd), read in the user’s zone, after which it stands down until re-signed with a later one. A date that does not parse stands it down too
Most requests for people to approve that one run may raise
Most runs it may start in any rolling hour; skipped runs do not count
Percent of each source’s declared rate it may take, keyed by bucket (a producer’s cost.bucket, else its name), with * for every bucket not named. Only sources that declare a rate are paced
object
Most model spend across a day, in US cents
Most model spend one run may make, in US cents
Most writes it may make on its own in a day
The duties it keeps, each with what its latest check found
A duty on an agent’s card (AgentView.duties): a condition the agent keeps true, with what its latest check and latest passing test run found
object
When the latest check ran, as an ISO-8601 instant; null when it has not been checked
Six-field cron cadence it is checked on; null when it is only checked on demand
Name of the view or DERIVE label whose rows are the violations
When the current lapse began, as an ISO-8601 instant; null when it is not lapsed or has not been checked
The duty’s name within its agent, as POST /agents/{name}/duties/{duty}/check takes it
Why the latest check could not tell, when its state is unknown; otherwise null
The stage it runs at (off, observing or on): its own declared stage, else the agent’s
The latest check’s state: upheld, lapsed, neglected or unknown; null when it has not been checked
The latest check in words: “upheld”, “lapsed since …”, “neglected: …”, “unknown:
When this duty last passed a test run, as an ISO-8601 instant; null when it never has
The signed agent version that test run checked; going on duty needs it to be the current one. Null when it was never tested
The condition in the sponsor’s words: an Always or a Never
Zone the cadence is read in, as a zone ID such as Europe/London; null reads it in the user’s own zone
How many violating rows the latest check found; 0 when it has not been checked
Whose account it calls each API with, keyed by API name: own-account or on-behalf-of. An API not named is called on its sponsor’s behalf
object
The job in one sentence, as declared; for a gathered agent, a sentence saying where its routines came from
The agent’s name, unique in this world. A gathered agent is named after its realm, or personal for your own routines; one that collides with a declared agent takes a -routines suffix
What must be fixed before it can go on duty, one phrase each (“a sponsor”, “a job”, a missing routine or sweep view, a signature, …). Empty when nothing stands in the way
Usernames of its operators, as declared; empty for a realm-shipped or gathered agent
Where it was declared: “world”, the name of the realm that ships it, or “migrated” for an agent gathered from existing routines
Usernames of its owners: they may sign it, put it back on duty after a sponsor stands it down, and move a Gatekeeper rule from observe to enforce. Empty for a realm-shipped agent until the world declares some
Slug of the personality it speaks through; null when it declares none
Its scheduling priority and model fallbacks, as declared; null is business priority with no fallbacks
object
Fallback model names keyed by LLM role. A check whose models and fallbacks all fail is held as unknown, never as upheld
object
Interactive, business (the default) or background. Background work takes half of each source it declares no share for; a conversation is interactive whatever is declared
The routines it holds, in declared order; a gathered agent’s are sorted by name
A routine on an agent’s card (AgentView.routines): a TypeScript action or realm-scheduled function, with the stage chosen for it and the stage it actually fires at
object
The action’s own description; empty when the routine does not exist in this world
The stage dispatch actually honours for it (off, observing or on). Lower than stage when something the agent still needs holds it back; off for a missing routine
True when the agent names a routine that does not exist in this world
The action’s name, as the agent names it
The stage chosen for this routine (off, observing or on): a stored override, else its declared stage, else the agent’s, before the agent’s own standing is applied
What fires it, in words: “when
“Ask me about…”: when people and other agents should come to it. Empty when not declared
When the latest version was signed, as an ISO-8601 instant string; null when it has never been signed
Username of whoever signed the latest version; null when it has never been signed
Username of the person who answers for it: as declared, else as recorded when someone adopted it; null while nobody has, which keeps it off duty
The stage chosen for the agent: off, observing or on. A stage set through POST /agents/{name}/stage overrides the declared one; what actually fires is each routine’s firing
Lifecycle state: draft, submitted, active, suspended or retired. Only an active agent goes on duty; retired is final
The cold materializations it keeps filled, as declared. Each one buys producer fetches and model judgements for as long as it runs, so this is what a sponsor signs for
A sweep: a cold materialization an agent keeps filled by running a saved view pass after pass, under a budget, until a pass buys nothing
object
Most units of paid work (a producer fetch, or a group of an inline judgement) one pass may buy; null takes the host’s default
The sweep’s name within its agent; part of the fill’s identity, so starting it twice is one fill
Name of a saved view of this world that takes no arguments: the query each pass runs
What the world holds now that the signed version does not, one sentence per change. Dispatch runs the signed version, so none of these take effect until it is signed again
Its latest signed version; 0 for an agent never signed, or one gathered from routines
Why the change was refused, in words; null when it was made
Example
{ "agent": { "authority": { "default": "act", "observe": [ "authority" ], "verbs": { "additionalProperty": "act" } }, "duties": [ { "stage": "off", "state": "upheld" } ], "identity": { "additionalProperty": "own-account" }, "qos": { "priority": "interactive" }, "routines": [ { "firing": "off", "stage": "off" } ], "stage": "off", "state": "draft" }}
