Agent: Chat Agents
Section titled “Agent: Chat Agents”These endpoints manage chat-agent definitions: the on-disk markdown files that combine a frontmatter (model, tools, max-turns) with a system prompt. Use them to list the files that shape agent behavior, enumerate definitions, read and write each agent’s source, create, copy, rename, and delete agents, and adjust per-field frontmatter settings. Every operation accepts an X-Hoody-Realm header (or ?realm= query) to name the realm the request resolves in; omitted, the request resolves to the agent’s own realm. Edits take effect on the agent’s next turn with no restart.
Inspect
Section titled “Inspect”GET /api/v1/agent/agent-files
Section titled “GET /api/v1/agent/agent-files”List the files that shape the agents’ behavior in the requesting cwd/config_dir scope, each with its absolute path on the agent’s machine. Rows, in order: the chat-agent definitions (the configured default chat agent first, marked chief), the skills (SKILL.md), the instruction files (CLAUDE.md per layer and the project’s AGENTS.md), and the workflow prompt files (prompts/**/*.md). Shadowed definitions are left out. Every listed file exists, except a shipped default agent with no file yet (see editable). Built-in hoody-* skills are listed with editable: false (they are reserved, rewritten at every agent start); write your own skill and name it in an agent’s skills: list instead. editable is also false for a shipped default agent the realm has no file for yet, with the path showing where a save through putAgentSource would create it. An edit made on disk applies at the agent’s next turn (applies: next_turn), with no restart and no new session. An external editor writes the file directly; a save takes no revision, so a save overwrites a concurrent change made through putAgentSource, putSkillSource, or the agent’s own tools (last writer wins). settings.json is not listed.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
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 against. |
X-Hoody-Realm | header | string | No | Per-request realm selector: "global" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request
Section titled “Request”curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agent-files?page=1&limit=20" \ -H "X-Hoody-Cwd: /home/user/project" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
for await (const file of client.agent.files.listIterator({ page: 1, limit: 20 })) { console.log(file);}Response
Section titled “Response”{ "items": [ { "id": "instructions:project:AGENTS.md", "kind": "instructions", "name": "AGENTS.md", "path": "/home/user/project/AGENTS.md", "layer": "project", "exists": true, "editable": true, "applies": "next_turn" } ], "meta": { "total": 1 }}| Field | Type | Required | Description |
|---|---|---|---|
items | array | Yes | The page of agent files, in the order described above. |
items[].id | string | Yes | Stable row key: the kind, then the layer or skill root, then the name. Unique in the list. |
items[].kind | string | Yes | One of agent, skill, instructions, workflow_prompt. |
items[].name | string | Yes | The agent name, the skill name, the file name, or the path under prompts/. |
items[].path | string | Yes | The absolute path of the file on the agent’s machine. |
items[].layer | string | Yes | One of user, project, config, shipped. |
items[].exists | boolean | Yes | Whether the file exists. false only for a shipped default agent with no file in this realm yet. |
items[].editable | boolean | Yes | Whether an edit on disk is kept and applies. false with a reason for a shipped default with no file yet and for a built-in skill. |
items[].reserved | boolean | No | A built-in hoody-* skill the agent rewrites at every start. Omitted when false. |
items[].reason | string | No | Why the file is not editable. Omitted when it is. |
items[].applies | string | Yes | When an edit on disk takes effect: next_turn (the agent’s next turn in every session, with no restart). |
items[].chief | boolean | No | The configured default chat agent. Omitted when false. |
meta | object | Yes | Pagination metadata. |
meta.total | integer | No | Total number of items across all pages. |
meta.page | integer | No | 1-based page number (present only when limit > 0). |
meta.limit | integer | No | Items per page (present only when limit > 0). |
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "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": "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. |
GET /api/v1/agent/agents
Section titled “GET /api/v1/agent/agents”List the chat-agent definitions resolved for the requesting cwd/config_dir (built-in + custom), sorted by name. Definition files whose stem is not a valid agent name (lowercase letters, digits, - and _, starting with a letter or digit) are left out. Each entry carries the file path, the parsed frontmatter (model, tools, max_turns, effort, labels, MCP tools, skills), the full system prompt, and advisory flags: shadows_lower, unknown_tools, unknown_skills, missing_vs_default, name_mismatch, duplicate_name. The configured default chat agent for the scope is marked is_configured_default.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
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 against. |
X-Hoody-Realm | header | string | No | Per-request realm selector: "global" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request
Section titled “Request”curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents?page=1&limit=20" \ -H "X-Hoody-Cwd: /home/user/project" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
for await (const agent of client.agent.definitions.listIterator({ page: 1, limit: 20 })) { console.log(agent);}Response
Section titled “Response”{ "items": [ { "name": "researcher", "description": "Web-focused research agent.", "path": "/srv/team-config/agents/researcher.md", "provenance": "user", "model": "anthropic/claude-sonnet-4-6", "labels": ["research"], "effort": "medium", "tools": ["web_search", "web_fetch", "read_file"], "prompt_preview": "You research questions on the web and cite sources.", "prompt": "You research questions on the web and cite sources.", "spawn_advertised": true, "realm": "global" } ], "meta": { "total": 1 }}| Field | Type | Required | Description |
|---|---|---|---|
items | array | Yes | The page of agent definitions, sorted by name. |
items[].name | string | Yes | The agent’s name (the definition file’s stem). Unique in the list. |
items[].frontmatter_name | string | No | The frontmatter name, present only when it differs from name. |
items[].description | string | No | The agent’s description. Omitted when empty. |
items[].path | string | Yes | The definition file. Empty for a shipped default the realm has no file for. |
items[].provenance | string | Yes | One of user, project, user (shipped default), shipped default (embedded), product-owned (read-only). |
items[].shadows_lower | boolean | No | true when this file overrides a same-named file in a lower layer. Omitted when false. |
items[].model | string | No | The agent’s model. Omitted when it inherits the session model. |
items[].labels | array of string | No | Organizational labels. Omitted when none. |
items[].effort | string | No | Reasoning effort from the frontmatter. Omitted when unset. |
items[].max_turns | integer | No | Turn cap from the frontmatter. Omitted when unset. |
items[].tools | array of string | No | The tools list. Omitted when absent, which means every tool unless strict_tools. |
items[].strict_tools | boolean | No | The agent gets exactly its tools list. Omitted when false. |
items[].mcp_tools | array of string | No | The MCP tools the agent gets, each server/tool or server/*; an empty array means none. Omitted when the frontmatter has no mcp_tools key. |
items[].skills | array of string | No | The skills the agent gets; an empty array means none. Omitted when the frontmatter has no skills key: then the chat agent gets every enabled skill and a spawned agent none. |
items[].compaction_max_tokens | integer | No | Prompt tokens at which the agent’s automatic compaction starts, as the chat agent, when that is lower than the box’s threshold. Omitted when unset. |
items[].unknown_tools | array of string | No | Entries of tools that are not built-in tools (advisory). Omitted when none. |
items[].unknown_skills | array of string | No | Entries of skills that name no installed skill in this scope (advisory). Omitted when none. |
items[].missing_vs_default | array of string | No | Tools the shipped default of the same name has and this file lacks (advisory). Omitted when none. |
items[].name_mismatch | boolean | No | The frontmatter name differs from the file stem. Omitted when false. |
items[].duplicate_name | boolean | No | Another listed file has the same frontmatter name. Omitted when false. |
items[].is_configured_default | boolean | No | The configured default chat agent for this scope. Omitted when false. |
items[].spawn_advertised | boolean | Yes | Whether spawn_agent’s menu lists the agent; a hidden agent is still spawnable by name. |
items[].prompt_preview | string | No | The system prompt’s first six non-empty lines. Omitted when the prompt is empty. |
items[].prompt | string | No | The full system prompt. Omitted when empty. |
items[].realm | string | Yes | The agent definition’s realm: "global" for one not tied to a realm, else its 24-hex realm id. Pass it as X-Hoody-Realm (or ?realm=) to reach it by id. |
meta | object | Yes | Pagination metadata. |
meta.total | integer | No | Total number of items across all pages. |
meta.page | integer | No | 1-based page number (present only when limit > 0). |
meta.limit | integer | No | Items per page (present only when limit > 0). |
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "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": "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. |
GET /api/v1/agent/agents/{name}/source
Section titled “GET /api/v1/agent/agents/{name}/source”Read the raw markdown source of a chat-agent definition. The response carries {path, content, revision}. For the product-owned bot agent the content is the definition it runs with: the shipped source with the model pinned in the file at path. Send revision as putAgentSource’s expected_revision to save only if nobody changed the agent since this read. An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request
Section titled “Request”curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/source" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const source = await client.agent.definitions.getSource('researcher');console.log(source);Response
Section titled “Response”{ "path": "/srv/team-config/agents/researcher.md", "content": "---\nmodel: anthropic/claude-sonnet-4-6\ndescription: Web-focused research agent.\ntools: web_search, read_file\nmax_turns: 12\n---\n\nYou are a research assistant. Cite sources for every claim.", "revision": "rev_01HMRESEARCHER42"}{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "agent not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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. |
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": "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. |
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. |
Create, copy, rename
Section titled “Create, copy, rename”POST /api/v1/agent/agents
Section titled “POST /api/v1/agent/agents”Create a new custom chat-agent definition file from a name, optional frontmatter, and optional system prompt. The name must be unused: creating over an existing agent is refused and the existing definition is left untouched. To replace an existing agent, use putAgentSource instead. The bot agent is product-owned: creating it is refused with 400 bad_request; only its model can be pinned (setAgentModel).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Agent name (the definition file stem). Must be a valid agent name and not in use. |
frontmatter | object | No | Optional frontmatter object. See the keys below. |
system_prompt | string | No | The agent’s system prompt body. |
frontmatter keys
Section titled “frontmatter keys”| Field | Type | Required | Description |
|---|---|---|---|
description | string | No | One-line description of the agent. |
model | string | No | A provider/model spec or a fusion/<slug> composite. |
tools | array of string | No | Built-in tool names the agent gets. |
effort | enum (adaptive, low, medium, high, max) | No | Reasoning level. |
max_turns | integer | No | Turn cap, at least 1. |
max_steps_per_turn | integer | No | The most model requests one chat turn of this agent may make. A turn that reaches it stops with error_code max_steps, and the next message continues. It applies to the agent’s own chat turns, not to it as a helper or workflow step, and not to a Claude Code session. Omit for no limit. |
labels | array of string | No | Grouping labels; no commas or newlines. |
strict_tools | boolean | No | true gives the agent exactly its tools list. |
mcp_tools | array of string | No | MCP tools the agent gets: server/tool, server/*, or mcp__server__tool; an empty array means none. |
skills | array of string | No | Skill names the agent gets; an empty array means none. Left out: every enabled skill as the chat agent, none as a spawned agent. |
prompt_blocks | object | No | Block name to boolean; false drops that optional system-prompt block. |
ask_timeout | string or integer | No | A duration such as "10m" or a number of seconds, more than zero and at most 24h. |
thinking | enum (enabled, disabled) | No | Turn reasoning on or off. |
temperature | number | No | Sampling temperature, 0 to 2. |
response_format | enum (json_object) | No | Ask for a JSON object reply. |
compaction | enum (same_prefix) | No | same_prefix: a compaction resends the session’s own system prompt, tools and transcript so it reuses the prompt cache. Fusion models use the default compaction. Omit for the default compaction. |
compaction_max_tokens | integer | No | Prompt tokens at which the agent’s automatic compaction starts, as the chat agent, when that is lower than the box’s threshold. Omit to use the threshold alone. |
Any other frontmatter key is rejected. strict_tools: true gives the agent exactly its tools list: no skill or workflow tool is added, no MCP tool unless mcp_tools names it, and a call to any other tool is refused. With no tools list it gets only ask_question_to_user, todo_read, todo_write, task_output, list_tasks, and bash_job_wait. prompt_blocks names: contract, transcripts, frequent_files, hook_context, memory, project_instructions, agent_instructions, team_rules, skills, workflows, verbosity, hoody_platform, hoody_exec, fleet_notice. ask_timeout defaults to 15 minutes. thinking disabled together with an effort is rejected.
Request
Section titled “Request”curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -d '{ "name": "researcher", "frontmatter": { "description": "Web-focused research agent.", "model": "anthropic/claude-sonnet-4-6", "tools": ["web_search", "read_file"], "max_turns": 12 }, "system_prompt": "You are a research assistant. Cite sources for every claim." }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.create({ name: 'researcher', frontmatter: { description: 'Web-focused research agent.', model: 'anthropic/claude-sonnet-4-6', tools: ['web_search', 'read_file'], max_turns: 12, }, system_prompt: 'You are a research assistant. Cite sources for every claim.',});Response
Section titled “Response”{}The response is a JSON object whose shape is passed through verbatim from the operation.
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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; 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": "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. |
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. |
POST /api/v1/agent/agents/{name}/copy
Section titled “POST /api/v1/agent/agents/{name}/copy”Copy a chat-agent definition to a new name. The source {name} comes from the path; the destination is given in the body as new_name. A copy of the product-owned bot agent takes the definition it runs with; copying onto its name is refused with 400 bad_request. An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The source agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
new_name | string | Yes | Name for the copied agent. Must be unused. |
Request
Section titled “Request”curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/copy" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -d '{ "new_name": "researcher-v2" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.copy('researcher', { new_name: 'researcher-v2' });Response
Section titled “Response”{}The response is a JSON object whose shape is passed through verbatim from the operation.
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "agent not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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. |
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": "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. |
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. |
POST /api/v1/agent/agents/{name}/rename
Section titled “POST /api/v1/agent/agents/{name}/rename”Rename a custom chat-agent definition. The current {name} comes from the path; the new name is given in the body as new_name. Renaming the product-owned bot agent, or to its name, is refused with 400 bad_request. An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The current agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
new_name | string | Yes | New agent name. Must be unused. |
Request
Section titled “Request”curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/rename" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -d '{ "new_name": "researcher-v2" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.rename('researcher', { new_name: 'researcher-v2' });Response
Section titled “Response”{}The response is a JSON object whose shape is passed through verbatim from the operation.
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "agent not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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. |
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": "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. |
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. |
Edit source and frontmatter
Section titled “Edit source and frontmatter”PUT /api/v1/agent/agents/{name}/source
Section titled “PUT /api/v1/agent/agents/{name}/source”Overwrite the raw markdown source of a chat-agent definition and return {path, revision}. With expected_revision (the revision returned by getAgentSource) the save is refused with a 409 revision_conflict and nothing is written when the source changed since that read: another tab, a model, tools, or turns edit, a hand edit, or a copy in a different realm or layer now resolving. The revision is bound to the realm this request resolves to, so on a gateway without a realm pin, a revision read while another realm was active is also refused 409, never written into the other realm. details.current_revision carries the current value. Without expected_revision the save is unconditional. The bot agent is product-owned: this is refused for it with 400 bad_request; only its model can be pinned (setAgentModel). An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | The full markdown source (frontmatter + system prompt). Frontmatter is read as one key: value per line: a tools: line must be a comma-separated list on that same line, because a YAML block list underneath it parses to NOTHING and the agent is then granted every tool, the opposite of the restriction it looks like. The turn cap is spelled max_turns; a turns line is ignored. |
expected_revision | string | No | The revision getAgentSource returned. A save whose source changed since is refused 409 revision_conflict (details.current_revision) and writes nothing. Omit to save unconditionally. The revision is bound to the realm this request resolves to: on a gateway without a realm pin, a revision read while another realm was active is refused 409 revision_conflict (details.current_revision is this realm’s), never written into the other realm. |
Request
Section titled “Request”curl -X PUT "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/source" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -d '{ "content": "---\nmodel: anthropic/claude-sonnet-4-6\ndescription: Web-focused research agent.\ntools: web_search, read_file\nmax_turns: 12\n---\n\nYou are a research assistant. Cite sources for every claim.", "expected_revision": "rev_01HMRESEARCHER42" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.setSource('researcher', { content: '---\nmodel: anthropic/claude-sonnet-4-6\ndescription: Web-focused research agent.\ntools: web_search, read_file\nmax_turns: 12\n---\n\nYou are a research assistant. Cite sources for every claim.', expected_revision: 'rev_01HMRESEARCHER42',});Response
Section titled “Response”{ "path": "/srv/team-config/agents/researcher.md", "revision": "rev_01HMRESEARCHER43"}{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "agent not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "code": "revision_conflict", "message": "the agent source changed since expected_revision was read; nothing was written"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
revision_conflict | Agent source revision conflict | The agent’s source changed since expected_revision was read (or now resolves to another file), so nothing was written. details.current_revision carries the current revision. | Re-read getAgentSource, re-apply the change and retry with its revision. |
{ "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. |
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": "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. |
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. |
PATCH /api/v1/agent/agents/{name}/model
Section titled “PATCH /api/v1/agent/agents/{name}/model”Set, or with model: "" remove, an agent’s frontmatter model line. For the product-owned bot agent this pin is the one part of its definition that can change; a Bot’s own model still wins over it. An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
model | string | No | Model spec (e.g. anthropic/claude-sonnet-4-6); "" removes the frontmatter model line. |
Request
Section titled “Request”curl -X PATCH "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/model" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -d '{ "model": "anthropic/claude-sonnet-4-6" }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.setModel('researcher', { model: 'anthropic/claude-sonnet-4-6' });Response
Section titled “Response”{}The response is a JSON object whose shape is passed through verbatim from the operation.
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "agent not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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. |
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": "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. |
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. |
PATCH /api/v1/agent/agents/{name}/tools
Section titled “PATCH /api/v1/agent/agents/{name}/tools”Set, or with an empty list remove, an agent’s frontmatter tools line. An empty list removes the line and the agent then has every tool. The bot agent is product-owned: this is refused for it with 400 bad_request; only its model can be pinned (setAgentModel). An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
tools | array of string | Yes | Tool names allowed for the agent; an empty list removes the line (every tool). |
Request
Section titled “Request”curl -X PATCH "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/tools" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -d '{ "tools": ["web_search", "read_file"] }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.setTools('researcher', { tools: ['web_search', 'read_file'] });Response
Section titled “Response”{}The response is a JSON object whose shape is passed through verbatim from the operation.
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "agent not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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. |
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": "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. |
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. |
PATCH /api/v1/agent/agents/{name}/turns
Section titled “PATCH /api/v1/agent/agents/{name}/turns”Set an agent’s max_turns frontmatter value. The bot agent is product-owned: this is refused for it with 400 bad_request; only its model can be pinned (setAgentModel). An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
turns | integer | No | Max agent turns per dispatch. |
Request
Section titled “Request”curl -X PATCH "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/turns" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -d '{ "turns": 20 }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.setTurnLimit('researcher', { turns: 20 });Response
Section titled “Response”{}The response is a JSON object whose shape is passed through verbatim from the operation.
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "agent not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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. |
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": "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. |
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. |
POST /api/v1/agent/agents/{name}/tools/{tool}/toggle
Section titled “POST /api/v1/agent/agents/{name}/tools/{tool}/toggle”Toggle one tool on or off in an agent’s frontmatter tools line. Each call flips the tool’s current state; there is no way to request a specific state. The body has no fields; the agent {name} and {tool} come from the path. The bot agent is product-owned: this is refused for it with 400 bad_request; only its model can be pinned (setAgentModel). An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The agent name. |
tool | path | string | Yes | The tool name to toggle. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request
Section titled “Request”curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/tools/web_search/toggle" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -d '{}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.toggleTool('researcher', 'web_search', {});Response
Section titled “Response”{}The response is a JSON object whose shape is passed through verbatim from the operation.
{ "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 scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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": "agent not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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. |
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": "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. |
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. |
Restore and remove
Section titled “Restore and remove”POST /api/v1/agent/agents/{name}/reset-to-shipped
Section titled “POST /api/v1/agent/agents/{name}/reset-to-shipped”Restore one agent to its shipped default, discarding local customizations. An agent with no shipped default is refused as is_error: true (the HTTP status stays 200). Access is decided by the container’s proxy permission policy. An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request
Section titled “Request”curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher/reset-to-shipped" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.reset('researcher');Response
Section titled “Response”{ "status": "ok", "output": "Reset researcher to shipped default.", "is_error": false}The 200 response is the gated tool-run envelope {status, output, is_error, ...} the gateway composes, not a daemon reply. A run that completed but failed the tool is still status: "ok"; read is_error. An agent with no shipped default is refused here as is_error, still under a 200.
| Field | Type | Required | Description |
|---|---|---|---|
status | string | No | "ok" once the run completed. A tool that ran and failed is still "ok", read is_error. |
output | string | No | The tool’s output. |
is_error | boolean | No | true when the tool itself failed. The HTTP status stays 200. |
error_code | string | No | Present on a typed tool failure. |
hint | string | No | Present when the tool suggested a recovery. |
hint_cmd | string | No | Present alongside hint: the suggested command. |
code | string | No | Present on a guarded write refused by its expected-revision check, and as not_found when a workflow or agent definition tool found no such definition. |
current_revision | string | No | Present alongside code: the revision the guarded write found. |
{ "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. |
tool_mutation_refused | Tool mutation refused | A sessionless tool run resolved to a mutating tool with no confirmation posture. Sessionless runs are read-only by default. | Open a session and run the tool there, or supply allow_mutations: true or confirm: true on the sessionless run. |
realm_scope_unsupported | Realm scope unsupported | A per-request scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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 |
|---|---|---|---|
realm_not_allowed | Realm not allowed for this login | The agent is logged in with a token limited to some realms (GET /hoody/auth/status lists them in realm_ids), and this session’s realm is not one of them, or is the global scope (a session restored from before the login, or a realm the login was narrowed away from). The session can still be read; nothing was run. | Continue in a session of a realm the login serves, or log the agent in with a token that covers this session’s realm. |
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": "tool_not_found", "message": "no tool with that name"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
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. |
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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": "restriction_unknown", "message": "the login's realm restriction could not be read (introspection failed) — retry, or log in again"}| 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 runs no work in any session until it can. Nothing was run. | Retry after the restriction is readable. |
DELETE /api/v1/agent/agents/{name}
Section titled “DELETE /api/v1/agent/agents/{name}”Delete one custom chat-agent definition. The answer is 200 with {output, is_error}; when the agent cannot be deleted, is_error is true and output says why. The agents that ship with Hoody and the default chat agent cannot be deleted: edit them with putAgentSource or restore them with resetAgentToShipped. In a realm that has its own copy of a shipped agent, deleting that copy brings the shipped agent back. The bot agent is shipped too, and only its model can be chosen: deleting a realm’s own copy removes that realm’s model choice; anywhere else, clear the model with setAgentModel and an empty model, or with resetAgentToShipped. Access is decided by the container’s proxy permission policy. An agent that does not exist is 404 not_found “agent not found”, and so is a realm this login does not serve.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | path | string | Yes | The agent name. |
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 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" (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
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" (not tied to a realm) or a 24-hex realm id. On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm. |
Request
Section titled “Request”curl -X DELETE "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/agents/researcher-v2" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.definitions.delete('researcher-v2');Response
Section titled “Response”{ "status": "ok", "output": "Deleted agent researcher-v2.", "is_error": false}The 200 response is the gated tool-run envelope {status, output, is_error, ...} the gateway composes, not a daemon reply. A run that completed but failed the tool is still status: "ok"; read is_error.
| Field | Type | Required | Description |
|---|---|---|---|
status | string | No | "ok" once the run completed. A tool that ran and failed is still "ok", read is_error. |
output | string | No | The tool’s output. |
is_error | boolean | No | true when the tool itself failed. The HTTP status stays 200. |
error_code | string | No | Present on a typed tool failure. |
hint | string | No | Present when the tool suggested a recovery. |
hint_cmd | string | No | Present alongside hint: the suggested command. |
code | string | No | Present on a guarded write refused by its expected-revision check, and as not_found when a workflow or agent definition tool found no such definition. |
current_revision | string | No | Present alongside code: the revision the guarded write found. |
{ "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. |
tool_mutation_refused | Tool mutation refused | A sessionless tool run resolved to a mutating tool with no confirmation posture. Sessionless runs are read-only by default. | Open a session and run the tool there, or supply allow_mutations: true or confirm: true on the sessionless run. |
realm_scope_unsupported | Realm scope unsupported | A per-request scope header this route does not take: a realm or container header on a route without that dimension, or, on an agent pinned to one realm, a different realm. | Omit the header, or name the realm the agent is pinned to. |
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 |
|---|---|---|---|
realm_not_allowed | Realm not allowed for this login | The agent is logged in with a token limited to some realms (GET /hoody/auth/status lists them in realm_ids), and this session’s realm is not one of them, or is the global scope (a session restored from before the login, or a realm the login was narrowed away from). The session can still be read; nothing was run. | Continue in a session of a realm the login serves, or log the agent in with a token that covers this session’s realm. |
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": "tool_not_found", "message": "no tool with that name"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
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. |
not_found | Not found | The agent does not exist, or the realm is not one this login serves. | Check the agent name and the realm. |
{ "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": "restriction_unknown", "message": "the login's realm restriction could not be read (introspection failed) — retry, or log in again"}| 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 runs no work in any session until it can. Nothing was run. | Retry after the restriction is readable. |