Skip to content
Hoody.com

File, read, update, claim, run, snooze, and archive agent todos. Approve or deny run proposals, run an LLM triage pass over the inbox, and purge archived rows. Write operations are CAS-guarded by the per-todo revision (fetched from getTodo); the store-wide revision from getTodosRevision is a cheap poll cursor, not a CAS token.

The agent routes are scoped by the request’s working directory (the .hoody project layer / record cwd / tool+workflow cwd) via the X-Hoody-Cwd header (or a body cwd on create). Per-request realm scoping is rejected with realm_scope_unsupported on these routes.

Lists master todos for the requesting cwd/config_dir, with a store-wide revision poll cursor. Typed filters ride the request body — there is no query-param filter alias.

Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos?page=1&limit=25" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{"open_only": true, "tags": ["P0", "security"]}'
NameInTypeRequiredDescription
pagequeryintegerNo1-based page number for pagination.
limitqueryintegerNoMaximum items per page (0 = no pagination).
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local).
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias of X-Hoody-Realm). Rejected on this route.

Optional typed filters forwarded to todos.list. All fields are optional; omit the body for the full list.

NameTypeRequiredDescription
statesarray of stringNoFilter to these todo states.
tagsarray of stringNoFilter to todos carrying these tags.
querystringNoFree-text filter over title/body.
open_onlybooleanNoWhen true, only open (non-terminal) todos.
allbooleanNoWhen true, include archived/closed todos.
{
"items": [
{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"title": "Rotate staging TLS certs",
"body": "STAGING cluster certs expire in 14 days.",
"state": "open",
"priority": 1,
"tags": ["security", "P1"],
"revision": 7,
"created_at": "2026-01-04T09:00:00Z",
"updated_at": "2026-01-12T14:32:10Z"
},
{
"id": "todo_01HMZX8T2B6K1M5N7P9RWDEFGH",
"title": "Refactor billing idempotency keys",
"state": "in_progress",
"priority": 2,
"tags": ["billing"],
"revision": 3,
"created_at": "2026-01-05T11:20:00Z",
"updated_at": "2026-01-13T08:05:00Z"
}
],
"meta": {
"total": 42,
"page": 1,
"limit": 25
}
}

Returns the full todo record including timeline and proposals (todos.read).

Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme"
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local).
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias of X-Hoody-Realm). Rejected on this route.
{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"title": "Rotate staging TLS certs",
"body": "STAGING cluster certs expire in 14 days.",
"state": "open",
"priority": 1,
"rank": 0,
"tags": ["security", "P1"],
"revision": 7,
"proposals": [
{
"id": "prop_01HMZZ1QAE3V6X8K2B4NMD0FHJ",
"kind": "run",
"summary": "Run certbot renew on staging nodes",
"status": "pending",
"created_at": "2026-01-12T14:00:00Z"
}
],
"timeline": [
{
"kind": "comment",
"text": "Filed by on-call.",
"at": "2026-01-04T09:00:00Z"
},
{
"kind": "message",
"text": "Started investigate.",
"at": "2026-01-12T14:00:00Z"
}
],
"created_at": "2026-01-04T09:00:00Z",
"updated_at": "2026-01-12T14:32:10Z"
}

Returns the store-wide revision counter (todos.revision) — a cheap poll cursor that moves on every persisted mutation. This is NOT the per-todo CAS token; updateTodo, archiveTodo, snoozeTodo, and claimTodo take each todo’s own revision from getTodo.

Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/revision" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme"
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.
{
"revision": 1284
}

Files a new master todo (todos.create). Deterministic triage (normalize, fingerprint-dedupe, defaults) runs server-side. The todo’s working directory is taken from the body cwd or, if omitted, the X-Hoody-Cwd header; one of the two is required.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{
"title": "Rotate staging TLS certs",
"body": "STAGING cluster certs expire in 14 days.",
"priority": 1,
"tags": ["security", "P1"]
}'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope (defaults the body cwd when omitted).
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.
NameTypeRequiredDescription
titlestringYesTodo title.
bodystringNoTodo body / description.
priorityintegerNoOptional priority band 0..4 (0 = P0 urgent … 4 = P4 someday); defaults to 2 when omitted. Must be a JSON integer in range.
tagsarray of stringNoOptional tags.
cwdstringNoThe todo’s working directory. Defaults to the X-Hoody-Cwd header when omitted.
{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"deduped": false,
"revision": 1
}

Applies a CAS-guarded field patch / state transition to a todo (todos.update). Pass the current revision from getTodo; a stale revision is rejected.

Terminal window
curl -X PATCH "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{
"revision": 7,
"state": "in_progress",
"priority": 0
}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.
NameTypeRequiredDescription
revisionintegerYesThe todo’s own current revision (from getTodo — NOT the store-wide revision).
titlestringNoNew title.
bodystringNoNew body.
statestringNoNew state transition.
priorityintegerNoNew priority.
rankintegerNoNew ordering rank.
tagsarray of stringNoNew tag set.
cwdstringNoRetarget the todo’s working directory.
{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"revision": 8,
"updated_at": "2026-01-13T09:15:00Z"
}

Archives a todo (todos.archive). The body carries the CAS revision from getTodo.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/archive" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{"revision": 7}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.
NameTypeRequiredDescription
revisionintegerYesThe todo’s own current revision (from getTodo).
{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"state": "archived",
"revision": 8
}

Snoozes a todo until a wake time (todos.snooze). The body carries the RFC3339 wake_at and the CAS revision.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/snooze" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{
"wake_at": "2026-07-04T09:00:00Z",
"revision": 7
}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.
NameTypeRequiredDescription
wake_atstringYesWake time, RFC3339 (e.g. 2026-07-04T09:00:00Z); an empty string clears the snooze.
revisionintegerYesThe todo’s own current revision (from getTodo).
{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"wake_at": "2026-07-04T09:00:00Z",
"revision": 8
}

Permanently and irreversibly removes archived todos (todos.purge). An empty body purges all archived tombstones for the cwd.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/purge" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{}'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.

The body is an optional filter object forwarded to todos.purge. An empty body purges all archived tombstones for the cwd. No fields are documented.

{
"purged": 14
}

Posts a comment onto a todo’s timeline WITHOUT triggering an orchestrator turn (todos.post_message). Use /message (singular) to also kick an orchestrator turn.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/messages" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{"text": "Investigating — looks like certs are also stale on node-3."}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.
NameTypeRequiredDescription
textstringYesThe comment body to append to the todo timeline.
{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"revision": 8,
"message_id": "msg_01HN0ABCDEF1234567890ABCDE"
}

Posts a comment AND kicks an orchestrator turn on the todo (todos.message). Returns {job_id}, but the job completes at DISPATCH — the orchestrator runs as a daemon-managed resident whose turn is NOT tracked by the job lifecycle. Poll the todo itself (getTodo) for the orchestrator’s reply/proposal on the timeline; a succeeded job means the turn was dispatched, not finished.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/message" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{"text": "Please draft a run plan for the cert rotation, then post a proposal."}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.
NameTypeRequiredDescription
textstringYesThe message that both comments and prompts the orchestrator.
{
"job_id": "job_01HN0Z9K8Q5WX2AB3CD4EFGHJK"
}

Claims a todo for the caller (todos.claim). The CAS revision is required for a fresh claim; only the lease’s existing owner may refresh without it.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/claim" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{"revision": 7}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.
NameTypeRequiredDescription
revisionintegerNoThe todo’s own current revision (from getTodo). Required for a fresh claim; only the lease’s existing owner may refresh without it.
{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"lease_owner": "agent_01HN0LEASEOWNER1234567890",
"lease_expires_at": "2026-01-13T13:00:00Z",
"revision": 8
}

Releases a claimed todo (todos.release).

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/release" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.

The body is an optional JSON object forwarded to the daemon todos.release RPC. No fields are documented.

{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"lease_owner": null,
"revision": 9
}

Dispatches a background worker to autonomously work a todo (todos.run) and returns {job_id, session_id}. The daemon treats reaching the todos.run RPC as the human approval itself (“issued by the TUI Run action or the CLI, both human-driven”). The minted job completes at DISPATCH (it carries the worker session_id for correlation, but the resident worker runs asynchronously and is NOT tracked by the job lifecycle): a succeeded job means the run was STARTED, not that the todo is finished. Poll the todo itself (getTodo) — it lands in review when the worker is done.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/run" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.

The body is an optional JSON object forwarded to the daemon todos.run RPC. No fields are documented.

{
"job_id": "job_01HN0Z9K8Q5WX2AB3CD4EFGHJK",
"session_id": "sess_01HN0RUNNER1234567890ABCDE"
}

Cancels an in-flight orchestrator run for a todo (todos.cancel_run).

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/cancel-run" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.

The body is an optional JSON object forwarded to the daemon todos.cancel_run RPC. No fields are documented.

{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"state": "open",
"run_cancelled": true,
"revision": 10
}

POST /api/v1/agent/todos/{id}/proposals/{pid}/approve

Section titled “POST /api/v1/agent/todos/{id}/proposals/{pid}/approve”

Approves a run proposal on a todo (todos.approve_proposal). Approval is NOT inert: the daemon hands the approved proposal to a background worker session equivalent to todos.run — a J-class autonomous run. (The paired denyTodoProposal spawns no worker.)

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/proposals/prop_01HMZZ1QAE3V6X8K2B4NMD0FHJ/approve" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
pidpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.

The body is an optional JSON object forwarded to the daemon todos.approve_proposal RPC. No fields are documented.

{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"proposal_id": "prop_01HMZZ1QAE3V6X8K2B4NMD0FHJ",
"status": "approved",
"job_id": "job_01HN0Z9K8Q5WX2AB3CD4EFGHJK",
"session_id": "sess_01HN0RUNNER1234567890ABCDE"
}

POST /api/v1/agent/todos/{id}/proposals/{pid}/deny

Section titled “POST /api/v1/agent/todos/{id}/proposals/{pid}/deny”

Denies a run proposal on a todo (todos.deny_proposal). No worker is spawned.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/todo_01HMZX7P5V3J8N9K4Q2WXABCDE/proposals/prop_01HMZZ1QAE3V6X8K2B4NMD0FHJ/deny" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{}'
NameInTypeRequiredDescription
idpathstringYesPath identifier.
pidpathstringYesPath identifier.
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.

The body is an optional JSON object forwarded to the daemon todos.deny_proposal RPC. No fields are documented.

{
"id": "todo_01HMZX7P5V3J8N9K4Q2WXABCDE",
"proposal_id": "prop_01HMZZ1QAE3V6X8K2B4NMD0FHJ",
"status": "denied"
}

Kicks an LLM triage pass over the inbox (todos.triage) and returns {job_id}. This is a J-class op: it spends model budget on an autonomous LLM run — the same property that makes todos.run a privileged op.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/todos/triage" \
-H "Authorization: Bearer <token>" \
-H "X-Hoody-Cwd: /home/user/projects/acme" \
-H "Content-Type: application/json" \
-d '{}'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override.
X-Hoody-ContainerheaderstringNoPer-request bound remote container.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected on this route.
realmquerystringNoPer-request realm selector (query alias). Rejected on this route.

The body is an optional JSON object forwarded to the daemon todos.triage RPC. An empty body triages the whole inbox. No fields are documented.

{
"job_id": "job_01HN0TRIAGE1234567890ABCDEF"
}