Persistent agent memory — read, write, search, and control the project memory store. These endpoints forward to the daemon’s memory.* RPCs, with active-realm-scoped reads and writes, daemon-paginated listings, and a daemon-side human-only gate on consolidation.
The HTTP edge has no service-level auth; hoody-proxy is the boundary (kit network-position trust). The daemon’s memAdminGate over the Unix socket may still return admin_unauthorized when a socket admin capability is configured.
Read a project’s memory relation graph. Returns a paginated page of memory.graph — nodes, edges, and stats. Filter via ?project=&node_type= and page via ?limit=&offset=. The daemon’s memAdminGate may still return admin_unauthorized when a socket admin capability is configured. Active-realm-scoped (a realm header is rejected). Returns 503 store_unavailable when the memory store is not warm.
Per-request working-directory scope (§6.1): the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-Dir
header
string
No
Per-request --config-dir override (§6.1) selecting which on-disk .hoody install a stateless read/write resolves.
X-Hoody-Container
header
string
No
Per-request bound remote container (§6.1; omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-Realm
header
string
No
Per-request realm selector (§6.1): 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 (§6.1) — the in:query alias of X-Hoody-Realm (read only when the header is absent).
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
The daemon’s Unix-socket memAdminGate / systemAdminGate refused the request. The daemon retains its own socket-side admin gate; when an admin capability is configured without a matching forwarded admin_token, the daemon refuses.
Run the daemon with socket auth (--auth-token-path) and no separate admin capability; 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 arrive through hoody-proxy; its source IP is private/local. Authorization is owned by hoody-proxy, which is the only party that can reach the gateway.
Reach the agent through hoody-proxy (e.g. hoody agent … → platform → proxy), not by connecting to the container directly.
{
"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": "store_unavailable",
"message": "memory store unavailable"
}
Error Code
Title
Description
Resolution
store_unavailable
Memory store unavailable
The memory store could not be opened (degraded remote host, not-warm realm store, divergent/corrupt local DB). The request fails closed rather than silently falling back.
Retry once the store is warm; if persistent, inspect the daemon logs for the degrade reason.
Lists memory records for a project (memory.list). Filter via ?project=&kind=&type=&query=. The listing is daemon-paginated: the daemon caps the page size at 200 and never returns an unbounded set. An omitted ?limit (or one over 200) pages at 200, not “no pagination” — the response always carries meta.page and meta.limit reflecting the effective page size. Active-realm-scoped: a realm header is rejected.
Reads one memory record by id (memory.detail). Pass ?project=&kind= to disambiguate. The daemon’s memAdminGate may still return admin_unauthorized when a socket admin capability is configured.
Lists the memory projects (memory.projects). The daemon’s memAdminGate may still return admin_unauthorized when a socket admin capability is configured. Active-realm-scoped: a realm header is rejected.
Hybrid recall across a project (memory.search): BM25 + vector + graph fusion. The query is privacy-stripped server-side before any tokenize/embed; the read is no-touch (it never strengthens future ranking). The daemon’s memAdminGate may still return admin_unauthorized when a socket admin capability is configured. Active-realm-scoped: a realm header is rejected. Returns 503 store_unavailable when the memory store is not warm.
"head": "Deploy to staging: 1) run migration 2) restart app 3) verify health",
"scores": {
"bm25": 0.82,
"vector": 0.91,
"graph": 0.45,
"fused": 0.87
}
},
{
"id": "mem_01HMZ3K9X8R7P2V4N6YTBJWQ5C",
"project": "hoody-platform",
"kind": "fact",
"type": "fact",
"head": "Staging URL is https://staging.hoody.dev",
"scores": {
"bm25": 0.55,
"vector": 0.78,
"graph": 0.30,
"fused": 0.61
}
}
]
}
{
"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.
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
The daemon’s memAdminGate refused the request.
Run the daemon with socket auth and no separate admin capability; or present the Memory-admin token for the interactive TUI.
forbidden
Forbidden (not via the Hoody proxy)
The request did not arrive through hoody-proxy.
Reach the agent through hoody-proxy.
{
"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, default 8 MiB). The gateway rejects an oversized body at the edge before the handler reads it.
Reduce the request body below the configured limit; 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.
Honor Retry-After 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": "store_unavailable",
"message": "memory store unavailable"
}
Error Code
Title
Description
Resolution
store_unavailable
Memory store unavailable
The memory store could not be opened.
Retry once the store is warm; if persistent, inspect the daemon logs.
Patches a memory record by id (memory.edit). The daemon’s memAdminGate may still return admin_unauthorized when a socket admin capability is configured.
Deletes a memory record (memory.delete). This is the cross-project delete — pass the identity in the body. The daemon’s memAdminGate may still return admin_unauthorized when a socket admin capability is configured.
Flips the memory privacy switch (memory.set_enabled) — persists features.memory and flips the live store. Not admin-gated. The body is {enabled: bool}.
Forces the memory store durability barrier (memory.flush). Not admin-gated. The request body is empty; the gateway scrubs every _-prefixed key and folds in the request scope (cwd/config_dir) before dispatch.
Requests a consolidation pass for a project (memory.consolidate). HUMAN-ONLY: consolidation spends multi-LLM passes and evolves memory state irreversibly, so an autonomous caller may never self-approve it. The gateway server-stamps the machine marker and the daemon’s human-only gate always refuses an HTTP call with 403 human_only (the HTTP edge has no service-level auth, but the human-only gate is a second, non-bypassable daemon factor).
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.
Omit the realm header on this route, or open a session to scope by realm.
{
"code": "human_only",
"message": "memory consolidation requires direct human confirmation and is not available to machine callers"
}
Error Code
Title
Description
Resolution
admin_unauthorized
Rejected by the daemon’s own admin gate
The daemon’s memAdminGate refused the request.
Run the daemon with socket auth and no separate admin capability; or present the Memory-admin token for the interactive TUI.
human_only
Human confirmation required
The operation requires direct human confirmation and is not available to machine callers — an autonomous caller may not self-approve it even with a valid admin token.
Trigger the operation from an interactive human session, not an autonomous/machine-confirmed dispatch.
forbidden
Forbidden (not via the Hoody proxy)
The request did not arrive through hoody-proxy.
Reach the agent through hoody-proxy.
{
"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, default 8 MiB).
Reduce the request body below the configured limit; 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.
Honor Retry-After 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": "consolidate_unavailable",
"message": "could not enqueue consolidation (queue full or memory disabled) — retry shortly"
}
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.
store_unavailable
Memory store unavailable
The memory store could not be opened.
Retry once the store is warm; if persistent, inspect the daemon logs.
consolidate_unavailable
Consolidation unavailable
The consolidation pass could not be enqueued (maintenance queue full or memory disabled). It is reported as retryable rather than as a silent success.