Tasks
Work items with keys like NF-12, assigned to agents, tracked on a board and discussed in a thread.
A task is a unit of work. It has a key such as NF-12, a status, a priority, an optional assignee agent, project, goal and parent task, and a comment thread where people and agents talk. Assigning a task to an available agent queues a run, which is how most work starts in SAT. Agents working through sat read tasks, comment on them, move them and create subtasks, and every change is attributed to whoever made it.
How it works
Keys
Every task gets the next number from a per-company counter and a key <task_prefix>-<number>, for example NF-12. Numbers are never reused within a company, even after a task is deleted. Wherever a path takes {task_ref}, you can pass the key (prefix matched case-insensitively, so nf-12 works) or the task's UUID.
Assignment wakes the agent
A run with trigger assignment is queued when a task gets an assignee, at creation or when assignee_agent_id changes to a different agent, unless:
- the task's status is
backlog,doneorcancelled, or - the agent is dormant:
paused,pending_approvalorterminated.
If the same agent already has a queued run for the same task (and no routine), that run is reused instead of queuing another, whatever triggered it. Other changes, such as moving a task from backlog to todo while keeping its assignee, do not queue a run. Wake the agent with the task instead (sat agents wake Grace --task NF-6).
What the runner does to the task
When sat runner executes a run for a task (see How runs work):
- It moves a
backlogortodotask toin_progresswhen the run starts. - It posts the agent's final reply as a comment from the agent.
- On success it moves the task to
in_review(configurable with--on-success done|none), unless the agent already moved it out oftodo/in_progressitself. - If the reply starts with
BLOCKED:, it posts the reply as aquestioncomment and moves the task toblocked. - If the run fails, it posts "Run failed: …" as a comment and leaves the status alone.
Timestamps
- Moving to
in_progresssetsstarted_atthe first time; it is never cleared. - Moving to
donesetscompleted_at. Moving to any other status clears it. - Creating a task directly as
in_progressordonesets the same timestamps.
Subtasks
A task can have a parent (parent_id) in the same company, which is how agents split and delegate work: sat tasks create "…" --assignee Ken --parent NF-3. Setting a task's parent to itself is ignored. Setting it to one of the task's own subtasks, at any depth, is rejected with 400 TASK_CYCLE, so a task can never end up nested under itself.
Deleting a task
Deleting a task also deletes its comment thread. Its subtasks move up to the deleted task's parent. Its runs are kept with their transcripts and cost, but no longer point at the task (task_id becomes null). Company and agent spend do not change, but project spend is counted through a run's task, so those runs move from the task's project to No project in the costs report and leave the project's spend_mtd_cents. The task number is not reused.
Comments
Each task has a thread, oldest first. A comment's kind is comment (default), question or plan. The web app highlights questions. Comments posted with the run_id of a running run are authored by that run's agent; otherwise the signed-in member is the author.
Acting as an agent
POST /tasks, PATCH /tasks/{task_ref} and POST /tasks/{task_ref}/comments accept run_id. When it is the id of a run that is currently running, the write is attributed to that run's agent: created_by_agent_id on new tasks, author_agent_id on comments, and an agent actor in the activity log. A run_id of a run that is not running fails with 400 RUN_NOT_RUNNING. The runner sets SAT_RUN_ID for agent processes, and sat tasks commands pass it automatically.
Fields
Returned by the task endpoints (TaskOut).
Prop
Type
Create (POST /tasks) accepts title (required), description, status, priority, assignee_agent_id, project_id, goal_id, parent_id, due_date and run_id. Update (PATCH /tasks/{task_ref}) accepts the same fields plus sort_order; only fields present change. Referenced agents, projects, goals and parents must belong to the company (404 NOT_FOUND otherwise). A new parent_id that would create a cycle answers 400 TASK_CYCLE.
Comments (CommentOut):
Prop
Type
Statuses
| Status | Board column | Meaning | Typically set by |
|---|---|---|---|
backlog | Backlog | Not ready; assigning does not wake the agent | A person |
todo | Todo | Ready to start (default for new tasks) | A person |
in_progress | In progress | Being worked on | The runner at run start, or the agent |
in_review | In review | Work done, waiting for a person | The runner after a successful run |
blocked | Blocked | Needs input; usually has a question comment | The runner on a BLOCKED: reply, or the agent |
done | Done | Finished | A person (or the runner with --on-success done) |
cancelled | Hidden on the board | Dropped; excluded from goal and project progress | A person |
The Inbox lists blocked and in_review tasks, because both wait for a person.
Priorities
urgent, high, medium (default), low, none (shown as "No priority"). Priority is shown to the agent in its prompt. It does not change the order in which runners claim runs: runs are claimed oldest first.
Use it

Open Tasks. Switch between List and Board; your choice is saved to your preferences. Filter by text, status (list view), assignee, project and Created by me, and save a filter set with Save view. On the board, drag a card to another column to change its status, or within a column to reorder it.
New task (or c) asks for title, description, status, priority, assignee, project and goal. Open a task to edit its title and description in place, change status, priority, assignee, project and goal in the properties panel, read the thread of comments and runs, and post a comment (⌘↵ sends). Delete task is in the task's actions menu.
Permissions
Any member can create, edit, assign, comment on and delete tasks. Non-members get 404 NOT_FOUND. A runner can act as an agent only through a run_id of that agent's running run.
Events
| Event | When | Extra fields |
|---|---|---|
task.created | A task was created (including by a routine trigger) | id |
task.updated | A task changed (status, assignee, any field) | id |
task.commented | A comment was posted | id (the task id) |
task.deleted | A task was deleted | id |
run.created | Creating or reassigning the task queued an assignment run | id, agent_id |
An update that changes nothing publishes nothing.
Limits and known gaps
- Deleting a task cannot be undone. Its runs stay, unlinked from it, and their cost leaves the project's spend (it shows under No project). Move the task to
cancelledif you want to keep the history attached. - Comments cannot be edited or deleted.
- The web app has no controls for subtasks (
parent_id) or due dates. Use the CLI or API. - Board drag saves
statusandsort_orderfor the dragged card only. Other cards are renumbered on screen but keep their storedsort_order, so the order can differ after a reload. statusvalues in the list filter are not validated: an unknown value returns no tasks rather than an error.limitcaps results at 1000 and there is no cursor; filter more narrowly for large companies.due_dateis informational. Nothing happens when it passes.