Cost fields on this page are
OWNER / ADMIN only. Other roles receive the same response with them left out — see Who sees cost figures.
A fourth value,
generation, is bumped on every claim. It is the fence: a
worker whose lease was taken over cannot report a result for the attempt that
replaced it.
States
needs_reconciliation is not a failure and not an automatic retry. It
means a process may still be alive under a locator nobody has verified, so it
keeps holding its capacity until a person or a reconciler resolves it. A timer
never clears it.
There is one exception to the capacity rule, and only to it. When the protected
run capture later confirms that the current attempt’s runtime ended (its own
exit, the runtime gone, or a whole-tree stop receipt), the attempt records
runtime_end_confirmed_at and the item gives back its execution slot. It
stays in needs_reconciliation, keeps its result and evidence, is not retried
or replayed, and still needs a resolution, because its effects remain unknown.
A park reason, an expired lease or an operator note never confirms an end, and
a later attempt of the same item does not inherit an earlier confirmation.
cancelled means a confirmed stop. Work whose process could not be
stopped, or whose outcome is unclear, goes to needs_reconciliation instead —
never to cancelled.
What these responses never contain
The ledger stores the accepted input (input_json), each transition’s
free-form detail, and — for a webhook — the raw payload. None of it is served
here. A work item’s input is, for a chat or assignment source, the
conversation itself, so the API returns its fingerprint (input_sha256) and
the revision it was accepted against instead. No response on this page carries
conversation text, credentials or model output.
A receipt is an identifier, not a capability. Holding a work_id or a
delivery_id grants nothing: every route below requires an authenticated
session or CLI token, membership of {workspaceId}, and — for the two POST
routes — MANAGER or above. A webhook token is permission to deliver, and
never permission to read the work a delivery produced.
Reading work items
The list is keyset paginated: at most 100 rows, with
next_cursor set when
more remain, passed back as ?after=. Filters are validated against the
vocabularies above — ?state=runnign is a 400, not an empty page, because
“nothing is running” is the wrong answer to a typo.
Pages run oldest first. ?since= (an RFC 3339 time) keeps to work created
since then, so a time window reads from its start rather than from the
ledger’s oldest row; an unreadable time is a 400. ?open=true keeps to work
not yet finished (not succeeded, failed, expired or cancelled), however
old — what still holds an agent’s queue.
A work item belonging to another workspace answers 404, not 403: a 403
would confirm the id exists to someone who has no business knowing it.
Every item, in the list and the detail, also names its context so a reader
does not resolve ids by hand:
The detail adds two lists.
attempts[] carries one entry per attempt —
run_id (the same namespace as the journal’s run id), the lease and its
heartbeat, the runtime_locator recovery consults before deciding a process
is gone, runtime_end_confirmed_at (when the protected capture confirmed the
runtime ended, otherwise null), and cost_usd. events[] is the append-only history in sequence
order.
Cancelling
Cancel is an idempotent request, not an immediate terminal value. The
outcome field says what actually happened, and a client must not treat the
three cases as the same 200:
state is always the item’s true state after the call. Cancelling does not
undo external effects that already happened.
Repeating the call is safe. A cancel request against a live attempt is
recorded once per generation, so polling does not grow the history.
Replaying
A replay is not a retry. A retry keeps the work id and mints a new run id, and
the queue does that on its own for a repeatable failure. A replay is a new
authorization: it creates a new work item carrying
replay_of, your reason,
your identity rather than the original requester’s, and the original
input. Terminal history is never rewritten.
target_revision is inherited from the original unless you name one. Running
against a different revision has to be explicit, and an unrecognised field in
the body is a 400 rather than a silently ignored typo.
Two refusals, both 409 with an explanation rather than an opaque failure:
- The original has not finished. Replaying live work would start a second run of the same input. Cancel it first.
- The payload is gone. A webhook-sourced replay needs the raw body the delivery ledger kept, and that body has its own retention. Once it expires the delivery record remains — so “we received it, we can no longer replay it” stays distinguishable from “we never saw it” — but the replay is unavailable and the response says so, naming the expiry. Ask the sender to deliver it again.
raw_body_available on the delivery before offering a replay control.
Webhook deliveries
Every inbound webhook is recorded before anything is dispatched, including the
ones the filter rejected: an ignored delivery keeps its
filter_reason and a
null work_id, so a ping or a filtered event is auditable rather than
invisible.
Delivery identity is (workspace, endpoint, source delivery id) — never the
signature, which changes with a fresh timestamp for the same logical delivery.
Passing ?endpoint_id= and ?source_delivery_id= asks that identity
question and answers with a page of zero or one. ?source_delivery_id= on its
own is a 400: a sender’s delivery id is only unique within an endpoint.
Each delivery also carries agent (the endpoint’s agent, as above, null
once deleted) and work_state, the current state of the work item it became —
null for an ignored delivery. A delivery that was accepted but whose work
failed reads as such without a second request.
The raw payload is never returned. raw_body_available says whether it is
still held (and therefore whether a replay can work), raw_body_expires_at
says until when, and body_sha256 plus body_bytes identify it without
publishing whatever the sender put inside.
CLI
Everything above has a command: seecrewship work.
Resolve reconciliation
Example request body:
needs_reconciliation at the supplied generation can resolve, to
succeeded, failed, or cancelled. Missing evidence returns 400; a stale
generation or incompatible state returns 409. Success returns the updated work
item and releases its ledger slots. The authenticated operator and reason are
recorded. runtime_stopped is an explicit operator attestation, not a probe or a
request to kill the process. Resolve does not start another attempt.
Routine webhook receipts have no work-item controls. On upgrade, old unclaimed
routine work records are preserved in needs_reconciliation with their original
pipeline run identity. Inspect that pipeline run, then resolve the historical
work item. Cancel and replay for these records return 409; use the pipeline API
for any execution action.