Agent: Session settings
Section titled “Agent: Session settings”Most endpoints on this page are PATCH calls that change one property of an existing agent session and take effect from the next turn. Each call is safe to issue while a turn is running; the gateway forwards the change to the live session and, when a confirm or question gate is parked, defers the change to apply between turns (a 200 response with deferred: true reports this). Two settings break the pattern. The model switch applies inline and synchronously, so a busy session returns 409 instead of a deferred success. The after-compaction message is a PUT and is the other exception: the agent re-adds the text as a user message right after the summary of every compaction, before the next model request, rather than waiting for the next turn.
Agent and model
Section titled “Agent and model”PATCH /api/v1/agent/sessions/{id}/agent
Section titled “PATCH /api/v1/agent/sessions/{id}/agent”Live chat-agent switch, echoed as a session event. Safe to call while a turn is running; deferred between turns if a gate is parked.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Path identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; todos.create also accepts a body cwd). |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: global or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
agent | string | No | Chat-agent name to switch to. |
curl -X PATCH "https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com/api/v1/agent/sessions/{id}/agent" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"agent":"build"}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.setAgent('{id}', { agent: 'build' });{ "status": "ok"}Responses
Section titled “Responses”Applied.
{ "status": "ok"}When a gate is parked, the response also carries deferred: true and a note explaining why the command has not yet been applied.
| Field | Type | Description |
|---|---|---|
status | string | ok on success. |
deferred | boolean | Present and true when a gate is parked: the command is applied only between turns. |
note | string | Present alongside deferred: why the command has not been applied yet. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only or global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it, so a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
PATCH /api/v1/agent/sessions/{id}/model
Section titled “PATCH /api/v1/agent/sessions/{id}/model”Synchronous inline model switch: applies the model now and returns exactly what happened (persisted: false means the live switch stands but reverts next session). Safe to call while a turn is running, but returns 409 instead of deferring if the session is busy or external-agent owned.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Path identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; todos.create also accepts a body cwd). |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: global or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model spec to switch to (provider-prefixed, e.g. anthropic/claude-opus-4-8, or fusion/<slug>). A blank value is rejected and never treated as a silent no-op. |
curl -X PATCH "https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com/api/v1/agent/sessions/{id}/model" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"model":"anthropic/claude-opus-4-8"}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.setModel('{id}', { model: 'anthropic/claude-opus-4-8' });{ "status": "ok", "model": "anthropic/claude-opus-4-8", "persisted": true}Responses
Section titled “Responses”Applied.
{ "status": "ok", "model": "anthropic/claude-opus-4-8", "persisted": true}| Field | Type | Description |
|---|---|---|
status | string | ok on a successful switch. |
model | string | The model spec now active on the session. |
persisted | boolean | Whether the choice was written to the chat agent’s frontmatter. false means the live switch stands but reverts next session. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters (including a blank model). | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only or global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
Session unknown, closed (including the close-vs-switch race), cross-realm, or foreign-owner, all collapsed into one answer so nothing leaks.
{ "code": "not_found", "message": "session not live"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Session not found | Unknown, closed (including the close-vs-switch race), cross-realm, or foreign-owner session, all collapsed into one code and one message so nothing leaks. | List sessions and retry against a live one. |
Session busy or delegated.
{ "code": "turn_in_flight", "message": "a turn is running (or parked on a gate) — retry when the session is idle"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
gate_parked | Gate parked | A confirm or question gate is parked; the switch cannot apply until it resolves. | Answer or cancel the gate under details.pending_gate, then retry. |
turn_in_flight | Turn in flight | A turn is running (or parked) on the session’s single-writer slot. | Retry when the session is idle. |
delegated_session | Delegated session | The external agent owns its model; switching is unavailable. | Use the external agent’s own configuration. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it, so a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
Model cannot be constructed.
{ "code": "model_unavailable", "message": "cannot switch to model \"x/y\": unknown provider"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
model_unavailable | Model unavailable | Unknown model, missing credential, or invalid fusion composite. | Check the spec and provider credentials. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
Session still initializing when the request ended.
{ "code": "timeout", "message": "session still initializing"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
timeout | Initialization wait cut short | The switch waited on session readiness and the request context ended first. | Retry once the session finishes initializing. |
Reasoning and response
Section titled “Reasoning and response”PATCH /api/v1/agent/sessions/{id}/effort
Section titled “PATCH /api/v1/agent/sessions/{id}/effort”Live reasoning-effort change. Accepts low, medium, high, xhigh, max, or an empty string for the model default. Safe to call while a turn is running; deferred between turns if a gate is parked.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Path identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; todos.create also accepts a body cwd). |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: global or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
effort | string | No | low, medium, high, xhigh, max, or "" for the model default. |
curl -X PATCH "https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com/api/v1/agent/sessions/{id}/effort" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"effort":"high"}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.setEffort('{id}', { effort: 'high' });{ "status": "ok"}Responses
Section titled “Responses”Applied.
{ "status": "ok"}When a gate is parked, the response also carries deferred: true and a note explaining why the command has not yet been applied.
| Field | Type | Description |
|---|---|---|
status | string | ok on success. |
deferred | boolean | Present and true when a gate is parked: the command is applied only between turns. |
note | string | Present alongside deferred: why the command has not been applied yet. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only or global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it, so a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
PATCH /api/v1/agent/sessions/{id}/verbosity
Section titled “PATCH /api/v1/agent/sessions/{id}/verbosity”Live verbosity change. Accepts normal, concise, terse, or minimal. Safe to call while a turn is running; deferred between turns if a gate is parked.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Path identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; todos.create also accepts a body cwd). |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: global or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
level | string | No | normal, concise, terse, or minimal. |
curl -X PATCH "https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com/api/v1/agent/sessions/{id}/verbosity" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"level":"concise"}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.setVerbosity('{id}', { level: 'concise' });{ "status": "ok"}Responses
Section titled “Responses”Applied.
{ "status": "ok"}When a gate is parked, the response also carries deferred: true and a note explaining why the command has not yet been applied.
| Field | Type | Description |
|---|---|---|
status | string | ok on success. |
deferred | boolean | Present and true when a gate is parked: the command is applied only between turns. |
note | string | Present alongside deferred: why the command has not been applied yet. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only or global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it, so a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
Auto-reply loop
Section titled “Auto-reply loop”PATCH /api/v1/agent/sessions/{id}/auto-reply
Section titled “PATCH /api/v1/agent/sessions/{id}/auto-reply”Arm or disarm the self-driving auto-reply loop, including the round budget, replier model, and write opt-in. Safe to call while a turn is running; deferred between turns if a gate is parked.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Path identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; todos.create also accepts a body cwd). |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: global or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
armed | boolean | No | true to arm the auto-reply loop, false to disarm. |
rounds | integer | No | Number of auto-reply rounds budgeted. |
model | string | No | Replier model override. |
allow_writes | boolean | No | Opt in to write-class actions during auto-reply. |
curl -X PATCH "https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com/api/v1/agent/sessions/{id}/auto-reply" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"armed":true,"rounds":5,"model":"anthropic/claude-haiku-4-5","allow_writes":false}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.setAutoReply('{id}', { armed: true, rounds: 5, model: 'anthropic/claude-haiku-4-5', allow_writes: false,});{ "status": "ok"}Responses
Section titled “Responses”Applied.
{ "status": "ok"}When a gate is parked, the response also carries deferred: true and a note explaining why the command has not yet been applied.
| Field | Type | Description |
|---|---|---|
status | string | ok on success. |
deferred | boolean | Present and true when a gate is parked: the command is applied only between turns. |
note | string | Present alongside deferred: why the command has not been applied yet. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only or global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it, so a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
PATCH /api/v1/agent/sessions/{id}/auto-reply/writes
Section titled “PATCH /api/v1/agent/sessions/{id}/auto-reply/writes”Flip the write-class opt-in on an already-armed auto-reply loop without re-arming (no budget reset). Safe to call while a turn is running; deferred between turns if a gate is parked.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Path identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; todos.create also accepts a body cwd). |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: global or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
allow_writes | boolean | No | New write-class opt-in state. |
curl -X PATCH "https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com/api/v1/agent/sessions/{id}/auto-reply/writes" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"allow_writes":true}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.setAutoReplyWrites('{id}', { allow_writes: true });{ "status": "ok"}Responses
Section titled “Responses”Applied.
{ "status": "ok"}When a gate is parked, the response also carries deferred: true and a note explaining why the command has not yet been applied.
| Field | Type | Description |
|---|---|---|
status | string | ok on success. |
deferred | boolean | Present and true when a gate is parked: the command is applied only between turns. |
note | string | Present alongside deferred: why the command has not been applied yet. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only or global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it, so a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
Shell environment
Section titled “Shell environment”PATCH /api/v1/agent/sessions/{id}/hoody-env
Section titled “PATCH /api/v1/agent/sessions/{id}/hoody-env”Live toggle of the session’s HOODY_* shell-env contract for the bash tool. Safe to call while a turn is running; deferred between turns if a gate is parked.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Path identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; todos.create also accepts a body cwd). |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: global or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
enabled | boolean | No | Whether to inject the HOODY_* shell-env contract. |
curl -X PATCH "https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com/api/v1/agent/sessions/{id}/hoody-env" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"enabled":false}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.setHoodyEnv('{id}', { enabled: false });{ "status": "ok"}Responses
Section titled “Responses”Applied.
{ "status": "ok"}When a gate is parked, the response also carries deferred: true and a note explaining why the command has not yet been applied.
| Field | Type | Description |
|---|---|---|
status | string | ok on success. |
deferred | boolean | Present and true when a gate is parked: the command is applied only between turns. |
note | string | Present alongside deferred: why the command has not been applied yet. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only or global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it, so a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
After-compaction message
Section titled “After-compaction message”PUT /api/v1/agent/sessions/{id}/after-compaction
Section titled “PUT /api/v1/agent/sessions/{id}/after-compaction”Sets the text the agent re-adds to the conversation as a user message right after the summary of every compaction (automatic, manual, or the recovery pass that follows a context overflow), so it is in place before the next model request. This is the exception to the “from the next turn” rule above: the text is re-added right after the summary, not deferred to the next turn. The text is stored and re-added byte for byte, never in the system prompt; an empty or whitespace-only text removes the message. The cap is 16384 bytes (16 KiB). The message is saved with the session, kept across restarts, and inherited by a fork; GET /sessions/{id} and GET /sessions/{id}/state show it as after_compaction. A Claude Code session answers 409 delegated_session because Claude Code manages its own context; a closed session answers 404 not_found. Active-realm-scoped.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | The session id. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; todos.create also accepts a body cwd). |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: global or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | The message text, at most 16384 bytes in UTF-8. Empty or whitespace-only removes the message. |
curl -X PUT "https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com/api/v1/agent/sessions/{id}/after-compaction" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"text":"Identity: you are reviewing PRs for the payments service. Always run the unit tests before reporting back."}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://67e89abc123def456789abcd-890abcdef12345678901cdef-agent-1.node-example-1.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.setAfterCompaction('{id}', { text: 'Identity: you are reviewing PRs for the payments service. Always run the unit tests before reporting back.',});{ "status": "ok", "bytes": 121}Responses
Section titled “Responses”Saved.
{ "status": "ok", "bytes": 121}| Field | Type | Description |
|---|---|---|
status | string | ok. |
bytes | integer | The size of the saved text in bytes; 0 when the message was removed. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
The session is a Claude Code session.
{ "code": "delegated_session", "message": "an after-compaction message is not available on a delegated session — the external agent owns its context"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
delegated_session | Delegated session | Claude Code manages its own context, so the agent cannot add a message after its compaction. | Use a session with a Hoody model. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it, so a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
store_failed | Agent store failed | One of the agent’s own stores could not be read, parsed, locked or written, so the operation did not complete. The message names the store (for example “the agent’s settings file is damaged and was left unchanged”). A damaged store is left as it was rather than rewritten. | Retry once; if it persists, repair the named store inside the container. The agent’s log (GET /logs) records a “store failure” entry with the store, the failure kind (io, corrupt or lock) and a path-free cause such as “open: permission denied” or “invalid JSON at offset 12”; it does not name the file’s path. |
{ "code": "restriction_unknown", "message": "the login's realm restriction could not be read — retry"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
restriction_unknown | Login restriction unknown | The agent cannot read yet which realms its login may serve (GET /hoody/auth/status reports restriction “unknown”), so it refuses realm-scoped requests until it can. Nothing was read or changed. | Retry after the restriction is readable. |