Agents
Task data model (for agents)
The Tasks/MCP data model an agent needs to read the board correctly: entities, id spaces, status vs workflow state, task routing, and the cyborg7_* tool map.
Read this before driving the Tasks board through the cyborg7_* MCP tools. It describes the shape of the data. For the user-facing walkthrough see Create & track tasks. It covers the facts an agent most often gets wrong by guessing: id prefixes, status vs state, and where a task lands.
Entities and relationships
flowchart TD W[workspace] --> P["Tasks-project (tasks_projects, 1:1 with a chat project)"] P --> T["task (tasks)"] T --> S["workflow state (task_states): the board column"] T --> L["labels (per-project catalog, by name)"] T --> A["assignee (a human userId or an agent id)"] T --> C["channel (optional scope)"] T --> PT["parent task (optional, makes it a sub-task)"] T --> CM["cycle / modules (optional, sprint / grouping)"]
- A Tasks-project (
tasks_projects) is the bucket a task is filed under. Each one is linked 1:1 to a chatproject, and its displayname/identifiercome from that chat project. - The Inbox is a synthetic Tasks-project (
isInbox: true, no linked chat project). A task created with no project lands here. Inbox tasks are hidden from the per-project boards. - A task always belongs to exactly one Tasks-project, has one workflow state (its board column), and optionally an assignee, labels, parent, channel, and cycle.
Id spaces
Resolve ids by lookup, never by prefix. Four id spaces show up in the tools. They are not interchangeable, and you cannot build one from another by string manipulation.
| Id | Belongs to | Where you get it | Where it’s used |
|---|---|---|---|
tp_… | Tasks-project (tasks_projects.id) | cyborg7_list_projects → id | list_states(projectId), list_tasks({projectId}), create_task.projectId, update_task.projectId |
task… / uuid | Task (tasks.id) | leading token of each list_tasks line; create_task’s return | every task mutation (update_task, get_task, archive_task, delete_task, bulk_update_tasks) |
| state id | Workflow state (task_states.id) | cyborg7_list_states(projectId) → id | update_task.stateId / bulk_update_tasks.stateId (also accepts the state name) |
#N | Per-project sequence (sequence_id) | shown after the id in lists (… (#12)) | display only, not accepted by any mutation |
The Plane-style display key (for example CYBORG-181, the id you see on the board) is tasks_projects.identifier + "-" + sequence_id: the project’s short prefix (cyborg7_list_projects → identifier) joined to the #N above. You don’t have to build it by hand: cyborg7_get_task returns it as key, alongside the raw sequence_id. It is display only and never accepted by a mutation, same as #N.
status vs state
The board renders columns by the workflow state’s group. state.group is one of backlog | unstarted | started | completed | cancelled.
Legacy tasks.status is a one-way mirror derived from state.group. You read it, but the state is what places the card:
| Column | state.group | stored status (the mirror) | status inputs that land here |
|---|---|---|---|
| Backlog | backlog | pending | backlog |
| Todo | unstarted | pending | todo, pending |
| In Progress | started | in_progress | in_progress |
| Done | completed | done | done |
| Cancelled | cancelled | cancelled | cancelled |
Two consequences:
- The Todo column stores
status: "pending", and so does Backlog.todois only an input alias (it maps to the Todo/unstartedcolumn) and is never a stored value. A freshly placed task never reads back astodo. - The full set of
statusvalues you can filter on or set isbacklog | todo | pending | in_progress | done | cancelled. There is nopending_review.
Moving a card
- Preferred: set
stateIdonupdate_task. It takes an exact state id or name (case-insensitive) fromcyborg7_list_states. Thestatusmirror is then re-derived from the state’s group.stateIdwins if you pass both. - Or set
status(nostateId): it moves the card. It resolves to the target group (per the table above) and lands on that column’s default state (else its lowest-sequence state). If the task has no project/state catalog, it falls back to updatingstatusonly.
If a stateId doesn’t resolve, the tool returns an error telling you to call cyborg7_list_states(projectId). Call it instead of retrying.
This status→state resolution is enforced on every task-update surface: cyborg7_update_task/cyborg7_create_task (this agent tool set) and the separate workspace-API-token MCP surface’s update_task/create_task (a different integration point for external MCP clients) all resolve state_id from a status-only change instead of writing the legacy status mirror alone. A status-only update always moves the real board column. It is never a silent no-op.
Task routing
cyborg7_create_task needs exactly one of these to resolve a project (checked in order):
projectId(atp_…id fromlist_projects): files the task under that Tasks-project.channelId: files it under that channel’s Tasks-project (falling back to the workspace Inbox if the channel has none). A channel-bound agent auto-uses its channel when you pass none.parentId: the new task inherits its parent’s project (a sub-task).
A create with none of the three is rejected with “provide projectId or channelId”. When a task ends up with no project it lives in the Inbox (project_id null), hidden from project boards.
Invocation triggers
An agent runs a turn when one of these fires:
- @-mention in a channel it is a member of: mention it by slug, name, or
cybo:<id>. Human mentions always invoke. An agent’s own mention can also invoke another agent, but chaining is bounded (a fan-out limit per message, a total spawn budget per chain, and a depth clamp). Membership is required. Mentioning a non-member returns a private “add it first” notice. - DM: a direct message to the agent runs a private turn framed as a DM.
- Channel watcher: when a channel has auto-tasks turned on, its watcher agent reads new human messages (with recent transcript) and acts without being @-mentioned (for example turning “we still need to fix the login bug” into a task). Opt-in, off by default.
- Schedule (cron): a recurring or one-shot autonomous run set up via
cyborg7_schedule_create. Requires the spawn-agents capability and an online workspace daemon.
See Invoke an agent, Mention or notify someone, and Schedule a recurring job.
Task tool map
| Tool | Use it to |
|---|---|
cyborg7_list_projects | Find Tasks-projects; get each { id (tp_…), identifier, name, color, isInbox }. The id is create_task’s / filter’s projectId. |
cyborg7_list_states | List a project’s workflow states (board columns) as { id, name, group, isDefault, sequence }: get a stateId/name before moving a card. |
cyborg7_list_tasks | List/filter tasks (status, assignee, projectId, state, priority, label). Each line starts with the task id and shows state:Name (id) + project:<tp_…>. |
cyborg7_get_task | Read ONE task in full: { id, sequence_id, key, title, description, status, state:{id,name,group}, projectId, assigneeId, priority, labelIds, moduleIds, dueAt }. key is the Plane display id (e.g. “CYBORG-181”). |
cyborg7_create_task | Create a task. Route it with projectId, channelId, or parentId (else rejected). |
cyborg7_update_task | Change any field. stateId (id or name) moves the card (preferred); status also moves it; omitted fields are unchanged. |
cyborg7_bulk_update_tasks | Apply the same patch to many task ids at once (e.g. mark a batch done, reassign). |
cyborg7_archive_task | Hide a finished task (reversible: archived=false restores). |
cyborg7_delete_task | Permanently delete a task (irreversible, so prefer archive). |
cyborg7_get_workspace_roster | All members + agents with ids ([human] name (role): <userId> / [agent] name: <agentId>) to @mention or assign. |
cyborg7_list_channel_members | Members of one channel with ids. Resolve a name → id before mentioning. |
cyborg7_list_pages / cyborg7_read_page | List a project’s pages (id, title, parentId) and read one page’s content. |
cyborg7_create_page / cyborg7_update_page / cyborg7_nest_page | Create a page (optionally under a parent), edit its title, body or icon, or move it under another page. |
cyborg7_schedule_create / _list / _get / _update / _set_enabled / _delete | Manage recurring or one-shot runs of an agent (see the Schedule trigger above). |
cyborg7_read_docs | Read these end-user guides (nav / search / get <slug>) to answer a “how do I…?” question. |