An Action is a human decision recorded at the Orchestrator, not inside an automation. A robot run cannot stop and wait, so while a decision is open nothing is dispatched and no job row exists. The decision is what creates the run.
#The threshold
An invoice needs a human only when its amount is strictly greater than the threshold. The default is 13000. 13 000 exactly does not need a person; 13 000.01 does. The override is the TS_APPROVAL_THRESHOLD environment variable. A malformed override is refused rather than coerced, because guessing here would decide whether a person is asked at all. A non-finite amount is a malformed invoice, not a small one.
npx tsx orchestrator/cli.ts action threshold
#Raising and working an Action
npx tsx orchestrator/cli.ts action create --subject invoice:INV-1042 \
--title "Approve INV-1042 from Acme" --package approve-invoice --version v1 --queue approvals
npx tsx orchestrator/cli.ts action list --view unassigned
npx tsx orchestrator/cli.ts action assign <id>
npx tsx orchestrator/cli.ts action comment <id> --text "checked against the PO"
npx tsx orchestrator/cli.ts action show <id>
An Action moves unassigned → pending → completed. Completion is terminal and cannot be reverted. Priority is critical, high, medium or low, default medium. The default sort is priority then creation time, so the most urgent decision is first. A pending Action is read-only for everyone but its assignee. Only the assignee may forward it; an operator may reassign or unassign. action data prints the form payload the human sees. action history prints the append-only journal of the human step.
Every human operation is attested by a bearer read from TS_PRINCIPAL_TOKEN and needs the operator or approver role. The platform's own ingest seams author Actions as orchestrator:<seam>, a named system actor that is not a principal.
#Deciding and resuming
npx tsx orchestrator/cli.ts action complete <id> --outcome approve --output '{"approved":true}'
npx tsx orchestrator/cli.ts action complete <id> --outcome reject --reason "no purchase order"
npx tsx orchestrator/cli.ts action resume <id>
A reject needs a reason; silence is not a decision. Completion resumes the work through the same governed dispatchJob seam a schedule uses. Three properties are structural. One decision produces exactly one continuation: the job row is created and its id written onto the Action before the dispatch, so a crash leaves a readable link and a second resume is refused by name. The continuation cannot name a robot; it submits robot: auto and eligibility decides placement. It does not widen retries; it uses maxAttempts: 1.
The decision travels to the resumed run through its environment: TS_ACTION_ID, TS_ACTION_OUTCOME, TS_ACTION_REASON, TS_ACTION_OUTPUT and TS_ACTION_SUBJECT_REF. A reject whose resume spec says onReject: none dispatches nothing at all: zero job rows, with the reason journaled on the Action. action resume <id> is the recovery verb when a completion recorded its decision but the continuation never dispatched.
#Things that catch people out
There is deliberately no job row while an Action waits. The absence of work is the "workflow stops".
Completion cannot be reverted, so a wrong decision is corrected by a new Action, not by reopening the old one.
The --output payload is capped at 2000 characters and is non-sensitive by contract: ids and short operator text, not a data payload. Labels are lowercase, up to 32 characters, at most ten per Action. An over-threshold invoice that cannot be resumed is refused before the Action is created, so the human step is never recorded against a dead end.