Skip to main content

Draft — needs review

The six verbs that move a task through open → claimed → done | dismissed and back. All are POST, all answer 200, all take the task id in the path. 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 — just call the verb and branch on the error.

POST /v0/tasks/{id}/claim

Take the task and hold a lease. Re-claiming your own extends it. Succeeds when the task is open, when you already hold it, or when someone else’s lease has lapsed (a takeover). The response names the resolved leaseExpiresAt — advertise that, not the value you asked for. In personal scope there is no claim protocol at all: claim is a no-op that returns the row unchanged.

POST /v0/tasks/{id}/touch

Extend the lease you hold. Monotonic — it can only move the expiry forward, so a deliberately long lease survives a shorter session’s touch.

POST /v0/tasks/{id}/release

Give the claim back. The task returns to open. A team owner may release anyone’s claim; everyone else may only release their own.

POST /v0/tasks/{id}/complete

Close the task and attach what it produced. In personal scope a task completes straight from open — no lease condition.

POST /v0/tasks/{id}/dismiss

Close the task without doing it. Clears any claim in the same statement.

POST /v0/tasks/{id}/reopen

Bring a done or dismissed task back to open. Its results are kept — status is the truth, not the result set.

Leases lapse on their own

A sweep runs every minute and returns any task whose lease has expired to open, attributed to the platform rather than to a person. A lapsed lease is not a failure — it means the work is available again.

Operator mirror

Every verb has a mirror under /v0/operator/tasks/{id}/… with the same guards.