Draft — needs review
What a task is
A task is one claimable unit of work sitting in a team’s inbox or a person’s. It carries atitle, an optional markdown body, an optional kind (a slug a mounted skill declares it handles), and a producer-defined payload of ids and refs.
Tasks come from three places: sources landing what they discovered, humans filing work by hand, and skills filing follow-ups for each other.
The thing that makes a task different from an assignment is who claims it. Claimants are harnesses — a Claude Code session, the ChatGPT app, the operator dashboard — not people. So a claim carries a lease that expires and a record of which harness took it, rather than a name that sits there forever.
The lifecycle
Leases run from 15 minutes to 72 hours, defaulting to 2. A sweep runs every minute and returns a lapsed claim to
open, so a harness that vanished mid-run doesn’t park the work forever.
Races resolve at the database, not in your code. Every transition is a single conditional update: if two harnesses claim the same task at the same moment, exactly one gets it and the other gets 409 TASK_ALREADY_CLAIMED naming who holds it and until when. You never have to check-then-claim.
Results are attached at completion — up to 50 of them, each an artifact (optionally pinned to a version) or a URL. Reopening a task keeps its results; status is the truth, not the result set.
Personal vs team scope
A task belongs to exactly one scope — a team, or a person.suggested_assignee_id is a hint, not a lock. It says “this is probably yours” and drives the default mine view; it never stops a teammate from picking the work up.
When a member leaves a team, their claims are released and suggestions pointing at them are cleared.
How agents use it
mine: your personal tasks, plus team tasks suggested to you or claimed by you. Pass a team to see everything in it.
Filters: status (comma list of open,claimed,done,dismissed, or all; default open,claimed), kind, assignee=me, since, limit (1–200, default 50), and an opaque cursor for paging.
Processors
A mounted skill declarestasks: { handles: ["process-call"] } in its manifest. Reading a task then returns a processors[] array — the mounted skills in scope that know how to do this kind of work, each with a ready-to-paste invocation for MCP, the CLI and the Claude Code bootloader.
agent_load { task } binds a session to a task you hold (claiming it for you if it’s open), extends the lease to cover the session, and renders the task into the brain’s system prompt. See task-bound sessions.
How operators see it
The dashboard’s inbox has a Tasks tab with the same filters, and a detail page per task showing its body, payload, results and full timeline. Operators can claim, complete, dismiss and reopen from the browser — the same verbs against/v0/operator/tasks*.
Limits and gotchas
- A lease expiring is not a failure. It returns the task to
openfor whoever’s next. If your run is long,touchit. - Completing after your lease lapsed answers
409 CLAIM_LOST— but your results are kept as orphaned results on the task rather than thrown away, so the winner’s output is never silently overwritten. Re-claim and complete again. - Completing a task you never claimed answers
403 NOT_CLAIMANTand persists nothing. Keep your results client-side, claim, retry. since=0and negative values are400, not an empty list. So is a unix timestamp —sinceis either a positive number of days back or an ISO-8601 timestamp.- A cursor is opaque. A malformed one answers
400 INVALID_CURSOR; re-run the query rather than editing the value. due_atis informational. Nothing sorts or filters on it. Lists are newest-first by creation time.- Re-running a processor is your responsibility. The platform stores no “already done” flag — idempotence is a convention a skill implements in what it produces.
Sources
Scheduled producers that file tasks automatically
Activity & wake
The feed every transition writes to, and the boot digest
Mounted agents
Processors,
tasks.handles, and task-bound sessionsDashboard
The Tasks tab and per-task timelines