This page documents the HTTP endpoints for reading and mutating agent settings, managing model-fusion composites, and configuring BYOA ACP backend agents. The endpoints cover:
Settings core — read the effective merged settings (home → project → settings.local.json) and shallow-merge patches into the home ~/.hoody/settings.json.
BYOA ACP backends — read the BYOA backend status, enable or disable the claude backend, pin its default model and reasoning effort, and store per-backend env secrets in the dedicated 0600 acp-secrets.env store.
Fusion composites — list, create or update, and delete custom model-fusion compositions by slug.
Settings, fusion composites, and the local BYOA ACP report are global, process-wide config with no realm dimension, so a X-Hoody-Realm header or ?realm= query returns 400 realm_scope_unsupported on these routes. The BYOA ACP status report additionally accepts a realm when a remote container is bound through X-Hoody-Container — without a container, the local report has no realm dimension to scope.
The home ~/.hoody/settings.json is the layer PATCH /settings mutates. GET /settings returns the effective merged settings (home → project → settings.local.json, top-level merge) alongside the home-layer object.
Returns the effective merged settings plus the home-layer object that PATCH /settings mutates. Process-wide config (global, no-realm): settings have no realm dimension at any layer, so a per-request realm header returns 400 realm_scope_unsupported.
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; createTodo 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 (HoodyPaths).
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.
Applies a SHALLOW top-level merge into the home ~/.hoody/settings.json (a null value deletes a key). Sending { "features": { ... } } REPLACES the whole features object. A non-null top-level model is rejected (400) because nothing on settings consumes it — pin a model on the chat agent via PATCH /agents/{name}/model, or switch a live session via PATCH /sessions/{id}/model; { "model": null } still deletes a previously-persisted value.
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; createTodo 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 (HoodyPaths).
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.
"message":"realm scope not supported on this route"
}
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.
{
"code":"settings_key_protected",
"message":"settings key 'deny_list' is security-load-bearing and cannot be modified over HTTP"
}
Error Code
Title
Description
Resolution
settings_key_protected
Settings key protected
The patch targets a security-load-bearing top-level settings key (deny_list, features, allowed_directories, hooks, mcp_servers, …). These guardrail keys cannot be modified over HTTP.
Edit settings.json at the host to change a guardrail key; omit it from the HTTP patch.
forbidden
Forbidden (not via the Hoody proxy)
The request did not reach the service through the public endpoint.
Reach the agent through hoody-proxy (e.g. hoody agent … → platform → proxy), not by connecting to the container directly.
{
"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 — 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.
The BYOA (Bring Your Own Agent) ACP backend is a delegated session target. A delegated session — POST /sessions with backend: "acp" — runs through the armed backend, so a backend must be enabled before delegated sessions can use it. Per-backend env VALUES live in the dedicated 0600 acp-secrets.env store; settings.json holds only the env KEY NAMES.
Reports the BYOA delegated-session backend availability (claude) — enabled flag, on-PATH status, trust posture (acp.status). A fixed status object, NOT a paginated collection. The report is resolved through the layered settings the delegated session would use, so X-Hoody-Config-Dir (override) and X-Hoody-Cwd (project layer) are folded. For REMOTE BYOA, a bound X-Hoody-Container switches the report to ON-CONTAINER detection and login probing, and X-Hoody-Realm scopes that probe (threaded as realm_selector). A realm header WITHOUT a container returns 400 realm_scope_unsupported because the local report has no realm dimension.
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; createTodo 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 (HoodyPaths).
X-Hoody-Container
header
string
No
Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. When bound, switches the report to ON-CONTAINER detection / login probing and allows a realm scope.
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; on this route only valid together with a bound X-Hoody-Container.
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; on this route only valid together with a bound X-Hoody-Container.
Arms (or disarms) a BYOA ACP backend for delegated sessions (acp.set_enabled). A delegated session — POST /sessions with backend: "acp" — is refused by the daemon while its backend is disabled, so this is the prerequisite for the whole delegated-session capability on a host configured over HTTP. Writes tools.acp_agents.<agent>.enabled in settings.json. Returns 404 unknown_agent for anything that is not a known BYOA backend (claude).
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; createTodo 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 (HoodyPaths).
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.
"message":"realm scope not supported on this route"
}
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.
{
"code":"admin_unauthorized",
"message":"memory administration requires a valid admin token"
}
Error Code
Title
Description
Resolution
admin_unauthorized
Rejected by the daemon’s own admin gate
Forbidden — the request was refused by the server’s admin gate.
Run the daemon with socket auth (--auth-token-path) and no separate admin capability so its own gate allows HTTP requests forwarded from the gateway; or, for the interactive TUI Memory tab over the socket, present the daemon’s configured Memory-admin token.
forbidden
Forbidden (not via the Hoody proxy)
The request did not reach the service through the public endpoint.
Reach the agent through hoody-proxy (e.g. hoody agent … → platform → proxy), not by connecting to the container directly.
The named ACP agent is not a known BYOA backend, so a per-agent secret reference would be dead (no launch spec reads it).
Use "claude" — the only BYOA backend.
{
"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 — 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).
Sets the default model and reasoning effort a BYOA ACP backend runs on (acp.set_agent_model). These are the values the daemon passes to the backend at connect; a delegated session started without an explicit model inherits them. An empty value clears the pin and returns the backend to its own default. Returns 404 unknown_agent for anything that is not a known BYOA backend (claude).
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; createTodo 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 (HoodyPaths).
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.
"message":"realm scope not supported on this route"
}
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.
{
"code":"admin_unauthorized",
"message":"memory administration requires a valid admin token"
}
Error Code
Title
Description
Resolution
admin_unauthorized
Rejected by the daemon’s own admin gate
Forbidden — the request was refused by the server’s admin gate.
Run the daemon with socket auth (--auth-token-path) and no separate admin capability so its own gate allows HTTP requests forwarded from the gateway; or, for the interactive TUI Memory tab over the socket, present the daemon’s configured Memory-admin token.
forbidden
Forbidden (not via the Hoody proxy)
The request did not reach the service through the public endpoint.
Reach the agent through hoody-proxy (e.g. hoody agent … → platform → proxy), not by connecting to the container directly.
The named ACP agent is not a known BYOA backend, so a per-agent secret reference would be dead (no launch spec reads it).
Use "claude" — the only BYOA backend.
{
"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 — 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.
PUT /api/v1/agent/acp/agents/{agent}/secrets/{key}
Stores (or clears) one per-backend env VALUE for a BYOA ACP agent (acp.set_secret) in the dedicated 0600 ~/.hoody/acp-secrets.env store under acp/<agent>/ (atomic temp + rename, flock). settings.json holds only the env KEY NAMES; the VALUE lives ONLY in the 0600 store. An empty value DELETES (unsets) the reference. Returns 404 unknown_agent for an agent that is not a known BYOA backend (claude).
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; createTodo 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 (HoodyPaths).
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.
"message":"realm scope not supported on this route"
}
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.
{
"code":"admin_unauthorized",
"message":"memory administration requires a valid admin token"
}
Error Code
Title
Description
Resolution
admin_unauthorized
Rejected by the daemon’s own admin gate
Forbidden — the request was refused by the server’s admin gate.
Run the daemon with socket auth (--auth-token-path) and no separate admin capability so its own gate allows HTTP requests forwarded from the gateway; or, for the interactive TUI Memory tab over the socket, present the daemon’s configured Memory-admin token.
forbidden
Forbidden (not via the Hoody proxy)
The request did not reach the service through the public endpoint.
Reach the agent through hoody-proxy (e.g. hoody agent … → platform → proxy), not by connecting to the container directly.
The named ACP agent is not a known BYOA backend, so a per-agent secret reference would be dead (no launch spec reads it).
Use "claude" — the only BYOA backend.
{
"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 — 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).
Model-fusion composites combine multiple model members into a single named entry (fusion.list, fusion.upsert, fusion.delete). The persisted key is derived from spec.name (lowercased, separators collapsed to -).
Lists the persisted model-fusion composites (fusion.list). Pass ?include_invalid=true to also receive the entries that failed validation as a TOP-LEVEL invalid array beside items (each with the failure reason and its stable raw-file index; never mixed into or paginated with the selectable items) so a broken composite is editable or deletable. Composites are process-wide config with no realm dimension, so a per-request realm header returns 400 realm_scope_unsupported.
When true, also return composites that failed validation as a top-level invalid array beside items (each with a reason + raw-file index) so a broken composite is editable/deletable.
page
query
integer
No
1-based page number for pagination.
limit
query
integer
No
Maximum items per page (0 = no pagination).
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; createTodo 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 (HoodyPaths).
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.
Creates or updates a model-fusion composite keyed by slug (fusion.upsert). The body is the daemon FusionSpec under spec. The persisted key is derived from spec.name (lowercased, separators collapsed to -); the path {slug} must normalize to the same slug or the request is rejected 400 slug_mismatch — the path cannot rename what the body describes. Structural invariants (name, method, members, cycle guard, non-zero context window) are validated server-side.
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; createTodo 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 (HoodyPaths).
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.
"message":"path slug \"foo\" does not match spec.name \"bar\" (slug \"bar\")"
}
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.
slug_mismatch
Path slug does not match spec.name
The path {slug} and the slug derived from body spec.name normalize to different values; the daemon persists by the spec.name-derived slug, so honoring the request would write a composite the URL does not name.
Use the spec.name-derived slug in the path (lowercase, separators collapsed to -), or change spec.name.
{
"code":"forbidden",
"message":"request must arrive through the Hoody proxy"
}
Error Code
Title
Description
Resolution
forbidden
Forbidden (not via the Hoody proxy)
The request did not reach the service through the public endpoint.
Reach the agent through hoody-proxy (e.g. hoody agent … → platform → proxy), not by connecting to the container directly.
{
"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 — 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).
Removes a model-fusion composite by slug (fusion.delete). Composites are process-wide config with no realm dimension, so a per-request realm header returns 400 realm_scope_unsupported.
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; createTodo 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 (HoodyPaths).
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.