The Agent: Tools endpoints expose the agent’s tool catalogue, the effective tool set of a live session (including its MCP subset), and a single gated choke point for executing tools. Every execution path — sessionless sync, sessionless async, sessionless SSE, or inside a live session — funnels through the same gate chain (deny list, static-stakes, read-before-edit, dir-scope, write-permission, tool-membership). Use these endpoints to introspect what tools are available, then run them with an explicit confirmation posture when the gate requires it.
Lists the agent’s built-in tool schemas (name, description, JSON-Schema input, read_only flag). Catalogue-wide and realm-independent: a per-request realm header is rejected. Pass ?page=N&limit=M for a window; omit limit for the full set.
"description": "Read a UTF-8 text file from the workspace.",
"read_only": true,
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string" }
},
"required": ["path"]
}
},
{
"name": "bash",
"description": "Run a shell command in the workspace sandbox.",
"read_only": false,
"input_schema": {
"type": "object",
"properties": {
"command": { "type": "string" }
},
"required": ["command"]
}
}
],
"meta": {
"total": 42,
"page": 1,
"limit": 50
}
}
{
"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.
{
"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 arrive through hoody-proxy: its source IP is private/local. The gateway has no service-level auth — authorization is owned by hoody-proxy.
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.
Returns the schema for a single built-in tool by name. Returns 404 tool_not_found for an unknown name. Catalogue-wide and realm-independent: a per-request realm header is rejected.
Lists the read-only tools (safe for planning / sessionless runs). Catalogue-wide and realm-independent: a per-request realm header is rejected. Pagination honored.
Returns the complete effective tool set for a live session (computeTools = config-enabled AND on PATH, gated by the session’s tool mode / agent allowlist / headless exclusions). Returns 404 not_found when the session is not live.
Returns the MCP (mcp__*) tools available in a live session (drawn from the same computeTools snapshot). Returns 404 not_found when the session is not live.
These three routes share the same gate chain. They mint an ephemeral local session from the scope headers (X-Hoody-Cwd / X-Hoody-Config-Dir / X-Hoody-Tool-Mode / X-Hoody-Dir-Scope) and run executeToolDirect with the full gate chain (deny list / static-stakes / read-before-edit / dir-scope / write-permission / tool-membership). Sessionless runs are read-only by default — a non-read-only tool requires allow_mutations:true or confirm:true.
Runs a tool through the single gated choke point with no open session and returns the result inline. A parked confirmation returns 409 tool_needs_confirmation with the echoed tool + params; re-issue with confirm:true (and the confirm_token).
The tool’s input parameters (its JSON-Schema body).
confirm
boolean
No
Re-issue a previously-parked confirmation. MUST be paired with confirm_token; a bare confirm:true with no valid token does NOT bypass the gate.
confirm_token
string
No
The single-use token returned in the 409 tool_needs_confirmation details. Bound to the tool / session / params it was minted for.
allow_mutations
boolean
No
Sessionless only: opt a non-read-only tool into running under the full gate chain (else a sessionless mutating run is refused 400 tool_mutation_refused).
The tool was NOT executed: the gate chain (write-permission / dangerous-shape / outside-dir) requires confirmation first. The echoed tool + params let the caller re-issue the run with confirm:true.
Re-issue the run with confirm:true (or ?confirm=true), preserving the echoed params.
{
"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 before the handler reads it.
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.
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.
Async form of runTool: returns {job_id} immediately and runs the gated tool in the background. Poll GET /jobs/{id}/result for the result (or a parked confirmation). A non-read-only sessionless run still requires an explicit posture.
Streaming form of runTool over Server-Sent Events: a start frame, then a result / needs_confirmation / error frame, then end. The work is a one-shot gated RPC, so there is no per-token stream — the SSE shape mirrors the kit streaming convention for symmetry with the session stream. A non-read-only sessionless run still requires an explicit posture.
Runs a tool through the gated choke point on a live session. The gateway scrubs caller-supplied control keys and routes the run through executeToolDirect against the session’s frozen realm / container / cwd / tool-mode / dir-scope, with the full gate chain. It claims the session’s single serial turn slot so a direct tool run never races the turn loop (409 turn_in_flight if a turn is running; 409 gate_parked if a gate is parked). Because it occupies the turn slot it is also cancellable the same way a turn is: a concurrent POST /sessions/{id}/cancel (or a WS cancel frame, or session close) aborts the in-flight run. A parked confirmation returns 409 tool_needs_confirmation with the echoed tool + params; re-issue with confirm:true (and the confirm_token). Returns 404 tool_not_found when the tool is not in the session’s effective tool list.
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": "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 arrive through hoody-proxy.
Reach the agent through hoody-proxy, not by connecting to the container directly.
{
"code": "tool_not_found",
"message": "no tool with that name"
}
Error Code
Title
Description
Resolution
not_found
Not found
The requested resource does not exist.
Verify the path and identifier.
tool_not_found
Tool not found
No tool with the given name exists in the catalogue or in the session’s effective tool list.
List the catalogue (GET /tools) or the session’s tools (GET /sessions/{id}/tools) and use a valid name.
{
"code": "tool_needs_confirmation",
"message": "tool requires confirmation before execution"
}
Error Code
Title
Description
Resolution
tool_needs_confirmation
Tool needs confirmation
The tool was NOT executed: the gate chain (write-permission / dangerous-shape / outside-dir) requires confirmation first. The echoed tool + params let the caller re-issue the run with confirm:true.
Re-issue the run with confirm:true (or ?confirm=true), preserving the echoed params.
turn_in_flight
Turn in flight
A turn is already running on this session; the single serial turn slot is occupied, so a new turn / workflow run is refused.
Wait for the running turn to finish (observe agent_done on the session stream), then retry.
gate_parked
Gate parked
A confirm / question gate is parked on this session, so a new turn / workflow run is refused until it is answered. The parked gate is surfaced under details.pending_gate.
Answer the parked gate (/confirm or /answer) and retry; read it via GET /sessions/{id} or details.pending_gate.
{
"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 before the handler reads it.
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.
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.