Master TODO
Section titled “Master TODO”The Master TODO is the central, workspace-scoped ledger of work items that the Hoody agent orchestrator schedules, tracks, and reflects on. Each entry has a lifecycle status, a priority, dependency edges, budgeted spend and rounds, an optional spec, and a phase_id that ties it to a phase. Use these endpoints to read the full state, append new entries, and mutate individual fields such as status, priority, rounds, and specs.
Read full Master TODO state
Section titled “Read full Master TODO state”GET /api/v1/workspaces/{workspaceID}/orchestration/todo
Returns the fully materialized Master TODO, including all entries and phases for the workspace.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
Response
Section titled “Response”{ "id": "todo_01HMZ7K8XQF8RN2C9WXPEYJSVA", "version": 42, "created_at": 1717691342000, "project_context": "Build a TypeScript SDK for the Hoody public API with full test coverage.", "entries": [ { "id": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "seq": 1, "type": "task", "content": "Generate OpenAPI client scaffolding", "spec": { "requirements": "Produce a typed client covering auth, workspaces, and agent endpoints.", "acceptance_criteria": [ "Client compiles with tsc --noEmit", "Every endpoint exposed by the public spec is wrapped" ], "files_to_create": ["src/client.ts", "src/types.ts"], "files_to_modify": ["package.json"], "patterns": "Use the existing fetch-based HttpClient wrapper.", "api_contract": "All public types must match the OpenAPI schema byte-for-byte.", "examples": "See /examples/auth.ts for a runnable smoke test.", "integration_points": "Publishes through @hoody/sdk.", "authored_by": "specs-agent", "last_edited": 1717691300000, "revision": 4 }, "spec_frozen": false, "status": "in_progress", "priority": "high", "depends_on": [], "children": [], "parallelizable": true, "parallel_group": "scaffold", "budget_usd": 25, "spent_usd": 4.2, "budget_rounds": 5, "rounds_completed": 1, "created_by": "user", "assigned_to": "session_01HMZ7K0YQB4ET7JVM9F2D8N3P", "session_ids": ["session_01HMZ7K0YQB4ET7JVM9F2D8N3P"], "verified": false, "phase_id": "phase_01HMZ7KAB9C3R5V7T8DXQW2YN4" } ], "phases": [ { "id": "phase_01HMZ7KAB9C3R5V7T8DXQW2YN4", "seq": 1, "name": "Scaffolding", "description": "Generate the initial client and project files.", "status": "active", "entry_ids": ["entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ"], "fixer_entry_ids": [], "session_ids": ["session_01HMZ7K0YQB4ET7JVM9F2D8N3P"], "phase_rounds": 3, "phase_rounds_completed": 1, "created_at": 1717691000000, "updated_at": 1717691400000, "summary": "Scaffolding underway.", "memory": [ { "text": "Switched to fetch-based client wrapper after benchmarking.", "created_at": 1717691250000 } ] } ]}const todo = await client.agent.orchestration.todoRead({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE",});Get a single Master TODO entry
Section titled “Get a single Master TODO entry”GET /api/v1/workspaces/{workspaceID}/orchestration/todo/entries/{entryID}
Fetches a single entry by ID.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
entryID | path | string | Yes | Master TODO entry identifier |
Response
Section titled “Response”{ "entry": { "id": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "seq": 1, "type": "task", "content": "Generate OpenAPI client scaffolding", "spec": { "requirements": "Produce a typed client covering auth, workspaces, and agent endpoints.", "acceptance_criteria": [ "Client compiles with tsc --noEmit" ], "authored_by": "specs-agent", "last_edited": 1717691300000, "revision": 4 }, "spec_frozen": false, "status": "in_progress", "priority": "high", "depends_on": [], "parallelizable": true, "spent_usd": 4.2, "budget_rounds": 5, "rounds_completed": 1, "created_by": "user", "session_ids": ["session_01HMZ7K0YQB4ET7JVM9F2D8N3P"] }}{ "name": "NotFoundError", "data": { "message": "Entry entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ not found in workspace ws_01HMZ7J2H3D9R5C8PWTY6QNBVE." }}const { entry } = await client.agent.orchestration.todoGetEntry({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", entryID: "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ",});Read entry spec
Section titled “Read entry spec”GET /api/v1/workspaces/{workspaceID}/orchestration/todo/entries/{entryID}/spec
Returns the structured spec attached to an entry, or null if no spec has been authored.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
entryID | path | string | Yes | Master TODO entry identifier |
Response
Section titled “Response”{ "spec": { "requirements": "Produce a typed client covering auth, workspaces, and agent endpoints.", "acceptance_criteria": [ "Client compiles with tsc --noEmit", "Every endpoint exposed by the public spec is wrapped" ], "files_to_create": ["src/client.ts", "src/types.ts"], "files_to_modify": ["package.json"], "patterns": "Use the existing fetch-based HttpClient wrapper.", "api_contract": "All public types must match the OpenAPI schema byte-for-byte.", "examples": "See /examples/auth.ts for a runnable smoke test.", "integration_points": "Publishes through @hoody/sdk.", "authored_by": "specs-agent", "last_edited": 1717691300000, "revision": 4 }}{ "name": "NotFoundError", "data": { "message": "Entry entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ not found in workspace ws_01HMZ7J2H3D9R5C8PWTY6QNBVE." }}const { spec } = await client.agent.orchestration.todoReadSpec({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", entryID: "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ",});Read Master TODO event log
Section titled “Read Master TODO event log”GET /api/v1/workspaces/{workspaceID}/orchestration/todo/events
Returns a paginated append-only event log covering every mutation to the Master TODO (entries, statuses, specs, phases, and more).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
page | query | integer | No | Page number. Default: 1 |
limit | query | integer | No | Items per page. Default: 50 |
Response
Section titled “Response”{ "items": [ { "id": "evt_01HMZ7KAC8T7X5Z9Q2V1BHPRM3", "seq": 128, "type": "status_changed", "payload": { "entryID": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "from": "pending", "to": "in_progress" }, "timestamp": 1717691380000, "actor": "session_01HMZ7K0YQB4ET7JVM9F2D8N3P" }, { "id": "evt_01HMZ7K9B4YJ2K6L0N1XDPQ5S7", "seq": 127, "type": "entry_created", "payload": { "entryID": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "type": "task", "priority": "high" }, "timestamp": 1717691342000, "actor": "user" } ], "meta": { "page": 1, "limit": 50, "total": 128, "pages": 3 }}const events = await client.agent.orchestration.todoGetEvents({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", page: 1, limit: 50,});Modify
Section titled “Modify”Append entries to Master TODO
Section titled “Append entries to Master TODO”POST /api/v1/workspaces/{workspaceID}/orchestration/todo/entries
Appends one or more new entries to the Master TODO. Each entry must declare a type, content, and priority. An optional spec may be supplied to seed the entry with requirements and acceptance criteria.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
entries | array | Yes | Entries to append. Each item requires type, content, and priority. |
Each entry item supports:
type— one of"task","correction","review","snapshot","note","parent"content— human-readable descriptionspec— optionalobjectwithrequirements(required),acceptance_criteria(required, array of strings), and optionalfiles_to_create,files_to_modify,patterns,api_contract,examples,integration_pointspriority— one of"critical","high","medium","low"depends_on— array of entry IDs; defaults to[]parallelizable— boolean; defaults totrueparallel_group— string label grouping parallel-safe entriesbudget_usd— optional per-entry spend capbudget_rounds— integer; defaults to3phase_id— optional phase bindingcontainer_id— optional container binding
{ "entries": [ { "type": "task", "content": "Implement POST /api/v1/auth/login", "priority": "high", "spec": { "requirements": "Accept JSON { email, password } and return a signed session token.", "acceptance_criteria": [ "Valid credentials return 200 with a token", "Invalid credentials return 401 with an error code" ], "files_to_create": ["src/routes/auth/login.ts"], "files_to_modify": ["src/routes/auth/index.ts"] }, "depends_on": [], "parallelizable": true, "budget_usd": 10, "budget_rounds": 4 } ]}Response
Section titled “Response”{ "added": [ "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ" ], "count": 1}{ "data": null, "errors": [ { "field": "entries[0].priority", "message": "priority must be one of: critical, high, medium, low" } ], "success": false}const result = await client.agent.orchestration.todoAppend({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", data: { entries: [ { type: "task", content: "Implement POST /api/v1/auth/login", priority: "high", spec: { requirements: "Accept JSON { email, password } and return a signed session token.", acceptance_criteria: [ "Valid credentials return 200 with a token", "Invalid credentials return 401 with an error code" ], files_to_create: ["src/routes/auth/login.ts"], files_to_modify: ["src/routes/auth/index.ts"] }, budget_rounds: 4 } ] }});Update entry spec
Section titled “Update entry spec”PUT /api/v1/workspaces/{workspaceID}/orchestration/todo/entries/{entryID}/spec
Replaces the spec attached to an entry and increments its revision. The entry must not be frozen.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
entryID | path | string | Yes | Master TODO entry identifier |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
requirements | string | Yes | Free-form requirements text |
acceptance_criteria | array | Yes | Array of strings describing acceptance criteria |
files_to_create | array | No | Array of file paths to create |
files_to_modify | array | No | Array of file paths to modify |
patterns | string | No | Patterns or conventions to follow |
api_contract | string | No | API contract details |
examples | string | No | Example usage or references |
integration_points | string | No | Notes on how the entry integrates with surrounding work |
{ "requirements": "Accept JSON { email, password } and return a signed session token; throttle by IP.", "acceptance_criteria": [ "Valid credentials return 200 with a token", "Invalid credentials return 401 with an error code", "More than 10 attempts/minute from one IP returns 429" ], "files_to_create": ["src/routes/auth/login.ts"], "files_to_modify": ["src/routes/auth/index.ts", "src/middleware/rate-limit.ts"], "patterns": "Use the existing HttpError helper for error responses."}Response
Section titled “Response”{ "entryID": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "revision": 5}{ "name": "NotFoundError", "data": { "message": "Entry entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ not found in workspace ws_01HMZ7J2H3D9R5C8PWTY6QNBVE." }}{ "error": "Spec is frozen; further edits are not permitted.", "code": "spec_frozen"}const result = await client.agent.orchestration.todoUpdateSpec({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", entryID: "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", data: { requirements: "Accept JSON { email, password } and return a signed session token; throttle by IP.", acceptance_criteria: [ "Valid credentials return 200 with a token", "Invalid credentials return 401 with an error code" ] }});Freeze entry spec
Section titled “Freeze entry spec”POST /api/v1/workspaces/{workspaceID}/orchestration/todo/entries/{entryID}/spec/freeze
Locks an entry’s spec so that subsequent update attempts are rejected with 409. Use this to commit a spec before the implementation sessions begin.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
entryID | path | string | Yes | Master TODO entry identifier |
Response
Section titled “Response”{ "entryID": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "frozen": true}{ "name": "NotFoundError", "data": { "message": "Entry entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ not found in workspace ws_01HMZ7J2H3D9R5C8PWTY6QNBVE." }}const result = await client.agent.orchestration.todoFreezeSpec({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", entryID: "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ",});Update entry priority
Section titled “Update entry priority”PATCH /api/v1/workspaces/{workspaceID}/orchestration/todo/entries/{entryID}/priority
Re-orders an entry by changing its priority tier. The response includes the previous value so callers can audit the change.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
entryID | path | string | Yes | Master TODO entry identifier |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
priority | string | Yes | One of "critical", "high", "medium", "low" |
{ "priority": "critical"}Response
Section titled “Response”{ "entryID": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "priority": "critical", "previous": "high"}{ "data": null, "errors": [ { "field": "priority", "message": "priority must be one of: critical, high, medium, low" } ], "success": false}{ "name": "NotFoundError", "data": { "message": "Entry entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ not found in workspace ws_01HMZ7J2H3D9R5C8PWTY6QNBVE." }}const result = await client.agent.orchestration.todoSetPriority({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", entryID: "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", data: { priority: "critical" },});Set entry budget rounds
Section titled “Set entry budget rounds”PATCH /api/v1/workspaces/{workspaceID}/orchestration/todo/entries/{entryID}/rounds
Sets budget_rounds for an entry — the maximum number of execution rounds the orchestrator will attempt before giving up. The value must be between 1 and 50 inclusive.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
entryID | path | string | Yes | Master TODO entry identifier |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
budget_rounds | integer | Yes | Maximum number of execution rounds. Range: 1 to 50. |
{ "budget_rounds": 8}Response
Section titled “Response”{ "entryID": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "budget_rounds": 8}{ "data": null, "errors": [ { "field": "budget_rounds", "message": "budget_rounds must be between 1 and 50" } ], "success": false}{ "name": "NotFoundError", "data": { "message": "Entry entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ not found in workspace ws_01HMZ7J2H3D9R5C8PWTY6QNBVE." }}const result = await client.agent.orchestration.todoSetRounds({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", entryID: "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", data: { budget_rounds: 8 },});Update entry status
Section titled “Update entry status”PATCH /api/v1/workspaces/{workspaceID}/orchestration/todo/entries/{entryID}/status
Transitions an entry to a new status and optionally attaches a handoff note and a list of mistakes learned for future sessions. context_for_next is capped at 2000 characters.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
entryID | path | string | Yes | Master TODO entry identifier |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
status | string | Yes | One of "pending", "blocked", "in_progress", "done", "failed", "skipped", "superseded" |
context_for_next | string | No | Handoff note for the next session. Maximum 2000 characters. |
mistakes_learned | array | No | Array of strings describing mistakes the next session should avoid. |
{ "status": "done", "context_for_next": "Login route implemented; rate limiter wired in via src/middleware/rate-limit.ts.", "mistakes_learned": [ "Don't sha256 the password in the route handler — use the auth service." ]}Response
Section titled “Response”{ "entryID": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", "status": "done", "previous": "in_progress"}{ "data": null, "errors": [ { "field": "status", "message": "status must be one of: pending, blocked, in_progress, done, failed, skipped, superseded" } ], "success": false}{ "name": "NotFoundError", "data": { "message": "Entry entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ not found in workspace ws_01HMZ7J2H3D9R5C8PWTY6QNBVE." }}const result = await client.agent.orchestration.todoSetStatus({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", entryID: "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ", data: { status: "done", context_for_next: "Login route implemented; rate limiter wired in via src/middleware/rate-limit.ts.", mistakes_learned: [ "Don't sha256 the password in the route handler — use the auth service." ] },});Delete a task entry
Section titled “Delete a task entry”DELETE /api/v1/workspaces/{workspaceID}/orchestration/todo/entries/{entryID}
Removes an entry from the Master TODO. Returns 409 if the entry cannot be safely deleted in its current state (for example, when it is referenced as a dependency by other in-flight entries).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceID | path | string | Yes | Workspace identifier |
entryID | path | string | Yes | Master TODO entry identifier |
Response
Section titled “Response”{ "deleted": true, "entryID": "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ"}{ "name": "NotFoundError", "data": { "message": "Entry entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ not found in workspace ws_01HMZ7J2H3D9R5C8PWTY6QNBVE." }}{ "error": "Entry is referenced as a dependency by in-flight entries and cannot be deleted.", "code": "entry_has_dependents"}const result = await client.agent.orchestration.todoDeleteEntry({ workspaceID: "ws_01HMZ7J2H3D9R5C8PWTY6QNBVE", entryID: "entry_01HMZ7K9BQPJ3Y5T6H2SNQR4XZ",});