Sessions
A running unit of agent work; drives Live Activities.
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.
Get or create a session (agent), or kick one off (human)
POST/v2/sessionsAuthorization depends on intent. Without steer, it creates or finds a running session and needs sessions:write. With steer, it is a human kickoff and needs a user token, or steer:write plus an as_recipient in the target audience; sessions:write is not required, and a key holding messages:write is refused (403 self_response_forbidden).
- Auth: an API key, or a signed-in human’s token (the Kabu apps).
- Scopes:
sessions:write, orsteer:write. - Signed-in humans:
audience.
| 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. |
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: SessionCreate.
| Status | Means | Body |
|---|---|---|
201 |
Created, or the existing open session for (project, agent, external_id). | Session |
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" \
-H "Authorization: Bearer $KABU_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"title":"…"}'List sessions
GET/v2/sessionsWith a user token, only sessions whose audience includes the caller.
- Auth: an API key, or a signed-in human’s token (the Kabu apps).
- Scopes:
sessions:read. - Signed-in humans:
audience.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
limit |
query | integer, from 1 to 100 | Optional | |
after |
query | string | Optional | Opaque cursor from next_cursor. |
project |
query | string | Optional | |
agent |
query | string | Optional | |
external_id |
query | string | Optional | |
status |
query | SessionStatusKnown | Optional | |
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. |
| Status | Means | Body |
|---|---|---|
200 |
OK | SessionList |
4XX |
Error | Problem |
5XX |
Error | Problem |
curl "https://usekabu.com/api/v2/sessions" \
-H "Authorization: Bearer $KABU_API_KEY"Get a session
GET/v2/sessions/{session_id}- Auth: an API key, or a signed-in human’s token (the Kabu apps).
- Scopes:
sessions:read. - Signed-in humans:
audience.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
session_id |
path | string | Required | A ses_… id. |
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. |
curl "https://usekabu.com/api/v2/sessions/$SESSION_ID" \
-H "Authorization: Bearer $KABU_API_KEY"Update status, headline, progress or Live Activity
PATCH/v2/sessions/{session_id}Drives the Live Activity. Device pushes are coalesced to at most one per 2 s.
- Auth: an API key.
- Scopes:
sessions:write.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
session_id |
path | string | Required | A ses_… id. |
If-Match |
header | string | Optional |
Request body: SessionUpdate.
curl -X PATCH "https://usekabu.com/api/v2/sessions/$SESSION_ID" \
-H "Authorization: Bearer $KABU_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'End a session; pending asks are cancelled
POST/v2/sessions/{session_id}/end- Auth: an API key.
- Scopes:
sessions:write.
| 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. |
Request body (optional): SessionEnd.
curl -X POST "https://usekabu.com/api/v2/sessions/$SESSION_ID/end" \
-H "Authorization: Bearer $KABU_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{}'Report whether a machine's agents are live (a batch a minute, and each transition)
PUT/v2/presenceOne reporter per machine, (its key, its installation), sends every session it runs, at most 20, as enums only. The request is one transaction: its (generation, seq) must be newer than the reporter’s stored one, or every report is refused (stale) and nothing renews; taken, it is stored with the reporter’s 150 s lease on the server’s clock. A steady batch writes that one row; a session row is written only when it changes, and presence.updated goes out only then: a new state, a session the batch leaves out, and once when the lease lapses. Presence never changes Session.version, never pushes and writes no request log. 429 beyond 12 requests a minute per reporter, 60 requests and 600 reports a minute per key, or 1,200 requests a minute per org.
- Auth: an API key.
- Scopes:
sessions:write.
Request body: PresenceBeat.
| Status | Means | Body |
|---|---|---|
200 |
OK | PresenceAck |
429 |
A rate, concurrency or quota limit was reached | Problem |
4XX |
Error | Problem |
5XX |
Error | Problem |
curl -X PUT "https://usekabu.com/api/v2/presence" \
-H "Authorization: Bearer $KABU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"instance":"…","generation":0,"seq":1,"reports":[{"session":"…","lane":"…","runtime":"working","source":"hook"}]}'List the presence of sessions
GET/v2/presenceNewest sessions first. With a user token, only sessions whose audience includes the caller. A session that was never leased, or whose lease lapsed over 24 h ago, has no presence.
- Auth: an API key, or a signed-in human’s token (the Kabu apps).
- Scopes:
sessions:read. - Signed-in humans:
audience.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
limit |
query | integer, from 1 to 100 | Optional | |
after |
query | string | Optional | Opaque cursor from next_cursor. |
session |
query | string | Optional | Only this ses_… session. |
agent |
query | string | Optional | Only this agent’s sessions: its agt_… id or slug. |
project |
query | string | Optional | Only this project’s sessions: its prj_… id or slug. |
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. |
| Status | Means | Body |
|---|---|---|
200 |
OK | RuntimePresenceList |
4XX |
Error | Problem |
5XX |
Error | Problem |
curl "https://usekabu.com/api/v2/presence" \
-H "Authorization: Bearer $KABU_API_KEY"Schemas
SessionCreate
An agent key creates a running session. A human (app or steer:write) with steer creates a queued kickoff for a runtime to claim.
| Property | Type | Required | Description |
|---|---|---|---|
title |
string, 1 to 80 characters | 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. |
agent |
string, at most 64 characters | Optional | |
external_id |
string, at most 120 characters | Optional | Your run id. Create is get-or-create on (project, agent, external_id): the open run it finds comes back as it is, except that live.enabled turns its Live Activity on, never an automatic session’s. |
to |
array of RecipientRef, 1 to 20 items | Optional | Audience: who sees this session and its Live Activity, and who may steer it. Default: the key’s default_to; for a human kickoff, the creating human. Messages on the session default to it. |
live |
Live | Optional | Live Activity / Dynamic Island / Android ongoing notification, shown to the session audience. |
steerable |
boolean | Optional | |
automatic |
boolean | Optional | True for a session your integration opens on its own to group its messages, as Kabu’s MCP server does: it claims no run, so it starts idle, returns to idle once an ask in it settles, and never has a Live Activity of its own (live is not turned on, here or by a later get-or-create); each ask in it still has its own. False makes a run, whatever the external_id. Not with steer: a kickoff is a run. Absent, a kickoff or a session with live on is a run, and otherwise an external_id starting with mcp: or auto: (as integrations made them before this field) makes the session automatic. |
steer |
SteerInput | Optional | control: instruction with a body, or a pause / resume / stop signal. |
metadata |
Metadata | Optional | Your own key/value pairs (≤ 50 keys, values ≤ 500 chars), returned verbatim on every object and event. |
Unknown properties are refused.
Live
Live Activity / Dynamic Island / Android ongoing notification, shown to the session audience.
| Property | Type | Required | Description |
|---|---|---|---|
enabled |
boolean | Optional | On: the session’s Live Activity shows it, unless the session is automatic, which never has one. Turning it off ends the activity at once. Turned on again, a new activity starts at the session’s first change eight hours after the ended one started (iOS’s limit), not before. |
style |
string, one of "progress", "steps", "timer" |
Optional |
Unknown properties are refused.
SteerInput
control: instruction with a body, or a pause / resume / stop signal.
Type: SteerInstruction or SteerSignal.
Chosen by control: "instruction": SteerInstruction, "pause": SteerSignal, "resume": SteerSignal, "stop": SteerSignal.
SteerInstruction
A free-text instruction to the running agent.
| Property | Type | Required | Description |
|---|---|---|---|
control |
"instruction" |
Required | |
body |
string, 1 to 8000 characters | Required | |
attachments |
array of AttachmentRef, at most 10 items | Optional | |
as_recipient |
RecipientRef | Optional | rcp_…, ext:<your external id>, or me (the key’s default_to). |
metadata |
Metadata | Optional | Your own key/value pairs (≤ 50 keys, values ≤ 500 chars), returned verbatim on every object and event. |
Unknown properties are refused.
SteerSignal
A control signal: pause, resume or stop. Signals have their own lane: they are leasable even while an instruction holds the head, ordered only among themselves, and charged only to a per-human abuse cap, never to send or month. stop marks every still-queued instruction on the session cancelled.
| Property | Type | Required | Description |
|---|---|---|---|
control |
string, one of "pause", "resume", "stop" |
Required | |
body |
string, 1 to 8000 characters | Optional | Optional reason. |
attachments |
array of AttachmentRef, at most 10 items | Optional | |
as_recipient |
RecipientRef | Optional | rcp_…, ext:<your external id>, or me (the key’s default_to). |
metadata |
Metadata | Optional | Your own key/value pairs (≤ 50 keys, values ≤ 500 chars), returned verbatim on every object and event. |
Unknown properties are refused.
Session
| Property | Type | Required | Description |
|---|---|---|---|
object |
"session" |
Required | |
id |
string | Required | |
livemode |
boolean | Required | |
project |
string | Required | |
version |
integer | Required | |
status |
SessionStatus | Required | Open enum. Known values are SessionStatusKnown; accept and ignore unknown values. |
title |
string | Required | |
headline |
string or null | Required | |
to |
array of string | Required | The session audience. |
agent |
string or null | Required | |
external_id |
string or null | Required | |
progress |
ProgressView or null | Required | |
live |
LiveView | Required | Live Activity / Dynamic Island / Android ongoing notification, shown to the session audience. |
steerable |
boolean | Required | |
automatic |
boolean | Optional | Read-only. True for a session made to group messages (SessionCreate.automatic; a session made before the field whose external_id starts with mcp: or auto: counts too): it claims no run and never has a Live Activity of its own. |
listening |
boolean | Required | Read-only presence: a consumer holds a claim or stream. |
open_asks |
integer | Required | |
queued_steers |
integer | Required | |
steering |
SteeringState or null | Required | |
outcome |
string or null | Required | |
metadata |
Metadata | Required | Your own key/value pairs (≤ 50 keys, values ≤ 500 chars), returned verbatim on every object and event. |
created_at |
Timestamp | Required | |
updated_at |
Timestamp | Required | |
ended_at |
Timestamp or null | Required | |
presence |
RuntimePresence | Optional | Whether a session’s agent is live: a lease its machine renews, merged with the session’s asks and end. Read-only. A session never leased has none. Presence never changes Session.version and never pushes. |
SessionStatus
Open enum. Known values are SessionStatusKnown; accept and ignore unknown values.
Type: SessionStatusKnown or string.
SessionStatusKnown
queued until a runtime claims a kickoff; waiting while an ask on the session is pending.
Type: string, one of "queued", "running", "waiting", "idle", "ended".
ProgressView
Measured progress, shown exactly as sent: value of total with label naming what is counted (54 of 172 projects), or known steps, the one in state doing named. Report progress only when it is measurable (items done of a known total) or for known steps; never an estimated percentage; otherwise send only a headline.
| Property | Type | Required | Description |
|---|---|---|---|
value |
number, ≥ 0 | Optional | |
total |
number, > 0 | Optional | |
label |
string, at most 60 characters | Optional | |
steps |
array of StepView, at most 8 items | Optional |
StepView
| Property | Type | Required | Description |
|---|---|---|---|
label |
string, at most 40 characters | Required | |
state |
string, one of "todo", "doing", "done", "failed" or string |
Required |
LiveView
Live Activity / Dynamic Island / Android ongoing notification, shown to the session audience.
| Property | Type | Required | Description |
|---|---|---|---|
enabled |
boolean | Optional | On: the session’s Live Activity shows it, unless the session is automatic, which never has one. Turning it off ends the activity at once. Turned on again, a new activity starts at the session’s first change eight hours after the ended one started (iOS’s limit), not before. |
style |
string, one of "progress", "steps", "timer" or string |
Optional |
SteeringState
Why steering is or is not moving, for the human.
| Property | Type | Required | Description |
|---|---|---|---|
head |
string or null | Required | |
state |
string | Required | idle, leased, received or blocked (open). |
consumer |
string or null | Required | |
since |
Timestamp or null | Required | |
reason |
string or null | Required |
RuntimePresence
Whether a session’s agent is live: a lease its machine renews, merged with the session’s asks and end. Read-only. A session never leased has none. Presence never changes Session.version and never pushes.
| Property | Type | Required | Description |
|---|---|---|---|
object |
"presence" |
Required | |
id |
string | Required | The session’s ses_… id. |
version |
integer | Required | Monotonic per session’s presence, apart from Session.version; increases on every change except a renewal. presence.updated events carry it. |
livemode |
boolean | Required | |
project |
string | Required | |
agent |
string or null | Required | |
state |
PresenceState | Required | Open enum. Known values are PresenceStateKnown; accept and ignore unknown values. |
runtime |
PresenceRuntime | Required | Open enum. Known values are PresenceRuntimeKnown; accept and ignore unknown values. |
attention |
PresenceAttention or null | Required | |
source |
PresenceSource | Required | Open enum. Known values are PresenceSourceKnown; accept and ignore unknown values. |
outcome |
string or null | Required | |
since |
string (date-time) | Required | When state last changed, by the server’s clock. |
last_seen_at |
string (date-time) | Required | The last batch the server took that held the session. |
expires_at |
string (date-time) | Required | When the reporter’s lease lapses (or lapsed) for this session. |
PresenceState
Open enum. Known values are PresenceStateKnown; accept and ignore unknown values.
Type: PresenceStateKnown or string.
PresenceStateKnown
The merged answer to “is it live?”, first match wins: ended (the session ended), waiting (an ask is open), blocked (a live lease reports attention terminal), working, idle and online (a live lease), offline (the lease lapsed or the harness is gone). paused is only an agent’s: it outranks its sessions.
Type: string, one of "ended", "waiting", "blocked", "working", "idle", "online", "offline", "paused".
PresenceRuntime
Open enum. Known values are PresenceRuntimeKnown; accept and ignore unknown values.
Type: PresenceRuntimeKnown or string.
PresenceRuntimeKnown
What a session’s runtime is doing, as its machine reports it: working while a turn is open, idle once it ended (ready for a prompt), online from a liveness-only source, offline when the harness is gone. Presence reads offline once the lease lapses.
Type: string, one of "working", "idle", "online", "offline".
PresenceAttention
Open enum. Known values are PresenceAttentionKnown; accept and ignore unknown values.
Type: PresenceAttentionKnown or string.
PresenceAttentionKnown
Why a live runtime needs its person: terminal while a prompt waits at the computer (a permission request).
Type: string, one of "terminal".
PresenceSource
Open enum. Known values are PresenceSourceKnown; accept and ignore unknown values.
Type: PresenceSourceKnown or string.
PresenceSourceKnown
Which local signal a report came from: the harness’s hooks, the Herdr bridge, kabu mcp or the kabu CLI.
Type: string, one of "hook", "herdr", "mcp", "cli".
SessionList
| Property | Type | Required | Description |
|---|---|---|---|
object |
"list" |
Required | |
data |
array of Session | Required | |
has_more |
boolean | Required | |
next_cursor |
string or null | Required |
SessionUpdate
live with enabled off ends the session’s Live Activity at once, with a generic last state. Turned on, it starts one, unless the session is automatic; after an end, at the session’s first change eight hours after the ended activity started.
| Property | Type | Required | Description |
|---|---|---|---|
status |
string, one of "running", "idle" |
Optional | |
headline |
string, at most 80 characters | Optional | |
progress |
Progress | Optional | Measured progress, shown exactly as sent: value of total with label naming what is counted (54 of 172 projects), or known steps, the one in state doing named. Report progress only when it is measurable (items done of a known total) or for known steps; never an estimated percentage; otherwise send only a headline. |
live |
Live | Optional | Live Activity / Dynamic Island / Android ongoing notification, shown to the session audience. |
metadata |
Metadata | Optional | Your own key/value pairs (≤ 50 keys, values ≤ 500 chars), returned verbatim on every object and event. |
Unknown properties are refused.
Progress
Measured progress, shown exactly as sent: value of total with label naming what is counted (54 of 172 projects), or known steps, the one in state doing named. Report progress only when it is measurable (items done of a known total) or for known steps; never an estimated percentage; otherwise send only a headline.
| Property | Type | Required | Description |
|---|---|---|---|
value |
number, ≥ 0 | Optional | |
total |
number, > 0 | Optional | |
label |
string, at most 60 characters | Optional | |
steps |
array of Step, at most 8 items | Optional |
Unknown properties are refused.
Step
| Property | Type | Required | Description |
|---|---|---|---|
label |
string, at most 40 characters | Required | |
state |
string, one of "todo", "doing", "done", "failed" |
Required |
Unknown properties are refused.
SessionEnd
| Property | Type | Required | Description |
|---|---|---|---|
outcome |
string, one of "success", "failure", "cancelled" |
Optional | |
summary |
string, at most 500 characters | Optional | |
dismiss_after |
integer, from 0 to 14400 | Optional |
Unknown properties are refused.
PresenceBeat
A reporter’s whole state: every session it runs (at most 20), once a minute and at each transition; a session it leaves out goes offline. A batch is one transaction. Taking it renews the reporter’s 150 s lease on the server’s clock, which keeps its sessions live; a steady batch writes that lease and nothing else.
| Property | Type | Required | Description |
|---|---|---|---|
instance |
string, matching ^pin_[0-9A-Za-z]{8,40}$ |
Required | The installation’s id, made once and kept on the machine for its life, never per start. Kabu binds it to the key that sends it: the reporter is (key, instance), so the same id under another key is another reporter. |
generation |
integer, from 0 to 9007199254740991 | Required | The reporter’s restart counter: kept on disk and raised by one at every start, never read from a clock. Generations of different reporters are never compared: another reporter takes a session only once its lease lapsed. A reporter that lost its counter resumes above the ack’s generation. |
seq |
integer, from 1 to 9007199254740991 | Required | Raised on every request of a generation. The reporter’s (generation, seq) is stored with every accepted batch, in the same transaction, so a retried or replayed request is refused (stale) and renews nothing: a retry takes a new seq. |
reports |
array of PresenceReport, 1 to 20 items | Required |
Unknown properties are refused.
PresenceReport
One session’s runtime, as enums only: no prompt, path, tool name or title is accepted.
| Property | Type | Required | Description |
|---|---|---|---|
session |
string, matching ^ses_[0-9A-Za-z]{1,64}$ |
Required | A ses_… id the key can see: the session of the run, found or created with an external_id the machine computed as HMAC(installation secret, harness ‖ native session id), never the raw id. |
lane |
string, matching ^ln_[0-9a-f]{16,64}$ |
Required | An opaque hash of the local lane (machine, harness and native session) the report folds; never a path. |
runtime |
PresenceRuntimeKnown | Required | What a session’s runtime is doing, as its machine reports it: working while a turn is open, idle once it ended (ready for a prompt), online from a liveness-only source, offline when the harness is gone. Presence reads offline once the lease lapses. |
attention |
PresenceAttentionKnown or null | Optional | |
source |
PresenceSourceKnown | Required | Which local signal a report came from: the harness’s hooks, the Herdr bridge, kabu mcp or the kabu CLI. |
Unknown properties are refused.
PresenceAck
| Property | Type | Required | Description |
|---|---|---|---|
object |
"presence_ack" |
Required | |
server_time |
Timestamp | Required | |
next_beat_in |
integer | Required | Seconds until the next batch is due (60). A transition may go at once. |
generation |
integer | Required | The reporter’s stored generation after this request. |
seq |
integer | Required | The reporter’s stored seq after this request: send a higher one next. |
expires_at |
string (date-time) or null | Required | |
results |
array of PresenceResult | Required | One per report, in order. |
PresenceResult
| Property | Type | Required | Description |
|---|---|---|---|
session |
string | Required | |
accepted |
boolean | Required | |
reason |
string or null | Required | |
expires_at |
string (date-time) or null | Required |
RuntimePresenceList
| Property | Type | Required | Description |
|---|---|---|---|
object |
"list" |
Required | |
data |
array of RuntimePresence | Required | |
has_more |
boolean | Required | |
next_cursor |
string or null | Required |