The local runtime stores tasks in the configured SQLite database. task.create, task.get, task.list, and task.update_status return persisted task records through MCP. Local task rows are shared across runs: these handlers do not filter by run or workspace. The HTTP API does not expose first-class task create/list/get/update routes; other API records can carry a task_id association, but that does not make the associated task workspace-scoped or provide task CRUD. Do not infer workspace isolation for local MCP calls.
The HTTP repository-entity inventory is also not a task catalog: it walks filesystem paths and derives file, directory, and symbol entities. For the actual HTTP route surface, see the API Endpoint Guide.
task.create requires nonempty string title and body_md. Its advertised optional fields are integer priority, string risk, string assigned_agent_id, and an array of repository-relative readable_paths. The handler also recognizes string task_id and status, although those fields are not advertised in the tool schema.
readable_paths is the operator-authored filesystem scope for external agents assigned to the task. It accepts up to 256 exact file or directory paths; a directory entry authorizes descendants. The default is empty, so assigning a task without paths does not grant repository reads or resource claims. Paths are persisted with the task and preserved by status/assignment updates. Absolute paths, traversal, and sensitive locations such as .env, .git, .roundtable, .ssh, .aws, .docker, .config, credential files, private-key files, and symlink-containing resources are always rejected. Claims reserve resources but do not independently grant read access.
| Field | Stored behavior |
|---|---|
task_id |
Generated T- timestamp ID when missing/empty. Reusing an ID updates the existing row’s title, body, status, priority, risk, and assignment. |
status |
Defaults to open. The local handler accepts arbitrary nonempty strings rather than validating a lifecycle enum. |
priority |
Defaults to 100; the store also converts 0 to 100. Lower numbers are returned first. Negative values are preserved. |
risk |
Defaults to normal. The handler stores arbitrary nonempty strings. Exact high/critical values have special downstream policy behavior. |
assigned_agent_id |
Empty means unassigned. The create handler does not check that the agent exists, is enabled, or has the intended role. |
{"title":"Add pagination","body_md":"Implement and validate cursor pagination.","priority":20,"risk":"normal","assigned_agent_id":"implementer-1","readable_paths":["api/internal/httpapi","api/openapi.yaml"]}
The response is {"task": ...}. task.get requires task_id and fails for a missing row. task.list returns {"tasks": ...} for all local tasks, ordered by ascending priority, creation timestamp, then ID. It has no pagination or status/agent/run filters; an empty result can serialize as null rather than [].
The local handlers use string values only when JSON values are actually strings; a number/object supplied for an optional string becomes empty and therefore selects its default or leaves an update field unchanged. A non-string required title/body fails the same required-field check as omission. Required checks test exact emptiness rather than trimming, so whitespace-only titles and bodies are accepted. Integer priority accepts integer/JSON-number values via the runtime integer helper; floating-point numbers are truncated and nonnumeric/string values fall back to the default. These permissive local MCP conversions are distinct from HTTP API JSON decoding.
task.update_status requires an existing task_id. A nonempty string status changes status; a nonempty string assigned_agent_id changes assignment. Empty or omitted values preserve their existing fields. Consequently this operation cannot clear an assignment by sending an empty string. A call with neither optional field still upserts the task and advances updated_at. It returns the saved task.
The MCP handler does not enforce transition order or role permissions. Coordinator behavior does depend on status: open work is assigned by orchestration, and convergence examines the statuses described in Orchestration. Use consistent lowercase lifecycle values and verify the resulting table state. Completing a task does not itself approve or apply its proposal, run tests, or release its claims; perform those operations through their own tools.
The task’s created_at is preserved on updates. The local create/update handlers persist the task directly and do not themselves append a task event. Read task/table state to verify an update instead of assuming it will appear as a new event in table.watch.
See MCP Tools, Claims, and Proposals and Transactions for the associated workflow.