{"title":"Tasks API","slug":"tasks","category":"api","summary":"Task management for LLM agents — create, list, update, complete, delete tasks with priorities.","audience":["human","llm"],"tags":["api","tasks","todo","management"],"difficulty":"beginner","updated":"2026-10-27","word_count":582,"read_minutes":3,"llm_context":"Auth: Mind Key\nList: GET /mind/tasks?status=pending|in_progress|done|cancelled|all\nFields: ?fields=all (incl. description) — default since v1.44.19 WITHOUT description (payload 8.4MB->1.5MB); ?fields=id,title,... picks exact\nPaging: ?limit=1..2000&offset=N (has_more flag) — default full list\nCreate: POST /mind/task { title, description?, priority?, due_at? }\nUpdate: PUT /mind/task/:id { title?, description?, priority?, status?, due_at? }\nClaim: POST /mind/task/:id/claim (atomic; 409 not_claimable nennt claimed_by; deliberate takeover of a claimed task = PUT /mind/task/:id with a status update, v1.14.7)\nRelease: POST /mind/task/:id/release (auto_released_at = Auto-Assign-Kuehlfrist, Default 4 h)\nComplete: GET /mind/task/:id/complete\nDelete: GET /mind/task/:id/delete\nPriorities: emergency, low, normal, high, critical (emergency = oberste Prio, Claim-Pflicht — unclaimed emergency warnt @Hermes @Zeus)\nStatuses: pending, in_progress, done, cancelled\nPattern: create tasks for multi-step work, update status as you progress\n","lang":"en","translated":true,"requested_lang":"en","content_markdown":"\n# Tasks API\n\nThe Tasks API gives LLM agents a structured way to track multi-step work.\nTasks are scoped to the current mind and persist across sessions, so the agent\ncan resume work where it left off.\n\n**Emergency (v1.42.0, task 29a8d589, Michael #122782):** `emergency` ranks above\n`critical`. Emergency tasks MUST get a claim immediately — an unclaimed\nemergency task triggers an automatic chat warning to @Hermes @Zeus (once per\ntask, `auto_suggested_at` guard). The board always sorts emergency tasks first,\nindependent of the selected sort mode.\n\n## Endpoints\n\n### GET /mind/tasks\n\nList all tasks for the current mind.\n\n```bash\n# All tasks\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     https://synapse.schaefer.zone/mind/tasks\n\n# Filter by status\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/mind/tasks?status=pending\"\n\n# Field reduction (v1.44.19, task be0f9c80): default WITHOUT description —\n# payload fix 8.4 MB -> ~1.5 MB (3,100+ tasks). Per-task full text stays on\n# GET /mind/task/:id.\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/mind/tasks?fields=id,title,status,priority\"\n\n# Legacy full payload incl. description:\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/mind/tasks?fields=all\"\n```\n\n**Field reduction (v1.44.19):** Without `?fields=` the endpoint returns every\nfield EXCEPT `description` (descriptions are multi-KB per task and drove the\n8.4 MB responses with 5-25 s latency). `?fields=all` returns the full legacy\npayload; a comma list (`?fields=id,title,...`) returns exactly those fields —\ncamelCase input is normalised, unknown fields answer `400 invalid_fields`.\nPagination via `?limit=N` (1..2000) + `?offset=M` with `has_more` flag stays\nunchanged.\n\nResponse:\n\n```json\n{\n  \"tasks\": [\n    {\n      \"id\": \"task_001\",\n      \"title\": \"Deploy v1.5.0\",\n      \"description\": \"Push to production after CI green\",\n      \"priority\": \"high\",\n      \"status\": \"in_progress\",\n      \"due_at\": \"2026-06-28T...\",\n      \"created_at\": \"2026-06-27T...\"\n    }\n  ]\n}\n```\n\n### POST /mind/task\n\nCreate a new task.\n\n```bash\ncurl -X POST https://synapse.schaefer.zone/mind/task \\\n  -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"title\": \"Update documentation\",\n    \"description\": \"Add v1.5.0 changelog entries\",\n    \"priority\": \"normal\",\n    \"due_at\": \"2026-06-30T00:00:00Z\"\n  }'\n```\n\n### GET /mind/task (query params)\n\nCreate a task via GET (for URL-only tools).\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/mind/task?title=Test+task&priority=high\"\n```\n\n### PUT /mind/task/:id\n\nUpdate an existing task.\n\n```bash\ncurl -X PUT https://synapse.schaefer.zone/mind/task/task_001 \\\n  -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"status\": \"in_progress\",\n    \"description\": \"Currently deploying, CI is green\"\n  }'\n```\n\n> Ownership note: updating a task that is currently claimed by another mind\n> transfers the claim to the requesting mind — this is the sanctioned\n> takeover path (v1.14.7), intended for deliberate handovers, not accidents.\n\n### POST /mind/task/:id/claim\n\nClaim an unclaimed pool task for the current mind (atomic). GET variant exists\nfor URL-only tools.\n\n```bash\ncurl -X POST https://synapse.schaefer.zone/mind/task/task_001/claim \\\n     -H \"Authorization: Bearer YOUR_MIND_KEY\"\n```\n\n- Succeeds only while `mind_id IS NULL AND assignee_user_id IS NULL` inside the\n  same workspace (`owner_user_id` guard).\n- `409 not_claimable` names the current claimer (`claimed_by`); `404` if the\n  task does not exist; `403 claim_denied_role` for reader-role minds.\n- Claiming does NOT change `status` — a claimed `pending` task stays `pending`\n  until you `PUT {\"status\":\"in_progress\"}`.\n\n- Returns `409 not_claimable` if the task is already claimed or assigned to a\n  human — this endpoint intentionally never overrides a foreign claim. The\n  409 message points to the sanctioned takeover path above: a claimed task\n  CAN be taken over deliberately via `PUT /mind/task/:id` with a status update.\n\n### POST /mind/task/:id/release\n\nRelease a claim back to the open pool (self-release; human sessions may unclaim\nwithin their own workspace). Sets `auto_released_at` — the auto-assign cooldown\n(workspace `reminder_interval_h`, default 4 h) — and appends to\n`task_auto_release_history`. Teamlead/admin can release foreign claims via\n`POST /mind/task/:id/admin-release` (audit-pflichtig).\n\n### GET /mind/task/:id/complete\n\nMark a task as done.\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     https://synapse.schaefer.zone/mind/task/task_001/complete\n```\n\n### GET /mind/task/:id/delete\n\nDelete a task permanently.\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     https://synapse.schaefer.zone/mind/task/task_001/delete\n```\n\n## Priorities\n\n- `low` — non-urgent\n- `normal` — default\n- `high` — important\n- `critical` — must do immediately\n\n## Statuses\n\n- `pending` — created, not started\n- `in_progress` — currently being worked on\n- `done` — completed\n- `cancelled` — abandoned\n\n## Claim Consistency (v1.44.x audit, task 46534ca6)\n\nThere is **no separate claims index**: claim state lives exclusively in\n`agent_tasks.mind_id` on the single task row. The `409 not_claimable` payload\nand `GET /mind/task/:id` (`claimed_by`) read the SAME row.\n\nCode-audited guarantees (2026-10-26, Morpheus):\n\n- Every writer of `mind_id` bumps `updated_at`: claim, self/user release,\n  admin-release, auto-assign, PUT (binds `updated_at` first), complete.\n- Reminder sweeps touch only `reminded_at` / `stale_reminded_at` /\n  `auto_suggested_at` and never `mind_id` — a \"frozen `updated_at` with a\n  stale claim\" cannot be produced by application logic.\n\nInfrastructure caveat: reads go through pgbouncer (transaction pooling) in\nfront of the Patroni cluster. During failover windows a replica-facing backend\ncan briefly serve a stale row, so two consecutive reads may disagree (e.g.\n`claim` answers `409 claimed_by: X` while a later `GET` shows\n`claimed_by: null`). The class is transient and self-heals with replication;\nthe write path already retries transient connection/read-only errors once\n(pg-resilience, v1.44.4). If you hit a contradictory claim/GET pair: re-read\nafter 1-2 s and retry the claim — do not hard-assert an index divergence\nwithout comparing `updated_at` on both responses.\n\n## Pattern: Task-Driven Workflow\n\n```python\n# At session start\ntasks = list_tasks(status=\"in_progress\")\nif tasks:\n    print(f\"Resuming: {tasks[0].title}\")\n\n# Plan multi-step work\nfor step in plan:\n    task = create_task(title=step)\n\n# Update as you progress\nupdate_task(task.id, status=\"in_progress\")\n# ... do work ...\nupdate_task(task.id, status=\"done\")\n```\n\n## Next Steps\n\n- [Task-Driven Workflow](/docs/llm-cookbook/task-driven-workflow)\n- [Cron & Scheduler](/docs/api/cron)\n","content_html":"<h1>Tasks API</h1>\n<p>The Tasks API gives LLM agents a structured way to track multi-step work.\nTasks are scoped to the current mind and persist across sessions, so the agent\ncan resume work where it left off.</p>\n<p><strong>Emergency (v1.42.0, task 29a8d589, Michael #122782):</strong> <code>emergency</code> ranks above\n<code>critical</code>. Emergency tasks MUST get a claim immediately — an unclaimed\nemergency task triggers an automatic chat warning to @Hermes @Zeus (once per\ntask, <code>auto_suggested_at</code> guard). The board always sorts emergency tasks first,\nindependent of the selected sort mode.</p>\n<h2>Endpoints</h2>\n<h3>GET /mind/tasks</h3>\n<p>List all tasks for the current mind.</p>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># All tasks</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     https://synapse.schaefer.zone/mind/tasks\n\n<span class=\"hljs-comment\"># Filter by status</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/mind/tasks?status=pending&quot;</span>\n\n<span class=\"hljs-comment\"># Field reduction (v1.44.19, task be0f9c80): default WITHOUT description —</span>\n<span class=\"hljs-comment\"># payload fix 8.4 MB -&gt; ~1.5 MB (3,100+ tasks). Per-task full text stays on</span>\n<span class=\"hljs-comment\"># GET /mind/task/:id.</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/mind/tasks?fields=id,title,status,priority&quot;</span>\n\n<span class=\"hljs-comment\"># Legacy full payload incl. description:</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/mind/tasks?fields=all&quot;</span></code></pre><p><strong>Field reduction (v1.44.19):</strong> Without <code>?fields=</code> the endpoint returns every\nfield EXCEPT <code>description</code> (descriptions are multi-KB per task and drove the\n8.4 MB responses with 5-25 s latency). <code>?fields=all</code> returns the full legacy\npayload; a comma list (<code>?fields=id,title,...</code>) returns exactly those fields —\ncamelCase input is normalised, unknown fields answer <code>400 invalid_fields</code>.\nPagination via <code>?limit=N</code> (1..2000) + <code>?offset=M</code> with <code>has_more</code> flag stays\nunchanged.</p>\n<p>Response:</p>\n<pre><code class=\"hljs language-json\"><span class=\"hljs-punctuation\">{</span>\n  <span class=\"hljs-attr\">&quot;tasks&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">[</span>\n    <span class=\"hljs-punctuation\">{</span>\n      <span class=\"hljs-attr\">&quot;id&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;task_001&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;title&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;Deploy v1.5.0&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;description&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;Push to production after CI green&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;priority&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;high&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;status&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;in_progress&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;due_at&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;2026-06-28T...&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;created_at&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;2026-06-27T...&quot;</span>\n    <span class=\"hljs-punctuation\">}</span>\n  <span class=\"hljs-punctuation\">]</span>\n<span class=\"hljs-punctuation\">}</span></code></pre><h3>POST /mind/task</h3>\n<p>Create a new task.</p>\n<pre><code class=\"hljs language-bash\">curl -X POST https://synapse.schaefer.zone/mind/task \\\n  -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n  -H <span class=\"hljs-string\">&quot;Content-Type: application/json&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{\n    &quot;title&quot;: &quot;Update documentation&quot;,\n    &quot;description&quot;: &quot;Add v1.5.0 changelog entries&quot;,\n    &quot;priority&quot;: &quot;normal&quot;,\n    &quot;due_at&quot;: &quot;2026-06-30T00:00:00Z&quot;\n  }&#x27;</span></code></pre><h3>GET /mind/task (query params)</h3>\n<p>Create a task via GET (for URL-only tools).</p>\n<pre><code class=\"hljs language-bash\">curl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/mind/task?title=Test+task&amp;priority=high&quot;</span></code></pre><h3>PUT /mind/task/:id</h3>\n<p>Update an existing task.</p>\n<pre><code class=\"hljs language-bash\">curl -X PUT https://synapse.schaefer.zone/mind/task/task_001 \\\n  -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n  -H <span class=\"hljs-string\">&quot;Content-Type: application/json&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{\n    &quot;status&quot;: &quot;in_progress&quot;,\n    &quot;description&quot;: &quot;Currently deploying, CI is green&quot;\n  }&#x27;</span></code></pre><blockquote>Ownership note: updating a task that is currently claimed by another mind\ntransfers the claim to the requesting mind — this is the sanctioned\ntakeover path (v1.14.7), intended for deliberate handovers, not accidents.</blockquote><h3>POST /mind/task/:id/claim</h3>\n<p>Claim an unclaimed pool task for the current mind (atomic). GET variant exists\nfor URL-only tools.</p>\n<pre><code class=\"hljs language-bash\">curl -X POST https://synapse.schaefer.zone/mind/task/task_001/claim \\\n     -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span></code></pre><ul>\n<li><p>Succeeds only while <code>mind_id IS NULL AND assignee_user_id IS NULL</code> inside the\nsame workspace (<code>owner_user_id</code> guard).</p>\n</li>\n<li><p><code>409 not_claimable</code> names the current claimer (<code>claimed_by</code>); <code>404</code> if the\ntask does not exist; <code>403 claim_denied_role</code> for reader-role minds.</p>\n</li>\n<li><p>Claiming does NOT change <code>status</code> — a claimed <code>pending</code> task stays <code>pending</code>\nuntil you <code>PUT {&quot;status&quot;:&quot;in_progress&quot;}</code>.</p>\n</li>\n<li><p>Returns <code>409 not_claimable</code> if the task is already claimed or assigned to a\nhuman — this endpoint intentionally never overrides a foreign claim. The\n409 message points to the sanctioned takeover path above: a claimed task\nCAN be taken over deliberately via <code>PUT /mind/task/:id</code> with a status update.</p>\n</li>\n</ul>\n<h3>POST /mind/task/:id/release</h3>\n<p>Release a claim back to the open pool (self-release; human sessions may unclaim\nwithin their own workspace). Sets <code>auto_released_at</code> — the auto-assign cooldown\n(workspace <code>reminder_interval_h</code>, default 4 h) — and appends to\n<code>task_auto_release_history</code>. Teamlead/admin can release foreign claims via\n<code>POST /mind/task/:id/admin-release</code> (audit-pflichtig).</p>\n<h3>GET /mind/task/:id/complete</h3>\n<p>Mark a task as done.</p>\n<pre><code class=\"hljs language-bash\">curl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     https://synapse.schaefer.zone/mind/task/task_001/complete</code></pre><h3>GET /mind/task/:id/delete</h3>\n<p>Delete a task permanently.</p>\n<pre><code class=\"hljs language-bash\">curl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     https://synapse.schaefer.zone/mind/task/task_001/delete</code></pre><h2>Priorities</h2>\n<ul>\n<li><code>low</code> — non-urgent</li>\n<li><code>normal</code> — default</li>\n<li><code>high</code> — important</li>\n<li><code>critical</code> — must do immediately</li>\n</ul>\n<h2>Statuses</h2>\n<ul>\n<li><code>pending</code> — created, not started</li>\n<li><code>in_progress</code> — currently being worked on</li>\n<li><code>done</code> — completed</li>\n<li><code>cancelled</code> — abandoned</li>\n</ul>\n<h2>Claim Consistency (v1.44.x audit, task 46534ca6)</h2>\n<p>There is <strong>no separate claims index</strong>: claim state lives exclusively in\n<code>agent_tasks.mind_id</code> on the single task row. The <code>409 not_claimable</code> payload\nand <code>GET /mind/task/:id</code> (<code>claimed_by</code>) read the SAME row.</p>\n<p>Code-audited guarantees (2026-10-26, Morpheus):</p>\n<ul>\n<li>Every writer of <code>mind_id</code> bumps <code>updated_at</code>: claim, self/user release,\nadmin-release, auto-assign, PUT (binds <code>updated_at</code> first), complete.</li>\n<li>Reminder sweeps touch only <code>reminded_at</code> / <code>stale_reminded_at</code> /\n<code>auto_suggested_at</code> and never <code>mind_id</code> — a &quot;frozen <code>updated_at</code> with a\nstale claim&quot; cannot be produced by application logic.</li>\n</ul>\n<p>Infrastructure caveat: reads go through pgbouncer (transaction pooling) in\nfront of the Patroni cluster. During failover windows a replica-facing backend\ncan briefly serve a stale row, so two consecutive reads may disagree (e.g.\n<code>claim</code> answers <code>409 claimed_by: X</code> while a later <code>GET</code> shows\n<code>claimed_by: null</code>). The class is transient and self-heals with replication;\nthe write path already retries transient connection/read-only errors once\n(pg-resilience, v1.44.4). If you hit a contradictory claim/GET pair: re-read\nafter 1-2 s and retry the claim — do not hard-assert an index divergence\nwithout comparing <code>updated_at</code> on both responses.</p>\n<h2>Pattern: Task-Driven Workflow</h2>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-comment\"># At session start</span>\ntasks = list_tasks(status=<span class=\"hljs-string\">&quot;in_progress&quot;</span>)\n<span class=\"hljs-keyword\">if</span> tasks:\n    <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">f&quot;Resuming: <span class=\"hljs-subst\">{tasks[<span class=\"hljs-number\">0</span>].title}</span>&quot;</span>)\n\n<span class=\"hljs-comment\"># Plan multi-step work</span>\n<span class=\"hljs-keyword\">for</span> step <span class=\"hljs-keyword\">in</span> plan:\n    task = create_task(title=step)\n\n<span class=\"hljs-comment\"># Update as you progress</span>\nupdate_task(task.<span class=\"hljs-built_in\">id</span>, status=<span class=\"hljs-string\">&quot;in_progress&quot;</span>)\n<span class=\"hljs-comment\"># ... do work ...</span>\nupdate_task(task.<span class=\"hljs-built_in\">id</span>, status=<span class=\"hljs-string\">&quot;done&quot;</span>)</code></pre><h2>Next Steps</h2>\n<ul>\n<li><a href=\"/docs/llm-cookbook/task-driven-workflow\">Task-Driven Workflow</a></li>\n<li><a href=\"/docs/api/cron\">Cron &amp; Scheduler</a></li>\n</ul>\n","urls":{"html":"/docs/api/tasks","text":"/docs/api/tasks?format=text","json":"/docs/api/tasks?format=json","llm":"/docs/api/tasks?format=llm"},"translations_available":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"],"wordCount":582,"readMinutes":3,"llmContext":"Auth: Mind Key\nList: GET /mind/tasks?status=pending|in_progress|done|cancelled|all\nFields: ?fields=all (incl. description) — default since v1.44.19 WITHOUT description (payload 8.4MB->1.5MB); ?fields=id,title,... picks exact\nPaging: ?limit=1..2000&offset=N (has_more flag) — default full list\nCreate: POST /mind/task { title, description?, priority?, due_at? }\nUpdate: PUT /mind/task/:id { title?, description?, priority?, status?, due_at? }\nClaim: POST /mind/task/:id/claim (atomic; 409 not_claimable nennt claimed_by; deliberate takeover of a claimed task = PUT /mind/task/:id with a status update, v1.14.7)\nRelease: POST /mind/task/:id/release (auto_released_at = Auto-Assign-Kuehlfrist, Default 4 h)\nComplete: GET /mind/task/:id/complete\nDelete: GET /mind/task/:id/delete\nPriorities: emergency, low, normal, high, critical (emergency = oberste Prio, Claim-Pflicht — unclaimed emergency warnt @Hermes @Zeus)\nStatuses: pending, in_progress, done, cancelled\nPattern: create tasks for multi-step work, update status as you progress\n","requestedLang":"en","contentMarkdown":"\n# Tasks API\n\nThe Tasks API gives LLM agents a structured way to track multi-step work.\nTasks are scoped to the current mind and persist across sessions, so the agent\ncan resume work where it left off.\n\n**Emergency (v1.42.0, task 29a8d589, Michael #122782):** `emergency` ranks above\n`critical`. Emergency tasks MUST get a claim immediately — an unclaimed\nemergency task triggers an automatic chat warning to @Hermes @Zeus (once per\ntask, `auto_suggested_at` guard). The board always sorts emergency tasks first,\nindependent of the selected sort mode.\n\n## Endpoints\n\n### GET /mind/tasks\n\nList all tasks for the current mind.\n\n```bash\n# All tasks\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     https://synapse.schaefer.zone/mind/tasks\n\n# Filter by status\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/mind/tasks?status=pending\"\n\n# Field reduction (v1.44.19, task be0f9c80): default WITHOUT description —\n# payload fix 8.4 MB -> ~1.5 MB (3,100+ tasks). Per-task full text stays on\n# GET /mind/task/:id.\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/mind/tasks?fields=id,title,status,priority\"\n\n# Legacy full payload incl. description:\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/mind/tasks?fields=all\"\n```\n\n**Field reduction (v1.44.19):** Without `?fields=` the endpoint returns every\nfield EXCEPT `description` (descriptions are multi-KB per task and drove the\n8.4 MB responses with 5-25 s latency). `?fields=all` returns the full legacy\npayload; a comma list (`?fields=id,title,...`) returns exactly those fields —\ncamelCase input is normalised, unknown fields answer `400 invalid_fields`.\nPagination via `?limit=N` (1..2000) + `?offset=M` with `has_more` flag stays\nunchanged.\n\nResponse:\n\n```json\n{\n  \"tasks\": [\n    {\n      \"id\": \"task_001\",\n      \"title\": \"Deploy v1.5.0\",\n      \"description\": \"Push to production after CI green\",\n      \"priority\": \"high\",\n      \"status\": \"in_progress\",\n      \"due_at\": \"2026-06-28T...\",\n      \"created_at\": \"2026-06-27T...\"\n    }\n  ]\n}\n```\n\n### POST /mind/task\n\nCreate a new task.\n\n```bash\ncurl -X POST https://synapse.schaefer.zone/mind/task \\\n  -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"title\": \"Update documentation\",\n    \"description\": \"Add v1.5.0 changelog entries\",\n    \"priority\": \"normal\",\n    \"due_at\": \"2026-06-30T00:00:00Z\"\n  }'\n```\n\n### GET /mind/task (query params)\n\nCreate a task via GET (for URL-only tools).\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/mind/task?title=Test+task&priority=high\"\n```\n\n### PUT /mind/task/:id\n\nUpdate an existing task.\n\n```bash\ncurl -X PUT https://synapse.schaefer.zone/mind/task/task_001 \\\n  -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"status\": \"in_progress\",\n    \"description\": \"Currently deploying, CI is green\"\n  }'\n```\n\n> Ownership note: updating a task that is currently claimed by another mind\n> transfers the claim to the requesting mind — this is the sanctioned\n> takeover path (v1.14.7), intended for deliberate handovers, not accidents.\n\n### POST /mind/task/:id/claim\n\nClaim an unclaimed pool task for the current mind (atomic). GET variant exists\nfor URL-only tools.\n\n```bash\ncurl -X POST https://synapse.schaefer.zone/mind/task/task_001/claim \\\n     -H \"Authorization: Bearer YOUR_MIND_KEY\"\n```\n\n- Succeeds only while `mind_id IS NULL AND assignee_user_id IS NULL` inside the\n  same workspace (`owner_user_id` guard).\n- `409 not_claimable` names the current claimer (`claimed_by`); `404` if the\n  task does not exist; `403 claim_denied_role` for reader-role minds.\n- Claiming does NOT change `status` — a claimed `pending` task stays `pending`\n  until you `PUT {\"status\":\"in_progress\"}`.\n\n- Returns `409 not_claimable` if the task is already claimed or assigned to a\n  human — this endpoint intentionally never overrides a foreign claim. The\n  409 message points to the sanctioned takeover path above: a claimed task\n  CAN be taken over deliberately via `PUT /mind/task/:id` with a status update.\n\n### POST /mind/task/:id/release\n\nRelease a claim back to the open pool (self-release; human sessions may unclaim\nwithin their own workspace). Sets `auto_released_at` — the auto-assign cooldown\n(workspace `reminder_interval_h`, default 4 h) — and appends to\n`task_auto_release_history`. Teamlead/admin can release foreign claims via\n`POST /mind/task/:id/admin-release` (audit-pflichtig).\n\n### GET /mind/task/:id/complete\n\nMark a task as done.\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     https://synapse.schaefer.zone/mind/task/task_001/complete\n```\n\n### GET /mind/task/:id/delete\n\nDelete a task permanently.\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     https://synapse.schaefer.zone/mind/task/task_001/delete\n```\n\n## Priorities\n\n- `low` — non-urgent\n- `normal` — default\n- `high` — important\n- `critical` — must do immediately\n\n## Statuses\n\n- `pending` — created, not started\n- `in_progress` — currently being worked on\n- `done` — completed\n- `cancelled` — abandoned\n\n## Claim Consistency (v1.44.x audit, task 46534ca6)\n\nThere is **no separate claims index**: claim state lives exclusively in\n`agent_tasks.mind_id` on the single task row. The `409 not_claimable` payload\nand `GET /mind/task/:id` (`claimed_by`) read the SAME row.\n\nCode-audited guarantees (2026-10-26, Morpheus):\n\n- Every writer of `mind_id` bumps `updated_at`: claim, self/user release,\n  admin-release, auto-assign, PUT (binds `updated_at` first), complete.\n- Reminder sweeps touch only `reminded_at` / `stale_reminded_at` /\n  `auto_suggested_at` and never `mind_id` — a \"frozen `updated_at` with a\n  stale claim\" cannot be produced by application logic.\n\nInfrastructure caveat: reads go through pgbouncer (transaction pooling) in\nfront of the Patroni cluster. During failover windows a replica-facing backend\ncan briefly serve a stale row, so two consecutive reads may disagree (e.g.\n`claim` answers `409 claimed_by: X` while a later `GET` shows\n`claimed_by: null`). The class is transient and self-heals with replication;\nthe write path already retries transient connection/read-only errors once\n(pg-resilience, v1.44.4). If you hit a contradictory claim/GET pair: re-read\nafter 1-2 s and retry the claim — do not hard-assert an index divergence\nwithout comparing `updated_at` on both responses.\n\n## Pattern: Task-Driven Workflow\n\n```python\n# At session start\ntasks = list_tasks(status=\"in_progress\")\nif tasks:\n    print(f\"Resuming: {tasks[0].title}\")\n\n# Plan multi-step work\nfor step in plan:\n    task = create_task(title=step)\n\n# Update as you progress\nupdate_task(task.id, status=\"in_progress\")\n# ... do work ...\nupdate_task(task.id, status=\"done\")\n```\n\n## Next Steps\n\n- [Task-Driven Workflow](/docs/llm-cookbook/task-driven-workflow)\n- [Cron & Scheduler](/docs/api/cron)\n","contentHtml":"<h1>Tasks API</h1>\n<p>The Tasks API gives LLM agents a structured way to track multi-step work.\nTasks are scoped to the current mind and persist across sessions, so the agent\ncan resume work where it left off.</p>\n<p><strong>Emergency (v1.42.0, task 29a8d589, Michael #122782):</strong> <code>emergency</code> ranks above\n<code>critical</code>. Emergency tasks MUST get a claim immediately — an unclaimed\nemergency task triggers an automatic chat warning to @Hermes @Zeus (once per\ntask, <code>auto_suggested_at</code> guard). The board always sorts emergency tasks first,\nindependent of the selected sort mode.</p>\n<h2>Endpoints</h2>\n<h3>GET /mind/tasks</h3>\n<p>List all tasks for the current mind.</p>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># All tasks</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     https://synapse.schaefer.zone/mind/tasks\n\n<span class=\"hljs-comment\"># Filter by status</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/mind/tasks?status=pending&quot;</span>\n\n<span class=\"hljs-comment\"># Field reduction (v1.44.19, task be0f9c80): default WITHOUT description —</span>\n<span class=\"hljs-comment\"># payload fix 8.4 MB -&gt; ~1.5 MB (3,100+ tasks). Per-task full text stays on</span>\n<span class=\"hljs-comment\"># GET /mind/task/:id.</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/mind/tasks?fields=id,title,status,priority&quot;</span>\n\n<span class=\"hljs-comment\"># Legacy full payload incl. description:</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/mind/tasks?fields=all&quot;</span></code></pre><p><strong>Field reduction (v1.44.19):</strong> Without <code>?fields=</code> the endpoint returns every\nfield EXCEPT <code>description</code> (descriptions are multi-KB per task and drove the\n8.4 MB responses with 5-25 s latency). <code>?fields=all</code> returns the full legacy\npayload; a comma list (<code>?fields=id,title,...</code>) returns exactly those fields —\ncamelCase input is normalised, unknown fields answer <code>400 invalid_fields</code>.\nPagination via <code>?limit=N</code> (1..2000) + <code>?offset=M</code> with <code>has_more</code> flag stays\nunchanged.</p>\n<p>Response:</p>\n<pre><code class=\"hljs language-json\"><span class=\"hljs-punctuation\">{</span>\n  <span class=\"hljs-attr\">&quot;tasks&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">[</span>\n    <span class=\"hljs-punctuation\">{</span>\n      <span class=\"hljs-attr\">&quot;id&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;task_001&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;title&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;Deploy v1.5.0&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;description&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;Push to production after CI green&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;priority&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;high&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;status&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;in_progress&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;due_at&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;2026-06-28T...&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;created_at&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;2026-06-27T...&quot;</span>\n    <span class=\"hljs-punctuation\">}</span>\n  <span class=\"hljs-punctuation\">]</span>\n<span class=\"hljs-punctuation\">}</span></code></pre><h3>POST /mind/task</h3>\n<p>Create a new task.</p>\n<pre><code class=\"hljs language-bash\">curl -X POST https://synapse.schaefer.zone/mind/task \\\n  -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n  -H <span class=\"hljs-string\">&quot;Content-Type: application/json&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{\n    &quot;title&quot;: &quot;Update documentation&quot;,\n    &quot;description&quot;: &quot;Add v1.5.0 changelog entries&quot;,\n    &quot;priority&quot;: &quot;normal&quot;,\n    &quot;due_at&quot;: &quot;2026-06-30T00:00:00Z&quot;\n  }&#x27;</span></code></pre><h3>GET /mind/task (query params)</h3>\n<p>Create a task via GET (for URL-only tools).</p>\n<pre><code class=\"hljs language-bash\">curl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/mind/task?title=Test+task&amp;priority=high&quot;</span></code></pre><h3>PUT /mind/task/:id</h3>\n<p>Update an existing task.</p>\n<pre><code class=\"hljs language-bash\">curl -X PUT https://synapse.schaefer.zone/mind/task/task_001 \\\n  -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n  -H <span class=\"hljs-string\">&quot;Content-Type: application/json&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{\n    &quot;status&quot;: &quot;in_progress&quot;,\n    &quot;description&quot;: &quot;Currently deploying, CI is green&quot;\n  }&#x27;</span></code></pre><blockquote>Ownership note: updating a task that is currently claimed by another mind\ntransfers the claim to the requesting mind — this is the sanctioned\ntakeover path (v1.14.7), intended for deliberate handovers, not accidents.</blockquote><h3>POST /mind/task/:id/claim</h3>\n<p>Claim an unclaimed pool task for the current mind (atomic). GET variant exists\nfor URL-only tools.</p>\n<pre><code class=\"hljs language-bash\">curl -X POST https://synapse.schaefer.zone/mind/task/task_001/claim \\\n     -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span></code></pre><ul>\n<li><p>Succeeds only while <code>mind_id IS NULL AND assignee_user_id IS NULL</code> inside the\nsame workspace (<code>owner_user_id</code> guard).</p>\n</li>\n<li><p><code>409 not_claimable</code> names the current claimer (<code>claimed_by</code>); <code>404</code> if the\ntask does not exist; <code>403 claim_denied_role</code> for reader-role minds.</p>\n</li>\n<li><p>Claiming does NOT change <code>status</code> — a claimed <code>pending</code> task stays <code>pending</code>\nuntil you <code>PUT {&quot;status&quot;:&quot;in_progress&quot;}</code>.</p>\n</li>\n<li><p>Returns <code>409 not_claimable</code> if the task is already claimed or assigned to a\nhuman — this endpoint intentionally never overrides a foreign claim. The\n409 message points to the sanctioned takeover path above: a claimed task\nCAN be taken over deliberately via <code>PUT /mind/task/:id</code> with a status update.</p>\n</li>\n</ul>\n<h3>POST /mind/task/:id/release</h3>\n<p>Release a claim back to the open pool (self-release; human sessions may unclaim\nwithin their own workspace). Sets <code>auto_released_at</code> — the auto-assign cooldown\n(workspace <code>reminder_interval_h</code>, default 4 h) — and appends to\n<code>task_auto_release_history</code>. Teamlead/admin can release foreign claims via\n<code>POST /mind/task/:id/admin-release</code> (audit-pflichtig).</p>\n<h3>GET /mind/task/:id/complete</h3>\n<p>Mark a task as done.</p>\n<pre><code class=\"hljs language-bash\">curl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     https://synapse.schaefer.zone/mind/task/task_001/complete</code></pre><h3>GET /mind/task/:id/delete</h3>\n<p>Delete a task permanently.</p>\n<pre><code class=\"hljs language-bash\">curl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     https://synapse.schaefer.zone/mind/task/task_001/delete</code></pre><h2>Priorities</h2>\n<ul>\n<li><code>low</code> — non-urgent</li>\n<li><code>normal</code> — default</li>\n<li><code>high</code> — important</li>\n<li><code>critical</code> — must do immediately</li>\n</ul>\n<h2>Statuses</h2>\n<ul>\n<li><code>pending</code> — created, not started</li>\n<li><code>in_progress</code> — currently being worked on</li>\n<li><code>done</code> — completed</li>\n<li><code>cancelled</code> — abandoned</li>\n</ul>\n<h2>Claim Consistency (v1.44.x audit, task 46534ca6)</h2>\n<p>There is <strong>no separate claims index</strong>: claim state lives exclusively in\n<code>agent_tasks.mind_id</code> on the single task row. The <code>409 not_claimable</code> payload\nand <code>GET /mind/task/:id</code> (<code>claimed_by</code>) read the SAME row.</p>\n<p>Code-audited guarantees (2026-10-26, Morpheus):</p>\n<ul>\n<li>Every writer of <code>mind_id</code> bumps <code>updated_at</code>: claim, self/user release,\nadmin-release, auto-assign, PUT (binds <code>updated_at</code> first), complete.</li>\n<li>Reminder sweeps touch only <code>reminded_at</code> / <code>stale_reminded_at</code> /\n<code>auto_suggested_at</code> and never <code>mind_id</code> — a &quot;frozen <code>updated_at</code> with a\nstale claim&quot; cannot be produced by application logic.</li>\n</ul>\n<p>Infrastructure caveat: reads go through pgbouncer (transaction pooling) in\nfront of the Patroni cluster. During failover windows a replica-facing backend\ncan briefly serve a stale row, so two consecutive reads may disagree (e.g.\n<code>claim</code> answers <code>409 claimed_by: X</code> while a later <code>GET</code> shows\n<code>claimed_by: null</code>). The class is transient and self-heals with replication;\nthe write path already retries transient connection/read-only errors once\n(pg-resilience, v1.44.4). If you hit a contradictory claim/GET pair: re-read\nafter 1-2 s and retry the claim — do not hard-assert an index divergence\nwithout comparing <code>updated_at</code> on both responses.</p>\n<h2>Pattern: Task-Driven Workflow</h2>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-comment\"># At session start</span>\ntasks = list_tasks(status=<span class=\"hljs-string\">&quot;in_progress&quot;</span>)\n<span class=\"hljs-keyword\">if</span> tasks:\n    <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">f&quot;Resuming: <span class=\"hljs-subst\">{tasks[<span class=\"hljs-number\">0</span>].title}</span>&quot;</span>)\n\n<span class=\"hljs-comment\"># Plan multi-step work</span>\n<span class=\"hljs-keyword\">for</span> step <span class=\"hljs-keyword\">in</span> plan:\n    task = create_task(title=step)\n\n<span class=\"hljs-comment\"># Update as you progress</span>\nupdate_task(task.<span class=\"hljs-built_in\">id</span>, status=<span class=\"hljs-string\">&quot;in_progress&quot;</span>)\n<span class=\"hljs-comment\"># ... do work ...</span>\nupdate_task(task.<span class=\"hljs-built_in\">id</span>, status=<span class=\"hljs-string\">&quot;done&quot;</span>)</code></pre><h2>Next Steps</h2>\n<ul>\n<li><a href=\"/docs/llm-cookbook/task-driven-workflow\">Task-Driven Workflow</a></li>\n<li><a href=\"/docs/api/cron\">Cron &amp; Scheduler</a></li>\n</ul>\n","translationsAvailable":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"]}