Skip to content
Hoody.com

The Tool endpoints expose the agent’s tool catalogue, surface a live session’s effective tool set, and let you execute a tool synchronously, asynchronously, or as a Server-Sent Events stream. Use these endpoints when you need to introspect what tools are available to an agent, inspect a single tool’s JSON-Schema input, or invoke a tool directly — either against an open session (with full gating against the session’s frozen scope) or sessionlessly (with the gateway creating an ephemeral session from per-request scope headers).

All endpoints in this group go through the container-scoped agent endpoint and must be reached through hoody-proxy.


Lists the agent’s built-in tool schemas (name, description, JSON-Schema input, read_only flag). Pagination: pass ?page=N&limit=M for a window; omit limit for the full set.

NameInTypeRequiredDescription
pagequeryintegerNo1-based page number for pagination.
limitqueryintegerNoMaximum items per page (0 = no pagination).
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on this route.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on this route.
{
"items": [
{
"name": "read_file",
"description": "Read the contents of a file under the current directory scope.",
"read_only": true,
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string" }
},
"required": ["path"]
}
},
{
"name": "bash",
"description": "Execute a shell command under the session's tool mode.",
"read_only": false,
"input_schema": {
"type": "object",
"properties": {
"cmd": { "type": "string" },
"cwd": { "type": "string" }
},
"required": ["cmd"]
}
}
],
"meta": {
"total": 42,
"page": 1,
"limit": 50
}
}
await client.agent.tools.listToolsIterator({ page: 1, limit: 50 });
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/tools?page=1&limit=50" \
-H "X-Hoody-Cwd: /home/user/project"

Returns the schema for a single built-in tool by name. Returns 404 tool_not_found for an unknown name.

NameInTypeRequiredDescription
namepathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on this route.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on this route.
{
"name": "bash",
"description": "Execute a shell command under the session's tool mode.",
"read_only": false,
"input_schema": {
"type": "object",
"properties": {
"cmd": { "type": "string", "description": "Shell command line to execute." },
"cwd": { "type": "string", "description": "Working directory; defaults to the session cwd." },
"timeout_ms": { "type": "integer", "description": "Execution timeout in milliseconds." }
},
"required": ["cmd"]
}
}
await client.agent.tools.getTool("bash");
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/tools/bash" \
-H "X-Hoody-Cwd: /home/user/project"

Lists the read-only tools — those safe for planning and sessionless runs. Pagination is honored.

NameInTypeRequiredDescription
pagequeryintegerNo1-based page number for pagination.
limitqueryintegerNoMaximum items per page (0 = no pagination).
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on this route.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on this route.
{
"items": [
{
"name": "read_file",
"description": "Read the contents of a file under the current directory scope.",
"read_only": true,
"input_schema": {
"type": "object",
"properties": { "path": { "type": "string" } },
"required": ["path"]
}
},
{
"name": "list_dir",
"description": "List a directory under the current directory scope.",
"read_only": true,
"input_schema": {
"type": "object",
"properties": { "path": { "type": "string" } }
}
}
],
"meta": {
"total": 18,
"page": 1,
"limit": 50
}
}
await client.agent.tools.listReadOnlyToolsIterator({ page: 1, limit: 50 });
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/tools/read-only?page=1&limit=50" \
-H "X-Hoody-Cwd: /home/user/project"

Returns the complete effective tool set for a live session — tools that are config-enabled and on PATH, gated by the session’s tool mode / agent allowlist / headless exclusions. Returns 404 when the session is not live.

NameInTypeRequiredDescription
idpathstringYesSession identifier.
pagequeryintegerNo1-based page number for pagination.
limitqueryintegerNoMaximum items per page (0 = no pagination).
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only routes.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on active-only routes.
{
"items": [
{
"name": "read_file",
"description": "Read the contents of a file under the current directory scope.",
"read_only": true,
"input_schema": {
"type": "object",
"properties": { "path": { "type": "string" } },
"required": ["path"]
}
},
{
"name": "write_file",
"description": "Write content to a file under the current directory scope.",
"read_only": false,
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string" },
"content": { "type": "string" }
},
"required": ["path", "content"]
}
}
],
"meta": {
"total": 24,
"page": 1,
"limit": 50
}
}
await client.agent.tools.listSessionToolsIterator("sess_01HMZ8XJ5K7Y9P3Q4R6T8V0WAB", {
page: 1,
limit: 50,
});
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/sessions/sess_01HMZ8XJ5K7Y9P3Q4R6T8V0WAB/tools?page=1&limit=50" \
-H "X-Hoody-Cwd: /home/user/project"

Returns the MCP (mcp__*) tools available in a live session, drawn from the same computeTools snapshot. Returns 404 when the session is not live.

NameInTypeRequiredDescription
idpathstringYesSession identifier.
pagequeryintegerNo1-based page number for pagination.
limitqueryintegerNoMaximum items per page (0 = no pagination).
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only routes.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on active-only routes.
{
"items": [
{
"name": "mcp__filesystem__read",
"description": "Read a file via the filesystem MCP server.",
"read_only": true,
"input_schema": {
"type": "object",
"properties": { "path": { "type": "string" } },
"required": ["path"]
}
},
{
"name": "mcp__github__list_issues",
"description": "List issues from a GitHub repository.",
"read_only": true,
"input_schema": {
"type": "object",
"properties": {
"owner": { "type": "string" },
"repo": { "type": "string" }
},
"required": ["owner", "repo"]
}
}
],
"meta": {
"total": 6,
"page": 1,
"limit": 50
}
}
await client.agent.tools.listSessionMCPToolsIterator("sess_01HMZ8XJ5K7Y9P3Q4R6T8V0WAB", {
page: 1,
limit: 50,
});
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/sessions/sess_01HMZ8XJ5K7Y9P3Q4R6T8V0WAB/tools/mcp?page=1&limit=50" \
-H "X-Hoody-Cwd: /home/user/project"

Runs a tool through the single gated policy gate with no open session: the gateway creates an ephemeral local session from the scope headers (X-Hoody-Cwd / X-Hoody-Config-Dir) and runs the full permission checks. Sessionless runs are read-only by default — a non-read-only tool requires allow_mutations:true or confirm:true (else 400 tool_mutation_refused). A parked confirmation returns 409 tool_needs_confirmation with the echoed tool+params; re-issue with confirm:true.

NameInTypeRequiredDescription
namepathstringYesPath identifier (the tool name).
confirmquerybooleanNoQuery alias of the body confirm field — re-issue a previously-parked confirmation (pair with confirm_token).
confirm_tokenquerystringNoQuery alias of the body confirm_token field — the single-use token returned in the 409 tool_needs_confirmation details.
X-Hoody-Tool-ModeheaderstringNoSessionless tool-mode for the ephemeral session (e.g. read_only / full); default per the daemon.
X-Hoody-Dir-ScopeheaderstringNoSessionless directory-access scope for the ephemeral session (e.g. home / full); default home.
X-Hoody-CwdheaderstringNoPer-request working-directory scope (the ephemeral session resolves paths under this subtree).
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only routes.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on active-only routes.
FieldTypeRequiredDescription
paramsobjectNoThe tool’s input parameters (its JSON-Schema body).
confirmbooleanNoRe-issue a previously-parked confirmation. MUST be paired with confirm_token from the prior 409.
confirm_tokenstringNoThe single-use token returned in the 409 tool_needs_confirmation details.
allow_mutationsbooleanNoSessionless only: opt a non-read-only tool into running under the full permission checks (else a sessionless mutating run is refused 400 tool_mutation_refused).

Caller-supplied confirmed/_-prefixed control keys are ignored — they are never trusted from the wire.

{
"params": {
"cmd": "ls -la /home/user/project",
"timeout_ms": 5000
},
"allow_mutations": false
}
{
"tool": "bash",
"is_error": false,
"content": [
{
"type": "text",
"text": "total 48\ndrwxr-xr-x 6 user user 4096 May 12 09:14 .\ndrwxr-xr-x 18 user user 4096 May 12 09:14 ..\n-rw-r--r-- 1 user user 2204 May 12 09:14 README.md\ndrwxr-xr-x 3 user user 4096 May 12 09:14 src\n"
}
]
}
await client.agent.tools.runTool("bash", {
params: { cmd: "ls -la /home/user/project", timeout_ms: 5000 },
allow_mutations: false,
});
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/tools/bash/run" \
-H "Content-Type: application/json" \
-H "X-Hoody-Cwd: /home/user/project" \
-H "X-Hoody-Tool-Mode: read_only" \
-d '{
"params": { "cmd": "ls -la /home/user/project", "timeout_ms": 5000 },
"allow_mutations": false
}'

Async form of runTool: returns {job_id} immediately and runs the gated tool in the background. Poll GET /jobs/{id} or GET /jobs/{id}/result for the result, a parked confirmation, or an execution error. A non-read-only sessionless run still requires an explicit posture.

NameInTypeRequiredDescription
namepathstringYesPath identifier (the tool name).
confirmquerybooleanNoQuery alias of the body confirm field — re-issue a previously-parked confirmation (pair with confirm_token).
confirm_tokenquerystringNoQuery alias of the body confirm_token field — the single-use token returned in the 409 tool_needs_confirmation details.
X-Hoody-Tool-ModeheaderstringNoSessionless tool-mode for the ephemeral session (e.g. read_only / full); default per the daemon.
X-Hoody-Dir-ScopeheaderstringNoSessionless directory-access scope for the ephemeral session (e.g. home / full); default home.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only routes.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on active-only routes.
FieldTypeRequiredDescription
paramsobjectNoThe tool’s input parameters (its JSON-Schema body).
confirmbooleanNoRe-issue a previously-parked confirmation. MUST be paired with confirm_token from the prior 409.
confirm_tokenstringNoThe single-use token returned in the 409 tool_needs_confirmation details.
allow_mutationsbooleanNoSessionless only: opt a non-read-only tool into running under the full permission checks.
{
"params": {
"cmd": "find /home/user/project -name '*.ts' -newer /tmp/marker",
"timeout_ms": 30000
},
"allow_mutations": false
}
{
"job_id": "job_01HN5K7Y9P3Q4R6T8V0WAB"
}

Submit the run:

const { job_id } = await client.agent.tools.runToolAsync("bash", {
params: { cmd: "find /home/user/project -name '*.ts' -newer /tmp/marker", timeout_ms: 30000 },
allow_mutations: false,
});

Fetch the result via client.agent.jobs.getJobResult:

const result = await client.agent.jobs.getJobResult({ id: job_id });
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/tools/bash/runAsync" \
-H "Content-Type: application/json" \
-H "X-Hoody-Cwd: /home/user/project" \
-H "X-Hoody-Tool-Mode: read_only" \
-d '{
"params": { "cmd": "find /home/user/project -name \u0027*.ts\u0027 -newer /tmp/marker", "timeout_ms": 30000 },
"allow_mutations": false
}'

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.

NameInTypeRequiredDescription
namepathstringYesPath identifier (the tool name).
confirmquerybooleanNoQuery alias of the body confirm field — re-issue a previously-parked confirmation (pair with confirm_token).
confirm_tokenquerystringNoQuery alias of the body confirm_token field — the single-use token returned in the 409 tool_needs_confirmation details.
X-Hoody-Tool-ModeheaderstringNoSessionless tool-mode for the ephemeral session (e.g. read_only / full); default per the daemon.
X-Hoody-Dir-ScopeheaderstringNoSessionless directory-access scope for the ephemeral session (e.g. home / full); default home.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only routes.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on active-only routes.
FieldTypeRequiredDescription
paramsobjectNoThe tool’s input parameters (its JSON-Schema body).
confirmbooleanNoRe-issue a previously-parked confirmation. MUST be paired with confirm_token from the prior 409.
confirm_tokenstringNoThe single-use token returned in the 409 tool_needs_confirmation details.
allow_mutationsbooleanNoSessionless only: opt a non-read-only tool into running under the full permission checks.
{
"params": {
"cmd": "wc -l /home/user/project/src/**/*.ts",
"timeout_ms": 10000
},
"allow_mutations": false
}
event: start
data: {"tool":"bash","started_at":"2026-05-12T09:14:02.114Z"}
event: result
data: {"tool":"bash","is_error":false,"content":[{"type":"text","text":" 142 src/cli.ts\n 88 src/agent.ts\n 214 src/router.ts\n"}]}
event: end
data: {"tool":"bash","finished_at":"2026-05-12T09:14:02.487Z"}
for await (const frame of client.agent.tools.streamTool("bash", {
params: { cmd: "wc -l /home/user/project/src/**/*.ts", timeout_ms: 10000 },
allow_mutations: false,
})) {
// frame.event ∈ {"start", "result", "needs_confirmation", "error", "end"}
}
Terminal window
curl -N -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/tools/bash/stream" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-H "X-Hoody-Cwd: /home/user/project" \
-H "X-Hoody-Tool-Mode: read_only" \
-d '{
"params": { "cmd": "wc -l /home/user/project/src/**/*.ts", "timeout_ms": 10000 },
"allow_mutations": false
}'

POST /api/v1/agent/sessions/{id}/tools/{name}/run

Section titled “POST /api/v1/agent/sessions/{id}/tools/{name}/run”

Runs a tool through the gated policy gate on a live session, against the session’s frozen realm/container/cwd/tool-mode/dir-scope, with the full permission checks. 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 params; re-issue with confirm:true. Returns 404 tool_not_found when the tool is not in the session’s effective tool list.

NameInTypeRequiredDescription
idpathstringYesSession identifier.
namepathstringYesPath identifier (the tool name).
confirmquerybooleanNoQuery alias of the body confirm field — re-issue a previously-parked confirmation (pair with confirm_token).
confirm_tokenquerystringNoQuery alias of the body confirm_token field — the single-use token returned in the 409 tool_needs_confirmation details.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only routes.
realmquerystringNoPer-request realm selector — the in:query alias of X-Hoody-Realm. Rejected (400 realm_scope_unsupported) on active-only routes.
FieldTypeRequiredDescription
paramsobjectNoThe tool’s input parameters (its JSON-Schema body).
confirmbooleanNoRe-issue a previously-parked confirmation. MUST be paired with confirm_token from the prior 409.
confirm_tokenstringNoThe single-use token returned in the 409 tool_needs_confirmation details.
allow_mutationsbooleanNoSessionless only: opt a non-read-only tool into running under the full permission checks (no effect on the in-session run, which inherits the session’s frozen scope).

Caller-supplied confirmed/_-prefixed control keys are ignored — they are never trusted from the wire.

{
"params": {
"path": "/home/user/project/src/agent.ts",
"max_lines": 200
}
}
{
"tool": "read_file",
"is_error": false,
"content": [
{
"type": "text",
"text": "import { createAgent } from \"./create.js\";\nexport const agent = createAgent({\n model: \"hoody-1\",\n tools: [\"read_file\", \"write_file\", \"bash\"],\n});\n"
}
]
}
await client.agent.tools.runSessionTool("sess_01HMZ8XJ5K7Y9P3Q4R6T8V0WAB", "read_file", {
params: { path: "/home/user/project/src/agent.ts", max_lines: 200 },
});
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.icu/api/v1/agent/sessions/sess_01HMZ8XJ5K7Y9P3Q4R6T8V0WAB/tools/read_file/run" \
-H "Content-Type: application/json" \
-H "X-Hoody-Cwd: /home/user/project" \
-d '{
"params": { "path": "/home/user/project/src/agent.ts", "max_lines": 200 }
}'