Skip to content
Hoody.com

A session is the long-lived context in which an agent runs: an attached conversation with a frozen binding (realm, container, working directory, tool mode, directory scope, backend) and a persisted history. This page is the entry point for the session lifecycle: listing persisted sessions, reading one, reading its per-call LLM usage, listing the directories it spans, creating or forking or attaching one, renaming it, closing it, trimming its history, and hard-deleting it. Turn dispatch, streaming, gates, leases, and per-session settings each have their own page.

  • Create with POST /api/v1/agent/sessions. Use the fork field to branch from an existing session, or the attach field to rejoin one. Send an Idempotency-Key header to make a create retry-safe: a retry with the same key re-joins the same session (replayed:true).
  • Read the persisted summary with GET /api/v1/agent/sessions/{id}. Live sessions also report their frozen start binding and any parked gate.
  • Read LLM usage with GET /api/v1/agent/sessions/{id}/usage to walk the per-call usage log for a live or closed session without attaching.
  • Rename with PATCH /api/v1/agent/sessions/{id} to set or clear the title.
  • Close the live connection with POST /api/v1/agent/sessions/{id}/close. To also remove the persisted record, use DELETE /api/v1/agent/sessions/{id}?hard=true instead.
  • Trim the conversation history with POST /api/v1/agent/sessions/{id}/trim.

Lists persisted sessions for the requesting cwd (open and closed), with an Attached flag set for live sessions. Pass ?page=N&limit=M to receive the page-th window of size M (page is 1-based; an invalid page or limit returns 400 bad_request). Omit limit to receive the full set. meta.total is always the full pre-slice count; meta.page and meta.limit echo the window only when a limit was supplied.

NameInTypeRequiredDescription
include_systemquerybooleanNoWhen true, also include daemon-owned system/resident sessions in the listing.
pagequeryintegerNo1-based page number for pagination.
limitqueryintegerNoMaximum items per page (0 = no pagination).
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
realmquerystringNoThe realm to list: “global” (sessions not tied to a realm), a 24-hex realm id, or “all” for every realm this login serves. Also accepted as the X-Hoody-Realm header, except “all”. Omitted, the agent’s current realm.
X-Hoody-RealmheaderstringNoPer-request realm selector: “global” (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.

This endpoint takes no request body.

Terminal window
curl -X GET \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions?page=1&limit=20' \
-H 'Authorization: Bearer <token>'

Returns the persisted summary for a session (live or closed). A live session also surfaces its frozen start binding (started: realm, container, modes), attached:true, its incarnation (the namespace of its stream sequence numbers and gate ids), and pending_gate {id, generation, type} while a confirm or question gate is parked.

NameInTypeRequiredDescription
idpathstringYesThe session id.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
X-Hoody-RealmheaderstringNoPer-request realm selector: “global” (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): “global” (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.

This endpoint takes no request body.

Terminal window
curl -X GET \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/9f2c4e1a-5b7d-4c3e-8a21-6d0f3b9e7c55' \
-H 'Authorization: Bearer <token>'

Returns one row per recorded LLM call of the session (its turns, and the helpers and workflow steps it ran) with the token counts the provider reported (cache reads and cache writes apart from uncached input), the cost and the latency, oldest first, plus totals over the whole session. Use it to see how much of each prompt the provider served from its cache. A failed attempt is its own row. Works for a live or closed session without attaching.

after_id is an exclusive cursor: rows with a larger id. To read every row, send next_after_id back as after_id while has_more is true; polling with next_after_id later returns only rows written since. limit caps the page (1 to 5000, default 500). totals always cover every row of the session, whatever page was asked for. A session that is not visible to this caller is a plain 404 (uniform envelope).

NameInTypeRequiredDescription
idpathstringYesThe session id.
after_idqueryintegerNoExclusive cursor: return rows whose id is greater than this. Omit (or 0) to start from the session’s first row. Negative or non-integer = 400.
limitqueryintegerNoReturn at most this many rows (1 to 5000, default 500). Out of range or non-integer = 400.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
X-Hoody-RealmheaderstringNoPer-request realm selector: “global” (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): “global” (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.

This endpoint takes no request body.

Terminal window
curl -X GET \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/9f2c4e1a-5b7d-4c3e-8a21-6d0f3b9e7c55/usage?after_id=0&limit=500' \
-H 'Authorization: Bearer <token>'

Returns the distinct working directories across all persisted sessions, most-recent first.

NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
X-Hoody-RealmheaderstringNoPer-request realm selector: “global” (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): “global” (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.

This endpoint takes no request body.

Terminal window
curl -X GET \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/cwds' \
-H 'Authorization: Bearer <token>'

Opens a new agent session, or forks or attaches an existing one. The session binding is frozen at start: realm, container, cwd, tool_mode, dir_scope, and backend cannot be changed afterward.

  • To create a new session, omit attach and fork.
  • To fork from an existing session, supply fork (the parent session id), and optionally fork_turn_idx to choose where to branch. The fork inherits the parent’s chat agent.
  • To attach to an existing session, supply attach (the session id). A resumed session keeps its model and chat agent.

BYOA: backend:"acp" plus delegated_agent delegate the session to an external CLI agent (the only supported BYOA backend is "claude"); the daemon enforces the per-agent enable gate (the local sandbox is mandatory; there is no trust gate).

Send a standard Idempotency-Key header to make the create retry-safe: a retry with the same key re-joins the same session (replayed:true) instead of creating a second one. The same key with a different request body returns 422.

A session that has never been prompted is a draft and is not saved: once no client has been attached to it for 5 minutes it is closed and discarded, and later calls by its id answer 404. Send the first prompt, or keep a stream or an attachment lease open, to keep it. A session with at least one turn is saved and can be re-attached by id after it is closed.

For a keyed create, every start refusal except admission_write_failed and session_terminating consumes the key: create again with a new Idempotency-Key.

NameInTypeRequiredDescription
Idempotency-KeyheaderstringNoOpaque retry key (1 to 255 printable ASCII, no whitespace). A retry with the same key returns the same receipt and never re-runs the turn; the same key with a different request body is 422.
realmquerystringNoPer-request realm selector (the query alias of the X-Hoody-Realm header, read only when the header is absent). "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
realmstringNoRealm selector to scope the session (frozen at start).
containerstringNoContainer id or selector to run tools on (frozen at start).
cwdstringNoWorking directory for the session (frozen at start).
config_dirstringNoConfig directory override.
modelstringNoModel for this session. On a fresh create or fork it overrides the chat agent’s pinned model for this session only (it is not written to the agent; use PATCH /sessions/{id}/model to change it and repin the agent globally). Omit it to use the agent’s pinned model (or your default). A model with no known provider prefix, or a fusion composite that does not exist, is refused 422 unknown_model and no session is created (client.agent.models.list() lists the choices). Rejected (400) together with attach (a resumed session keeps its model) or backend:"acp" (the delegated agent selects its own).
agentstringNoInitial chat-agent name. Rejected (400) together with fork (a fork inherits its parent’s chat agent) or attach (a resumed session keeps its agent).
tool_modestringNoInitial tool mode (frozen at start): standard (the default) or orchestrator. Any other value is refused 400 invalid_tool_mode.
dir_scopestringNoInitial directory-access scope (frozen at start): home or full. Any other value is refused 400 invalid_dir_scope.
attachstringNoAttach to an existing session instead of creating one; the value is that session’s id.
forkstringNoFork from an existing session; the value is that session’s id. The source must be LIVE in the daemon: fork copies its in-memory state and does not load a saved record the way attach does. An unknown id, a session in another realm, or one that has ended (closed, reaped or lost to a restart) is refused 404 not_found and no session is created; attach the ended session first to reload it, then fork it.
fork_turn_idxintegerNoTurn index to fork at (with fork).
backendstringNoSession backend: "" (Hoody LLM) or "acp" (BYOA delegated agent).
delegated_agentstringNoBYOA agent when backend:"acp": claude.
headlessbooleanNoStart the session in headless posture.
approvalobjectNoApproval policy assertion. On a create or fork it sets the session’s policy; on an attach it is checked against the live session (a session that cannot honour it returns 409 approval_policy_unsatisfiable, and it is closed for this caller). Asserting "always" also hands this caller the approver lease when none is live (approver_lease in the response, returned once). See the table below.
expected_bindingobjectNoFail-closed binding assertion. Only the dimensions given are compared with the binding the session actually resolved to; a contradiction returns 409 binding_mismatch (details name each mismatch) and the session is closed. See the table below.
prompt_blocksobjectNoSwitches for the optional system-prompt blocks, for a lean session: false turns a block off for this session. Switches only turn blocks off: true undoes a false in the agent’s own prompt_blocks frontmatter, but never turns on a block the box settings turned off. An omitted key keeps the block. Frozen at create and kept on resume; a fork inherits its parent’s switches and applies its own on top. An unknown key is 400; rejected (400) together with attach. See the table below.
model_settingsobjectNoPer-turn model settings for this session, the same object as the completion route’s settings: thinking, temperature, max_tokens, response_format. Per field they win over the chat agent’s own frontmatter; an omitted field keeps the agent’s value. Every turn applies them leniently: a setting the model or its adapter cannot take is left out of that request and logged, never an error. Frozen at create and kept on resume; a fork inherits its parent’s settings and applies its own on top. Unknown or invalid members are 400; rejected (400) together with attach, with backend:"acp", and on a fork of a delegated (acp) session that names no backend. Subagents and workflow steps do not inherit them. See the table below.
helper_gatesbooleanNotrue parks a spawn_agent helper’s approvals (a hook asking to confirm) and questions as gates on this session instead of failing them. Each is listed under pending_helper_gates and answered by its gate_id on /confirm or /answer, beside the lead’s own gate. Fixed when the session starts: set it on the create, or on an attach that reopens a closed session. On an attach to a live session, true for a session started without it is refused 400 helper_gates_unavailable. Defaults to false.
outcome_claimsbooleanNotrue gives the model the report_outcome tool and one prompt line asking it to call the tool last, alone, to say what it did and cite the tool calls that show it. A response whose every tool call is an accepted report_outcome ends the turn through the same end-of-turn checks as a normal finish. The turn then sends event.outcome_claims just before event.agent_done. No effect on backend:"acp". Fixed when the session starts, like helper_gates; on an attach to a live session, true for a session started without it is refused 400 outcome_claims_unavailable. Defaults to false.
frame_toolsbooleanNotrue gives the model the request_view tool and one prompt line asking it to use the tool when the user asks for a View: a live page of their data, such as a table of their containers. Set it only from a Frame that answers it. A call parks as a question gate (event.user_question with category frame_request and frame_request {kind: "view", request, id}); the Frame makes the View and answers on /answer with its status JSON. Never shown to a headless, delegated, orchestrator, or resident session; an automated turn (a loop, TODO, or background-task fire) is refused it. Fixed when the session starts, like helper_gates; on an attach to a live session, true for a session started without it is refused 400 frame_tools_unavailable. Defaults to false.
FieldTypeRequiredDescription
modestringNoThe approval mode to assert: "" (default policy), default, or always (every tool call waits for the approver). An empty string means default, exactly like omitting the property; the value is compared after surrounding whitespace is trimmed.
lockedbooleanNoLock the policy so later setters (PUT /sessions/{id}/approval, PATCH /sessions/{id}/yolo) are refused.
FieldTypeRequiredDescription
realmstringNoThe realm selector the session must have resolved to.
containerstringNoThe container id the session must have resolved to.
cwdstringNoThe working directory the session must have resolved to.
backendstringNoThe backend the session must be running on: "" (unasserted), llm (Hoody LLM), or acp (BYOA delegated agent). An empty string leaves this dimension unasserted, exactly like omitting the property.
FieldTypeRequiredDescription
contractbooleanNoThe task-completion contract (finish the task, verify results, say what remains). Callers that read a session’s outcome rely on it; turn it off only when you handle outcome reporting yourself.
transcriptsbooleanNoWhere this realm’s other session transcripts are stored.
frequent_filesbooleanNoThe list of files the agent opens most often in this project.
hook_contextbooleanNoContext returned by SessionStart hooks.
memorybooleanNoProject memory recalled for this session.
project_instructionsbooleanNoProject instruction files (CLAUDE.md, AGENTS.md).
agent_instructionsbooleanNoThe user’s global instructions for every agent.
team_rulesbooleanNoThe team rules (guidance and playbook rules from client.agent.hooks.setRules()) that cover the agent.
skillsbooleanNoThe catalogue of available skills.
workflowsbooleanNoThe catalogue of available workflows and the workflow hint.
verbositybooleanNoThe response-verbosity directive.
hoody_platformbooleanNoThe Hoody platform briefing.
hoody_execbooleanNoThe hoody-exec script conventions.
fleet_noticebooleanNoThe notice that fleet tools are unavailable in this session.
FieldTypeRequiredDescription
thinkingobjectNoReasoning: {type: enabled or disabled, effort?: low, medium, high, xhigh, or max}. effort is allowed only with enabled. Absent keeps the model’s default reasoning.
temperaturenumberNoSampling temperature, 0 to 2 (the model’s own range applies; many models accept it only with thinking disabled).
max_tokensintegerNoOutput cap, 1 to 1000000, clamped to the model’s output limit.
response_formatobjectNo{type: json_object}, or {type: json_schema, schema: {...}, name?, strict?}. name matches ^[A-Za-z0-9_-]{1,64}$ and defaults to "response".
Terminal window
curl -X POST \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: 01HF8Z2P3QYVJ4N5K6M7R8T9C0' \
-d '{
"cwd": "/home/user/projects/parser",
"tool_mode": "standard",
"dir_scope": "home",
"headless": false,
"approval": {
"mode": "default",
"locked": false
},
"model_settings": {
"thinking": {
"type": "enabled",
"effort": "medium"
}
}
}'

Sets the session’s title, or clears it back to the automatic title with name:"". Works on a live session (renamed in place; attached clients receive event.session_renamed) and on a closed one (its persisted record is rewritten where it lies; a closed session stays closed). The daemon sanitizes the title (control characters removed, surrounding whitespace trimmed, secret-shaped tokens redacted, capped at 120 characters) and returns the value it stored.

A live session that has not run a turn yet keeps the title in memory and persists it with its first turn. name is required: an absent field is 400, never a silent clear. A session in another realm, owned by another account, managed by the agent itself, or simply unknown is the same plain 404.

NameInTypeRequiredDescription
idpathstringYesThe session id.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
X-Hoody-RealmheaderstringNoPer-request realm selector: “global” (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): “global” (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
FieldTypeRequiredDescription
namestringYesThe new title. An empty string clears it back to the automatic title. Required; omitting it is a 400, not a clear.
Terminal window
curl -X PATCH \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/9f2c4e1a-5b7d-4c3e-8a21-6d0f3b9e7c55' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"name": "Release checklist"
}'

Tears the session down. The daemon cancels it and removes the live session. Use this when you want to end the connection but keep the persisted record. To also remove the persisted record, use DELETE /api/v1/agent/sessions/{id}?hard=true instead.

NameInTypeRequiredDescription
idpathstringYesSession identifier.
realmquerystringNoPer-request realm selector (the query alias of the X-Hoody-Realm header, read only when the header is absent). "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.

This endpoint takes no request body.

Terminal window
curl -X POST \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/sess_01HF8Z2P3QYVJ4N5K6M7R8T9C0/close' \
-H 'Authorization: Bearer <token>'

Truncates the session’s conversation history to (and including) the given turn_idx. When a gate is parked, the command is applied only between turns, so it may not have taken effect yet (deferred:true, with a note explaining why).

NameInTypeRequiredDescription
idpathstringYesSession identifier.
realmquerystringNoPer-request realm selector (the query alias of the X-Hoody-Realm header, read only when the header is absent). "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.
FieldTypeRequiredDescription
turn_idxintegerNoTurn index to truncate history to (and including).
Terminal window
curl -X POST \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/sess_01HF8Z2P3QYVJ4N5K6M7R8T9C0/trim' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"turn_idx": 4
}'

Closes the live session connection (the daemon cancels the session). Pass ?hard=true to also remove the persisted record. Without ?hard, only the live connection is torn down.

NameInTypeRequiredDescription
idpathstringYesSession identifier.
hardquerybooleanNoWhen true, also remove the persisted session record (not just the live connection).
realmquerystringNoPer-request realm selector (the query alias of the X-Hoody-Realm header, read only when the header is absent). "global" or a 24-hex id. Rejected on active-only routes.
X-Hoody-CwdheaderstringNoPer-request working-directory scope. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk install a stateless read or write resolves.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected on active-only routes.

This endpoint takes no request body.

Terminal window
curl -X DELETE \
'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/sess_01HF8Z2P3QYVJ4N5K6M7R8T9C0?hard=true' \
-H 'Authorization: Bearer <token>'