The agenttask.* family (19 verbs). Every verb enters through the one front door: it is capability-checked, permission-checked, scope-checked and audited before it runs (see Security & permissions). Each entry below lists its capability, risk class (which fixes the minimum autonomy level), the minimum caller permission, its availability tier, whether it is idempotent, and any outbound egress.
Cancelagenttask.cancel
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Sensitive - autonomy L2 |
| Min. permission | Admin |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
([2026] VJS-CC-OPBOX 55). Cancel a NON-TERMINAL agent task
(QUEUED/LEASED/ESCALATED) - the operator/parent-kill path the break-glass + bulk-cancel sites compose
(SEC-F08: org.freeze/org.lockdown abort in-flight work via agenttask.cancel). A guarded CAS
WHERE status NOT IN ('DONE','FAILED','CANCELLED') flips status->CANCELLED + stamps finished_at (the
ck_agent_task_terminal backstop: finished_at is set IFF terminal) and clears the lease lifecycle (a
cancelled task holds no lease). An ALREADY-TERMINAL task (DONE/FAILED/CANCELLED) is refused (fail-closed
Conflict, INV-3 - you cannot cancel completed/failed/already-cancelled work; CANCELLED is itself terminal
so a re-cancel is the same Conflict, never a silent no-op). One AuditEvent (the dispatch appends it,
INV-8). Workspace-scoped (RLS + the explicit predicate).
Input { taskId } (fields ending in ? are optional)
Call POST /v/agenttask.cancel with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.cancel.
Checkpointagenttask.checkpoint
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
Persists the durable agent state +
renews the lease (heartbeat). Only the LEASE HOLDER may checkpoint (the guard pins lease_owner +
status=‘LEASED’), so a stale/foreign worker cannot overwrite a re-leased task’s state. An optional
terminal status (DONE|FAILED) marks completion, stamping finished_at (INV-3) - the ONE write path
to a terminal task. A non-terminal checkpoint loops the task back to LEASED with a fresh lease.
CC-OPBOX 32 B3 - two changes on the non-terminal renewal path:
• heartbeat-only - checkpoint is now OPTIONAL: a pure lease renewal with no payload keeps the
existing checkpoint (the worker is alive but has nothing new to persist). A terminal call still
requires nothing extra; only the prior unconditional “requires a checkpoint” BadInput is lifted.
• LEASE_RUNAWAY guard - each non-terminal renewal increments lease_extensions; once it would
exceed MAX_LEASE_EXTENSIONS (4) OR now()-first_leased_at exceeds LEASE_WALLCLOCK_CAP_SECONDS the
renewal is REFUSED and the task is FORCE-REQUEUED (status=QUEUED, lease lifecycle cleared) as a
fail-closed LEASE_RUNAWAY Conflict - a wedged worker cannot hold a task forever (the cooperative
floor; the re-drive resumes from the last persisted checkpoint). A TERMINAL checkpoint is exempt
(it ENDS the lease; the count is irrelevant) and never trips the guard.
Input { taskId, checkpoint?, status?, lastError? } (fields ending in ? are optional)
Call POST /v/agenttask.checkpoint with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Clearagenttask.checkpoint.clear
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
Delete every checkpoint for a task (post-success/abandon).
{ taskId }. Idempotent (0 rows = success). DEFERRED (built, not wired).
Call POST /v/agenttask.checkpoint.clear with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.checkpoint.clear.
Pruneagenttask.checkpoint.prune
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Admin |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
(AdminOnly/system). GLOBAL retention sweep of checkpoint rows
older than the cutoff (workspace-agnostic - PLATFORM scope, NOT ctx.workspace_id; agent.md FLAG). { olderThanDays?:int (default 30) }. DEFERRED (built, not wired): Class-1 cron, bearerless + platform scope.
Call POST /v/agenttask.checkpoint.prune with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Writeagenttask.checkpoint.write
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
Append a per-phase resume checkpoint; phase_index is assigned
monotonically per task inside the tx (an advisory xact lock serialises concurrent lease-handoff writers).
{ taskId, phaseKey, state(json, <=1MiB), outputs(json[]) }. DEFERRED (built, not wired).
Call POST /v/agenttask.checkpoint.write with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.checkpoint.write.
Claimagenttask.claim
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
The guarded UPDATE ... WHERE status='QUEUED' RETURNING is the single
source of truth for “did I win the lease” (TOCTOU-safe, INV-4 style - the same discipline as
gate.apply + review.claim). rows_affected==0 ⇒ the task is not QUEUED (a concurrent winner already
leased it, or it is ESCALATED/terminal) ⇒ Conflict (no double-claim). The lease_owner + expiry +
heartbeat are written; the payload + checkpoint are RETURNED so the worker resumes from where it was.
Input { taskId } (fields ending in ? are optional)
Call POST /v/agenttask.claim with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Claim Nextagenttask.claimNext
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
Implements CC-OPBOX 18 C1(i) / 20 D1’s ratio - “the agent CLAIMS THE QUEUE
over MCP” - so the caged AGENT seat self-drains (CC-OPBOX 22, Position A) without an operator handing it a
taskId (agenttask.list is ADMIN, so a MEMBER seat cannot enumerate). Atomically claims the OLDEST QUEUED
task it is ALLOWED to run (optionally filtered to a carrier verb, e.g. agent.run): the WHERE pre-filters
to autonomy_ceiling >= ctx.autonomy_level (the C2 bound, so a claimant never leases a task above its
reach + never poison-loops), and FOR UPDATE SKIP LOCKED LIMIT 1 makes concurrent drainers each win a
DISTINCT task (no double-claim, no blocking). An empty queue is {claimed:false} (not an error). Confers
NO new capability: identical lease + ceiling semantics to claim, just selection-by-availability.
Input { verb? } (fields ending in ? are optional)
Call POST /v/agenttask.claimNext with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Createagenttask.create
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
depth = parent.depth+1 (threaded via parentTaskId, never ambient - INV-16); a root task is depth 0.
verb MUST be a registered registry row (INV-11: no “queue a call you can never drive”). A depth
over MAX_AGENT_TASK_DEPTH=5 is a hard deny BEFORE any write (fail-closed).
Input { verb, payload?, parentTaskId?, runId?, matterId?, matterStepId? } (fields ending in ? are optional)
Call POST /v/agenttask.create with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Escalateagenttask.escalate
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
The task hit an over-autonomy action
it may not perform; it mints a one-shot ESCALATION Gate via the CANONICAL gate.propose verb
(ctx.call_verb, INV-1 - no second escalation store/path) and records escalation_gate_id, moving
to ESCALATED. The gate is an action-gate {targetVerb, inputHash} (gate.apply consumes the one-shot
grant). Only a LEASED holder (or a QUEUED task) may escalate; a terminal task cannot.
Input { taskId, targetVerb?, inputHash?, reason? } (fields ending in ? are optional)
Call POST /v/agenttask.escalate with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Createagenttask.ext.create
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
The 1:1 frontend runtime/UI tail, written post-mint so the ext never
exists without its kernel agent_task SoR row. { agentTaskId, title, prompt, sourceType, sourceId?, sourceMatterId?, sourceStepId?, childKey?, priority?, requiresHumanReview? }. Unique(agent_task_id).
Call POST /v/agenttask.ext.create with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.ext.create.
Set Waitingagenttask.ext.setWaiting
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
The FRONTEND-DERIVED WAITING_CHILDREN park/wake CAS on the ext
(the kernel has no such status). { agentTaskId, waiting, declaredChildKeys? }. CAS-guarded on
waiting_for_children = NOT waiting so a concurrent/repeat transition lands exactly once; rows_affected==0
-> { changed
Call POST /v/agenttask.ext.setWaiting with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.ext.setWaiting.
Updateagenttask.ext.update
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
Partial claim-stamp / telemetry patch by agentTaskId (only the
supplied keys are written; last-write-wins). { agentTaskId, claimTokenHash?, claimedAt?, costUsd?, durationMs?, toolCallCount?, result?, progressText? }. claimTokenHash is the frontend-computed SHA-256 of
the kernel lease handle (never plaintext - B7); the kernel only persists it.
Call POST /v/agenttask.ext.update with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.ext.update.
Feedagenttask.feed
| Property | Value |
|---|---|
| Capability | agenttask.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
The single-task read a Hatchet agent-step’s await polls for its result.
Owner-guarded: created_by == the caller OR tier >= ADMIN (an admin break-glass), plus workspace RLS,
fail-closed - a non-owner gets the SAME not-found as a missing task (no existence leak, the CC-OPBOX 37
confinement). Returns the status + the checkpoint (the agent writes its structured output to
checkpoint.output on DONE - the C2 contract) so the flow can resolve. Reuses the existing agent_task
store (no new store; gate-(b) modelled-surfaced READ, CC-OPBOX 24/18 C6).
[2026] VJS-CC-OPBOX 104: the matter READ-HOME for agent metacognition. Returns the reasoning chain - the
rationale + the autonomy each task exercised - for a matter, a regenerable VIEW over the agent_task rows
(the write-grain), never a second store (Steering #2). READ/MEMBER but SCOPED (the data.audit.feed pattern):
a caller reads ONLY the feed of a matter it can itself read - the INV-17 matter read-fence proves access
BEFORE disclosure (anti-IDOR, not-found-equivalent deny for a non-grantee), workspace-RLS-bound. With
matterId OMITTED it returns the workspace’s NON-matter (CoS/board) reasoning (matter_id IS NULL) - so an
org-level deliberation is never stranded (CC-OPBOX 104 Q4).
Input { taskId } (fields ending in ? are optional)
Call POST /v/agenttask.feed with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Getagenttask.get
| Property | Value |
|---|---|
| Capability | agenttask.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
A read operation in the agenttask.* family. Called through the one governed front door: capability, permission tier, autonomy, scope and egress are all resolved before the handler runs, and the call is audited (INV-1, INV-8).
Call POST /v/agenttask.get with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Listagenttask.list
| Property | Value |
|---|---|
| Capability | agenttask.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Admin |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
The queue + status + lastError read over agent_task (zero
new store, INV-14). IDOR-scoped to the workspace (the explicit predicate + RLS backstop).
Input { status?, matterId? } (fields ending in ? are optional)
Call POST /v/agenttask.list with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Rank By Objectiveagenttask.rankByObjective
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
The Executive loop-prioritisation function: judge a candidate task
against its matter’s overriding objective and SET its priority (the EX-3 column claim_next drains).
Deterministic set-overlap: priority = the count of distinct objective tokens that also appear in the
candidate’s descriptor (its verb + payload summary/title/description). A matter with NO objective
(or a task with no matter) ranks at 0 (the floor - nothing to align against). Reuses the SAME guarded
priority write as reorder (non-terminal, RLS-scoped); idempotent (same objective+candidate => same
priority). NOT Sensitive - pure backlog sequencing, no privilege change.
Input { taskId } (fields ending in ? are optional)
Call POST /v/agenttask.rankByObjective with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.rankByObjective.
Releaseagenttask.release
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
([2026] VJS-CC-OPBOX 32 B2). The cooperative back-off path: the lease
HOLDER voluntarily relinquishes its lease (it cannot make progress right now, or is shedding load) and
returns the task to QUEUED so another worker can claim it. Guarded WHERE status='LEASED' AND lease_owner=$actor (the C2 lease-holder guard, fully replacing any token guard - no weakening): a
stale/foreign caller, or a non-LEASED task, matches 0 rows -> the existing claim_conflict (single-winner
preserved). The checkpoint is left INTACT so the next claim resumes from it; the lease lifecycle is
cleared (lease_owner/expiry/heartbeat NULL, first_leased_at NULL so a fresh claim starts a new runaway
budget). NOT a new engine - it re-opens the row for the SAME claim path (the requeue sibling, for a
LIVE lease rather than a FAILED task).
Input { taskId } (fields ending in ? are optional)
Call POST /v/agenttask.release with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Reorderagenttask.reorder
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
Set the integer priority (default 0) of a NON-terminal task (QUEUED/LEASED/ESCALATED) in this workspace’s backlog. Higher priority drains first (claim_next ORDER BY priority DESC, created_at ASC), making the board the whitepaper’s “continuously reordered backlog of the most valuable things to do next”. Workspace-scoped (RLS + explicit predicate): a caller may reorder ONLY their own workspace’s tasks - no cross-workspace, no privilege change (NOT Sensitive: pure backlog sequencing). Idempotent. A terminal task (DONE/FAILED/CANCELLED) is refused (INV-3: priority is moot once the work is over); an unknown task is a BadInput with no existence leak.
Input { taskId, priority } (fields ending in ? are optional)
Call POST /v/agenttask.reorder with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.reorder.
Requeueagenttask.requeue
| Property | Value |
|---|---|
| Capability | agenttask.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
M7 error-recovery (the fee-earner’s “my thing broke” loop): a FAILED
task returns to QUEUED, its checkpoint INTACT so a fresh claim resumes from where it broke. NOT a new
engine - it re-opens the row for the SAME claim path. Guarded WHERE status='FAILED'; a non-FAILED
task (still running / terminal-success / cancelled) is refused (no re-driving live or done work).
Input { taskId } (fields ending in ? are optional)
Call POST /v/agenttask.requeue with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool agenttask.requeue.