Skip to main content

Tasks API

Trackable work items assigned to users or Agents. Shipped as a plugin capability per ADR-013; the first-party Ever Works Task Tracker plugin is a thin shim over the platform's own DB-backed implementation. Community plugins (Linear / Jira / GitHub Issues) drop in by implementing the same ITaskTrackerPlugin contract.

All routes are @CurrentUser()-scoped. Cross-user reads return 404.

CRUD

MethodPathDescription
GET/api/tasksList with filters (status, priority, scope, label, search). Paginated.
POST/api/tasksCreate a Task. (60/min)
GET/api/tasks/:idGet one.
PATCH/api/tasks/:idUpdate fields. (60/min)
DELETE/api/tasks/:idDelete (cascades to side rows). (30/min)

Transitions

State machine — see TaskTransitionService:

backlog → todo / cancelled
todo → in_progress / blocked / cancelled
in_progress → in_review / blocked / done / cancelled
in_review → in_progress / blocked / done / cancelled
blocked → todo / in_progress / cancelled
done → in_progress (reopen)
cancelled → (terminal)

→ done requires:

  1. No open blockers (integrity — force=true does NOT override).
  2. When requireAllApprovers=true, all approvers must be approved (policy — force=true DOES override).
MethodPathDescription
POST/api/tasks/:id/transitionBody: {to, force?}. (60/min)

Members

MethodPathDescription
POST/api/tasks/:id/assigneesAdd {assigneeType, assigneeId}. (60/min)
DELETE/api/tasks/:id/assignees/:assigneeIdRemove one.
POST/api/tasks/:id/reviewersAdd a reviewer.
POST/api/tasks/:id/approversAdd an approver.
POST/api/tasks/:id/blocksAdd {blockedByTaskId}.
DELETE/api/tasks/:id/blocks/:blockIdRemove a blocker.
POST/api/tasks/:id/relationsAdd {relatedTaskId, kind}related / duplicates / follow-up.

Chat

MethodPathDescription
GET/api/tasks/:id/chat?limit=&offset=Paginated chat thread (newest last).
POST/api/tasks/:id/chatPost a message. Body secret-scanned, 16 KB cap. Mention parser strips unknown @ tokens server-side (T6 mitigation). (60/min)
PATCH/api/task-chat-messages/:idEdit within 5 min of createdAt. Past the window returns 403. (60/min)

Recurring tasks (Phase 17)

MethodPathDescription
POST/api/tasks/:id/recurringBody: {recurrenceRule, recurrenceTimezone?, recurrenceEndsAt?, recurrenceMaxOccurrences?}. RRULE per RFC 5545. (30/min)
DELETE/api/tasks/:id/recurringStop recurrence on a template. Existing spawned instances are kept.

The task-recurrence-dispatcher Trigger.dev cron walks templates where nextOccurrenceAt <= now, CAS-claims each one, clones a fresh instance via cloneRecurringTaskAsInstance, and advances nextOccurrenceAt to the next computed slot.

Spend

MethodPathDescription
GET/api/tasks/:id/spend?since=&until=&currency=Per-Task spend rollup in cents.

Backed by PluginUsageRepository.getTotalSpendCentsForTask() over the plugin_usage_events.taskId column (Phase 11.4 migration adds the column + index).

Notes

  • Slugs are generated atomically per-user (UserTaskCounter) as T-<n>.
  • Activity-log rows: TASK_CREATED / UPDATED / DELETED / TRANSITIONED / ASSIGNEE_ADDED / ASSIGNEE_REMOVED / BLOCKER_ADDED / BLOCKER_REMOVED / ASSIGNED / COMMENTED / COMPLETED / RECURRENCE_FIRED.
  • → in_progress with any Agent assignee fan-outs to the agent-task-execute Trigger.dev runs (Phase 15.3). @<agent-slug> mentions in chat fan-out to agent-chat-reply (Phase 15.4). Both dispatch hooks are failure-tolerant — the platform write succeeds even if the Trigger.dev runtime is unavailable.