todo → doing → done | cancelled and back. A proposal waits in review until its reviewer decides it: see Propose, Report and Decide. Every route by id takes the task id (a UUID) in the path and returns the task in data, in the shape shown on Get Task (with its latest round, approved round and links). The verbs are all POST and answer 200.
Every write needs task-write access in the task’s workspace (an internal member who is not a viewer, or an external editor; internal tasks need internal membership). Every change increments the task’s revision. Every route takes why in its body: one sentence on what the person is trying to accomplish, in their terms (not a description of the edit). An agent call without it is 400 WHY_REQUIRED. See Why on every write.
Auth: Authorization: Bearer tr_...
Every transition is a single conditional update. The guard is in the
WHERE clause and the row count is the verdict, so two harnesses racing for one task resolve at the database. You never have to check, then act: call the verb and branch on the error.doing task has one holder: an agent key under a lease, or the person in the browser, whose hold has no lease. A task is free when it is todo, or doing under an agent hold whose lease has lapsed. A hold is yours when you are its exact holder: the same account and the same agent key.
PATCH /v0/tasks/{id}
Edit a task’s text, tags, links, assignee and reviewer, or its audience. payload, due and the parent are fixed at creation.
While a task is In review, a new
reviewer re-addresses the open review (never to its proposer: 400 INVALID_REVIEWER), and a new assignee is whom a send back returns the task to. Changing the audience clears an assignee or reviewer who can no longer work the task, stops a hold whose holder can no longer see it, and withdraws an open proposal whose proposer can no longer see it.
rip task update <id> --expected-revision 3 --step draft --link url:https://example.com/changelog (--no-type and --no-step clear a tag; --remove-link artifact:<id> removes one).
POST /v0/tasks/start
Start by tags (agent keys only): take the oldest To do task in a workspace that matches the tags, in your audiences, and start it under your lease, in one statement. Two agents starting at once never get the same task.
It never takes a task for another agent or another person, nor one In review, Doing, Done or Cancelled. A lapsed Doing hold returns to To do through the lease sweep before it can be taken. Use no tag for your own queue, and the tags with the step for routine work: a type alone also matches an approved task waiting at the next step.
rip task start --workspace-id content --type article --step draft (prints “No task” when none matches). MCP: task_start { workspaceId, type?, step?, leaseHours?, why }; task_start { id } starts by id, and an input naming both is refused.
Returns 200 with { "task": … }: the task with its latest round whole (a sent-back round’s comment says what to change) and its approved round (approvedRound.final, exactly what to carry out), or { "task": null } when nothing matched, or when a match was locked for a moment by another write to it. Nothing is recorded then; try again later. A person starts a task by its id.
POST /v0/tasks/{id}/start
Take a free task by its id so nobody else works it in parallel. The hold belongs to your key and carries a lease. Starting a task you already hold renews the lease, never shortening it, and records no event. Assignment is advisory: you may start a task for someone else by its id.
Starting a task whose agent lease has lapsed takes it over. The response carries the resolved
holder.leaseExpiresAt; advertise that, not the value you asked for.
rip task start <id> --lease-hours 4.
POST /v0/tasks/{id}/stop
Put a doing task back in todo so someone else can take it. The holder may stop their own hold; a workspace admin may stop anyone’s, which the change feed records as an override. In the dashboard, the person may also stop a hold of their own agent.
On a task In review on your own proposal (or, for the person, their own agent’s), stop withdraws it: the round closes withdrawn and the task goes back to To do, still for whoever it was for. Use it to take a proposal back without cancelling the task.
CLI: rip task stop <id>.
POST /v0/tasks/{id}/complete
Close the task with what came of it. Completion is always explicit, and works from todo as well as doing: on a free task, or on your own hold (even after its lease lapsed, while nobody has taken it over). You do not need to start a task to complete it. On an approved task, carry out exactly approvedRound.final before completing.
rip task done <id> --result-text "Posted on X and LinkedIn" --link url:https://x.com/acme/status/1 --link artifact:b7e1c9a2-3f4d-4e5a-8b6c-7d8e9f0a1b2c@2.
POST /v0/tasks/{id}/cancel
Close the task without doing it: noise, a duplicate, no longer relevant. Works on a todo, doing or review task and clears any hold in the same statement. On an In review task, cancel is how to say no to the proposal: its round closes cancelled, decided by you, and the reason is the task’s cancelReason. Only its proposer (the same agent key), the proposer’s person in their own browser, or whoever may decide it can. To ask for changes instead, send it back with a comment; to withdraw your own proposal and keep the task, stop it.
CLI:
rip task cancel <id> --reason "Duplicate" [--expected-revision <n>].
POST /v0/tasks/{id}/reopen
Bring a done or cancelled task back to todo. A task whose proposal was cancelled In review, and that is still for its proposer, goes back to review instead, on a new round carrying the same draft, to be decided afresh, whoever cancelled it. Reopening clears the approved round (an approval is spent once used), the completer and the cancellation; every round, the result text and the links stay. It also clears an assignee who can no longer work the task.
CLI: rip task reopen <id>.
Errors on every route
Leases lapse on their own
A sweep runs every minute and returns any task whose agent lease has expired totodo, attributed to the platform rather than to a person. A lapsed lease is not a failure: the work is available again. Before the sweep reaches it, a lapsed hold is already free: anyone may start it by id or complete it. A person’s hold in the browser has no lease and never lapses.
Operator mirror
Every route by id has a mirror under/v0/operator/tasks/{id} (and the person’s decide) with the same guards, using an operator session that acts as the bound account and takes no why. POST /v0/operator/tasks/{id}/start takes no body and no lease (a leaseHours is refused): the person’s hold reads inBrowser: true with surface: "dashboard" unless the X-Tokenrip-Surface header names the caller. Start by tags has no operator mirror.