Steering
Human instructions to a running agent: steer, claim, ack.
Preview. Steering a running agent is not yet part of Kabu: these operations are in the contract ahead of it.
Generated from the contract, version 2.0.0-draft.2 (OpenAPI). Base URL https://usekabu.com/api. Errors are problem details, each code with its own page.
Report what the agent did with a steer
POST/v2/messages/{message_id}/ackreceived (started; no redelivery after this) then applied or rejected, once. Stale lease token: 409 lease_lost. Backwards: 409 invalid_ack_transition.
- Auth: an API key.
- Scopes:
claims:write.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
message_id |
path | string | Required | A msg_… id. |
Idempotency-Key |
header | string, at most 255 characters | Optional | Retry-safe key. For messages, sessions and responses it binds to the created object for its life; elsewhere for 24 h. |
Request body: AckInput.
curl -X POST "https://usekabu.com/api/v2/messages/$MESSAGE_ID/ack" \
-H "Authorization: Bearer $KABU_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"lease_token":"…","status":"received"}'Bind the runtime's own session id (claim holder only)
PUT/v2/sessions/{session_id}/continuationOnly the consumer holding the session’s current claim or durable attempt may set the continuation: the lease_token is checked atomically against the session, agent, mode and current claim generation. A superseded token is 409 lease_lost, so a stale worker can never redirect future steering into the wrong runtime.
- Auth: an API key.
- Scopes:
claims:write.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
session_id |
path | string | Required | A ses_… id. |
Request body: ContinuationSet.
curl -X PUT "https://usekabu.com/api/v2/sessions/$SESSION_ID/continuation" \
-H "Authorization: Bearer $KABU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"lease_token":"…","continuation":{"kind":"…","id":"…"}}'A human instructs a running agent
POST/v2/sessions/{session_id}/steerCreates a kind=steer message: instructions are FIFO within the session; signals (pause, resume, stop) use their own lane and are never blocked by an instruction. Human-voice writes have their own budget, never send or month, so a runaway agent can never prevent its own stop. Only the session audience may steer: a user token outside to, or a key whose as_recipient is outside to, gets a non-disclosing 404. Keys need steer:write and as_recipient, and a key holding messages:write gets 403 self_response_forbidden.
- Auth: an API key, or a signed-in human’s token (the Kabu apps).
- Scopes:
steer:write. - Refused to: a key holding
messages:write. - Signed-in humans:
audience.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
session_id |
path | string | Required | A ses_… id. |
Idempotency-Key |
header | string, at most 255 characters | Optional | Retry-safe key. For messages, sessions and responses it binds to the created object for its life; elsewhere for 24 h. |
Kabu-Org |
header | string | Optional | Select a live membership (default personal org); non-member is 404. Human tokens are live-only. Caller user id is distinct from billing owner. |
Request body: SteerInput.
| Status | Means | Body |
|---|---|---|
201 |
OK | Message |
429 |
A rate, concurrency or quota limit was reached | Problem |
4XX |
Error | Problem |
5XX |
Error | Problem |
curl -X POST "https://usekabu.com/api/v2/sessions/$SESSION_ID/steer" \
-H "Authorization: Bearer $KABU_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"control":"instruction","body":"…"}'Take queued steers with a lease (the only consumption path)
POST/v2/claimsHolds up to wait seconds for steers on one session, or across an agent’s sessions and kickoffs. Only the head of each session’s instruction queue is leasable; signals (pause, resume, stop) have their own lane and are leasable even while an instruction holds the head. A newer claim from the same consumer supersedes its own parked wait; it never takes another consumer’s lease. Retrying with the same Idempotency-Key while the leases are live returns the same claim and items, so a lost response loses nothing; once the leases lapse the items return to their queues.
- Auth: an API key.
- Scopes:
claims:write.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key |
header | string, at most 255 characters | Optional | Retry-safe key. For messages, sessions and responses it binds to the created object for its life; elsewhere for 24 h. |
wait |
query | integer, from 0 to 50 | Optional | Hold up to N seconds for the state to settle. 0 or absent returns at once. The kabu CLI and the MCP tools wait 25. |
Request body: ClaimCreate.
| Status | Means | Body |
|---|---|---|
200 |
OK | Claim |
429 |
A rate, concurrency or quota limit was reached | Problem |
4XX |
Error | Problem |
5XX |
Error | Problem |
curl -X POST "https://usekabu.com/api/v2/claims" \
-H "Authorization: Bearer $KABU_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"target":{"type":"session","session":"…"},"consumer":"…"}'Schemas
AckInput
Send received only after the consumer has durably accepted the instruction, or immediately before a non-idempotent injection. That turns the lease into a durable attempt: Kabu never redelivers it, and the same lease_token stays valid for the final applied/rejected until outcome_deadline (24 h), even after lease_expires_at. While it is received, the session’s instruction head stays with the same consumer id, so a runtime that restarts under that id continues in order; other consumers wait. If no outcome arrives within the claim’s attempt_timeout the attempt becomes uncertain and the head is released; a late outcome still settles it. A lease that lapses before received returns the steer to the head.
| Property | Type | Required | Description |
|---|---|---|---|
lease_token |
string | Required | |
status |
string, one of "received", "applied", "rejected" |
Required | |
note |
string, at most 500 characters | Optional |
Unknown properties are refused.
ContinuationSet
| Property | Type | Required | Description |
|---|---|---|---|
lease_token |
string | Required | The token from the claim item (or the durable attempt after received) that currently holds this session. |
continuation |
Continuation | Required | The runtime’s own session id (stored encrypted, never shown to recipients). |
Unknown properties are refused.
Continuation
The runtime’s own session id (stored encrypted, never shown to recipients).
| Property | Type | Required | Description |
|---|---|---|---|
kind |
string, at most 40 characters | Required | |
id |
string, at most 300 characters | Required |
Unknown properties are refused.
ClaimCreate
| Property | Type | Required | Description |
|---|---|---|---|
target |
ClaimTarget | Required | |
max |
integer, from 1 to 20 | Optional | |
consumer |
string, at most 120 characters | Required | Stable id of this consumer, shown to the human. |
lease_seconds |
integer, from 10 to 600 | Optional | |
attempt_timeout |
integer, from 60 to 86400 | Optional | How long a received instruction holds its session’s head for this consumer before it becomes uncertain and the head is released (default 600). |
Unknown properties are refused.
ClaimTarget
Type: SessionTarget or AgentTarget.
Chosen by type: "session": SessionTarget, "agent": AgentTarget.
SessionTarget
Claim one session’s steering queue.
| Property | Type | Required | Description |
|---|---|---|---|
type |
"session" |
Required | |
session |
string | Required | A ses_… id. |
Unknown properties are refused.
AgentTarget
Claim across an agent’s sessions and kickoffs (a daemon), optionally within one project.
| Property | Type | Required | Description |
|---|---|---|---|
type |
"agent" |
Required | |
agent |
string | Required | |
project |
ProjectRef | Optional | A project slug (auto-created on first use) or prj_… id. Omit for default. A slug that normalises (lowercase, letters and digits only) to an existing project’s key names that project, so My App, my-app and my_app are one project. Automatic creation stops at 1,000 live projects per org and mode with 429 quota_exceeded; existing projects stay usable. Nothing remembers a deleted project (projects.delete): the next message that names its slug creates a fresh one. |
Unknown properties are refused.
Claim
| Property | Type | Required | Description |
|---|---|---|---|
object |
"claim" |
Required | |
id |
string | Required | |
items |
array of ClaimItem | Required |
ClaimItem
continuation is returned only to the claiming runtime, never in Message or events.
| Property | Type | Required | Description |
|---|---|---|---|
message |
Message | Required | One object for notify, ask and steer. Never contains answer links. On human routes (user token, answer link, delegate) Kabu returns the recipient projection: to lists only the caller, metadata is {}, and correlation, extensions and quiz answers before the reveal point are null. For a recipient who did not respond, resolution is null (status and settled_at still show the ask is settled), so no recipient learns who else was asked or what they answered; the responding human, the creator and integrators see the full resolution and receipt. |
lease_token |
string | Required | |
lease_expires_at |
Timestamp | Required | |
outcome_deadline |
Timestamp or null | Required | |
continuation |
ContinuationView or null | Required |
ContinuationView
The runtime’s own session id (stored encrypted, never shown to recipients).
| Property | Type | Required | Description |
|---|---|---|---|
kind |
string, at most 40 characters | Required | |
id |
string, at most 300 characters | Required |