crewship routine
Manage workspace routines — AI-authored, repeatable workflow recipes that any crew can invoke.crewship pipeline (back-compat — every routine X invocation also works as pipeline X)
See Routines guide for the conceptual overview.
Subcommands
For batch evaluation across the eval-* routine fleet (matrix sweep, head-to-head tier compare, regression baselines), see the eval CLI.
crewship routine list
List workspace routines, sorted by usage by default.
Output columns: SLUG, INVOC, LAST STATUS, AUTHOR CREW, DESCRIPTION
crewship routine get <slug>
Show full routine detail including the DSL definition.
crewship routine save
Save a new routine from a JSON DSL file. Test_run gate runs first; if it fails, save aborts with a structured error pointing at the failing step.
--author-agent is not a credit line. Every crewship step in the routine
dispatches under that agent’s identity, and issue.comment has no other
source for one — a comment needs an author it can name. Saving a routine that
contains an issue.comment step without --author-agent is refused:400: agent_id is required.crewship routine delete <slug>
Soft-delete a routine after a confirmation prompt. The row is preserved for
audit, but the routine is no longer available for normal listing or invocation.
Backed by
DELETE /api/v1/workspaces/{ws}/pipelines/{slug}.
crewship routine run <slug>
Invoke a saved routine against the live execution tier.
Output:
run_id, status, output, duration_ms, cost_usd. Immediate runs
use COMPLETED, FAILED, or CANCELLED; WAITING means the run is parked at
an approval waitpoint and is not a failure; DEDUPED means the idempotency key
returned the original run. A delayed or debounced invocation returns
SCHEDULED with pending_id, fire_at, priority, and coalesced instead
of a run id. The API uses 200 for immediate results and 202 for this
deferred receipt.
If the routine hits a
kind: approval gate, run terminates with status: WAITING (exit 0, not a failure): it prints paused at approval step: <id> plus the waitpoint token and the approve/reject command hints, then releases its execution slot. Resume it with crewship routine waitpoints approve|reject <token>. See HITL waitpoints.With --wait, the CLI instead keeps polling the run until the approval is resolved and the run finishes — the “trigger and get the real outcome” path for scripts and agents. You can also wait later with crewship wait --routine <run_id>. Deferred receipts (SCHEDULED from --delay/--debounce-key) have no run id yet and are not waitable.Common errors
- API error (500):
pipeline: concurrency_key rendered to empty value (referenced input missing or empty)— the DSL declared aconcurrency_keytemplate that references an input you didn’t supply, and the template has no literal text to fall back on. See Troubleshooting in the routines guide for the four fixes.
crewship routine result <run_id>
Prints a finished run’s deliverable: the final output, followed by a
Files changed during this run section listing the artefacts on the
run’s crew that were written inside the run window (e.g. report.pdf,
summary.md) with a fetch hint. For a document-processing routine the
files are the deliverable, so this is the one view that surfaces them.
--client view lists the same files by bare name only — the
internal crew id, agent-slug paths, and the crew files get fetch hint
are stripped so the output is safe to forward to a customer. Backed by
GET …/pipeline-runs/{runId}/files.
crewship routine report <run_id>
Build a shareable report containing a run’s inputs, step outcomes and outputs,
final output, and (in the operator view) cost and duration. Markdown is the
default; use -f html for a self-contained HTML page.
crewship routine approve <slug>
Approve a routine sitting in proposed status — the maker-checker checkpoint that flips it live so crews can invoke it. Requires the MANAGER+ role.
POST /api/v1/workspaces/{ws}/pipelines/{slug}/approve. Output: Routine <slug> → <status>. A 403 role error or 409 “routine is awaiting approval” run refusal is rendered from the server’s Problem Details response.
crewship routine reject <slug>
Reject a proposed routine, removing it. Requires the MANAGER+ role.
POST /api/v1/workspaces/{ws}/pipelines/{slug}/reject. Output: Routine <slug> → <status>.
crewship routine disable <slug>
Airbag switch: disable an active routine. Cancels any in-flight runs and refuses new invocations (run then returns 409 routine is disabled). Requires the OWNER/ADMIN role.
POST /api/v1/workspaces/{ws}/pipelines/{slug}/disable. Output: Routine <slug> → <status>; when runs are cancelled a second line reports cancelled N in-flight run(s).
crewship routine enable <slug>
Re-enable a disabled routine so it accepts invocations again. Requires the OWNER/ADMIN role.
POST /api/v1/workspaces/{ws}/pipelines/{slug}/enable. Output: Routine <slug> → <status>.
crewship routine doctor <slug>
Preflight checklist that walks every checkable precondition before run and emits a ✓/⚠/✗ report. Catches the blind alleys (missing crew provisioning, agent slug typo, missing credential, contradictory validation gate, cost cap too tight) at one round-trip instead of one failure-per-run.
routine_exists— routine present in the workspaceauthor_crew— author crew exists, has a devcontainer config, provisioning status iscompleted(notin_progressorfailed)agent_slugs— every step’sagent_slugand everyoutcomes.grader_agent_slugresolves to an agent in the author crew (runtime resolution is crew-scoped)credential:<TYPE>— every entry incredentials_requiredhas an active workspace credential of that typeegress_allowlist—egress_targetsdeclared whenhttpsteps are present; no dead entries that match no host (*,*.*, empty); warns on loopback hosts (localhost,127.0.0.0/8) — legitimate on dev boxes, so a warning, not a failurecost_cap—max_cost_usdis set and is at least 1.5×estimated_cost_usdvalidation:<step_id>— gates are structurally satisfiable (min_length ≤ max_length, no string in bothmust_containandmust_not_contain)
crewship routine bench <slug>
Run a routine N times with the same inputs and report pass-rate, cost stats, and latency distribution. Statistical stability characterisation — use to decide whether a routine is production-ready at its current tier.
Output reports total / mean / p95 / max cost; p50 / p95 / max duration; fail-reason breakdown bucketed into
cost-cap / rubric-fail / gate-fail / auth-fail / timeout / other. Headline verdict label so the operator doesn’t need to interpret the stats:
crewship routine backtest <slug>
Replay a corpus of recent, successful runs against a candidate version and diff the outputs — validate a routine change before rollout, without creating a new version or touching which version is live. Read-only: --against names an immutable versions row; the backtest never bumps head_version and never changes what run/schedules/webhooks execute.
Composes two existing primitives — no new engine surface:
- Corpus selection —
GET /api/v1/workspaces/{ws}/pipelines/{slug}/run-records?status=completed, filtered client-side to the--lastwindow (newest-first, capped at--limit). - Pinned-version replay — for each corpus run,
POST /api/v1/workspaces/{ws}/pipelines/runs/{run_id}/replaywith{"pinned_version": N}. This replays that run’s original captured inputs against the pinned version’s definition instead of head (samePinnedVersionmechanism the cron scheduler and webhook dispatch already use for pinned triggers) and is graded against what was actually recorded.
Aggregate verdict (also the process exit code —
REGRESSION_DETECTED exits non-zero, CI-friendly like eval baseline diff):
For a matrix sweep across many routines/tiers or a saved regression baseline, see
eval scenarios and eval baseline — backtest answers a narrower question (“is this candidate version safe to promote?”) using the workspace’s own recent traffic as the corpus instead of an authored eval suite.
crewship routine appearance
A routine’s icon and colour — how it renders in lists. A workspace ends up with dozens of routines that look identical; an icon makes one findable at a glance, using the same set crews and projects use.
Presentation only. It never touches the definition, so setting an icon does not create a routine version, does not re-run the governance risk check, and does not invalidate a save token. Leave a routine unset and the UI derives a stable icon from its slug, so every routine still looks different without anyone choosing.
routine appearance get <slug>
routine appearance set <slug>
--clear removes both.
--color takes a palette id: blue, emerald, violet, amber, rose, cyan, lime, fuchsia.
API: PATCH /pipelines/{slug}/appearance.
crewship routine budget
Per-routine monthly spend budget (#1422 item 3) — a cap you set out-of-band from the DSL, compared against actual pipeline_runs.cost_usd for the current calendar month. Distinct from DSL max_cost_usd (a per-RUN hard gate the executor enforces mid-run); this is a budget-vs-actual view, not an enforcement gate — going over doesn’t block the next run.
routine budget get <slug>
Requires crewship login and a workspace context; the API is a member-scoped
read. --format json returns the response fields exactly, including month,
spent_usd, and (when a positive cap exists) pct_used and over_budget.
$spent of $cap (pct%), or a “no budget set” hint with the current spend if none is configured. --format json returns {slug, has_budget, monthly_budget_usd, month, spent_usd, pct_used, over_budget} (pct_used/over_budget are omitted when has_budget is false).
routine budget set <slug> --amount <N>
Setting a budget never touches the DSL and never bumps the routine’s version history — it’s independent of
routine save/rollback.
The mutation requires the OWNER/ADMIN manage capability and returns 200 OK
with the same budget object as budget get.
routine budget summary
ROUTINE BUDGET SPENT PCT STATUS (STATUS shows OVER when spend exceeds the cap), plus a workspace total line. --format json returns {month, routines: [...], total_budget_usd, total_spent_usd}.
This is a member-scoped read and returns 200 OK; each routine row includes
slug, monthly_budget_usd, spent_usd, and optional pct_used/
over_budget.
crewship routine state
Inspect and repair a routine’s durable cross-run state — the key/value bucket behind {{ routine.state.<key> }} and a step’s state_write binding. See Cross-run state for how a routine reads and writes it.
State is scoped per (routine, schedule): two cron schedules of the same routine keep independent watermarks, and manual / webhook runs share a separate bucket shown as (manual/webhook). That isolation is the reason this command exists — when a routine “stops seeing new items”, the stuck cursor sits in a bucket you can’t guess from the outside, and until now nothing outside a run could read it.
routine state list <slug>
schedule: <id> followed by a KEY VALUE UPDATED table. Omitting --schedule shows every bucket — that’s the diagnostic default. UPDATED is usually the tell: a cursor frozen days ago next to schedules that ran this morning.
Passing --schedule "" explicitly is not the same as omitting it: an empty value selects the shared manual/webhook bucket, while an absent flag means “all buckets”.
--format json returns {slug, buckets: [{schedule_id, entries: [{key, value, updated_at}]}]}.
routine state set <slug> <key> <value>
{{ routine.state.<key> }}. This is the preferred repair — rewinding to a known-good cursor is bounded, where clearing is not.
routine state rm <slug> <key>
routine state clear <slug>
crewship routine records <slug>
List runs for a routine using the pipeline_runs projection (introduced in migration v83). Backed by indexed columns, so this is O(log n) where runs is O(scan-with-LIKE) over journal_entries. Prefer records for filterable / scriptable run history.
Falls back with a clear message to
crewship routine runs <slug> when the server predates v83.
Reading the TRIGGER and CHAIN columns
TRIGGER is not a verbatim print of the row’s triggered_via. Every deferred
run — cron schedules and automations alike — is fired by
the same dispatcher and stored with triggered_via: "schedule", so the raw
field cannot tell the two apart. When a run carries an automation_name, the
column reads automation and SOURCE names the rule that started it:
CHAIN appears only when some run on the page was composed rather than
started directly — a routine that another routine called, or one an automation
fired from an event a run emitted. The number is chain_depth: hops from
whatever a human did, capped at 8. A workspace where nothing composes never
sees the column.
Structured output (--format json|yaml|ndjson) always carries the underlying
fields, whether or not the table drew them:
crewship routine runs <slug>
List recent invocations from the routine’s journal history. The human table
shows timestamp, event type, severity, run ID, and summary; structured formats
return the complete rows.
Backed by
GET /api/v1/workspaces/{ws}/pipelines/{slug}/runs.
crewship routine active
List in-flight runs across the entire workspace (not scoped to a single slug). Useful when triaging “is anything still running?” before a deploy or restart.
GET /api/v1/workspaces/{ws}/pipelines/runs/active — the handler note in internal/api/pipeline_runs.go flags it as single-replica scope: in a multi-replica deployment the response only reflects runs hosted by the replica the request landed on.
Output columns: RUN_ID (truncated), SLUG, STARTED, CANCEL_REQ, CONCURRENCY_KEY. Empty list prints No active runs.
Pair with routine cancel <run_id> to terminate any of the listed runs.
crewship routine logs <run_id>
Fetch the full journal trace for a single run. Post-mortem and CI-diagnostics surface — every step’s prompt, output, validation verdict, and cost in one document.
--show-outputs prints the full, untruncated output each step returned (from the run’s persisted step_outputs), for post-mortem “what did this step actually return?” debugging — the slug-free state view previously showed only status/error, and routine run truncates step outputs to a preview. Works on the slug-free form (routine logs <run_id> --show-outputs); the whole run map (including step_outputs) is also available via --format json.--slug):
DURATION and COST columns surface the per-step duration_ms / cost_usd from the journal payload (em-dash means “not applicable” — started / failed events don’t carry them). Matches the Runs-tab waterfall in the UI so the same numbers reconcile across surfaces.
Pair with
routine watch for live observation and routine logs for post-hoc forensics.
crewship routine dry-run <slug>
Preview what the routine WOULD execute without invoking agents. Returns a structured would_execute report with each step’s resolved tier, rendered prompt, and estimated cost.
crewship routine validate [file.json|file.yaml]
Offline DSL validation with no server call (by default). Reads from the file argument or stdin if absent.
validate catches three authoring mistakes that used to only surface at save or the first run:
concurrency_keythat can render empty — a key built entirely from{{ inputs.X }}refs where none isrequired: true/defaulted (e.g."{{ inputs.account_id }}"withaccount_idoptional) is rejected: a run that omits the inputs renders the key empty and dies at run time (concurrency_key rendered to empty value). Anchor one referenced input, or add literal text ("tenant-{{ inputs.account_id }}"always renders non-empty) — both accepted.- Unsatisfiable output gates — a step whose
validationhasmin_length > max_length, or the same token in bothmust_containandmust_not_contain, is rejected: no output could ever pass it. - Dead egress entry — an
egress_targetsvalue of*,*.*, or an empty host matches no real host at run time (targets are literal/subdomain-suffix matched, not globbed), so it silently denies everyhttpstep’s egress. Rejected at author time. List real hostnames instead, or omitegress_targetsentirely for unrestricted egress. (Loopback hosts likelocalhost/127.*are matchable and stay adoctorwarning, not a hard error — legitimate on dev boxes.)
Resolving agent slugs offline
By defaultvalidate skips the “does this agent_slug exist?” check because it needs the crew roster. Supply the roster to make typos fail here instead of at save:
agent_slug (or an outcomes.grader_agent_slug) not in the resolved set fails validation, naming the step — and, if a close match exists in the resolved roster, suggests it (did you mean: triage?). The same fuzzy suggestion applies to an unresolved {{ inputs.X }} reference against a typo’d input name.
Every failure in one pass, with a jump-to path
validate no longer stops at the first problem — it accumulates every static-check failure it finds and reports them all together, each prefixed with a JSON-pointer path to the offending field (/name, /steps/2/agent_slug, /steps/0/http/url, …) so an editor/LSP integration can jump straight there:
capabilities | claude -p → validate → fix authoring loop (see Routines cookbook): an AI author fixing every reported field in one revision converges in fewer round-trips than fixing one error, re-running, hitting the next one, and repeating. The one exception is the step-count bound (MaxPipelineSteps, 500) — a definition already over that limit fails immediately on its own, since walking the rest of the checks against an oversized definition isn’t meaningful.
crewship routine capabilities <crew>
Dump the authoring bundle for a crew: the routine DSL schema, agent slugs,
container CLIs and datastores, connected integrations and enabled tools, and
wired runtimes. The human view is a summary; JSON/YAML/NDJSON include the full
bundle, including the schema.
GET /api/v1/crews/{crewId}/capabilities.
crewship routine init
Scaffold an editable routine DSL locally. With no flags it prints a minimal
one-step agent_run skeleton; --script emits a deterministic script-backed
scaffold; --from clones an existing routine definition and requires the
server. --from and --script are mutually exclusive.
crewship routine schema
Print the published draft 2020-12 routine DSL JSON Schema, or write it to a
file for editor autocomplete and offline authoring.
crewship routine step-run <slug> <step>
Execute one agent_run, http, script, or transform step in isolation,
without a DAG or persisted run record. wait, notify, call_pipeline, and
code steps are unsupported. HTTP and script steps still perform their real
egress/container work.
The human output includes the PASS/FAIL validation verdict and output; JSON,
YAML, and NDJSON return the structured result. Backed by
POST /api/v1/workspaces/{ws}/pipelines/{slug}/step_run.
crewship routine tag <slug>
Add or remove discovery tags on a routine definition — distinct from run tags. Definition tags power cross-crew discovery via routine list --tag <tag>. Pass --add (repeatable) and/or --remove; at least one is required.
Adds are sent as
PUT /api/v1/workspaces/{ws}/pipelines/{slug}/tags; a removal is DELETE /api/v1/workspaces/{ws}/pipelines/{slug}/tags/{tag}. When both flags are passed, the add runs first (Tagged … +[…]), then the removal (Untagged … -…).
crewship routine step-override
Override a single step’s prompt or model without bumping the routine version — the change applies on the next run and can be cleared to revert to the authored value. A parent command with three children.
step-override set <slug> <step_id>
Set a prompt and/or model override for one step. Pass at least one of --prompt / --model.
Backed by
PUT /api/v1/workspaces/{ws}/pipelines/{slug}/steps/{step_id}/override.
step-override clear <slug> <step_id>
Remove a step’s override, reverting it to the authored prompt/model.
DELETE /api/v1/workspaces/{ws}/pipelines/{slug}/steps/{step_id}/override.
step-override list <slug>
List the active step overrides for a routine.
GET /api/v1/workspaces/{ws}/pipelines/{slug}/overrides. Output columns: STEP, MODEL, PROMPT (truncated to 50 chars). No overrides prints No step overrides — routine runs as authored.
crewship routine watch <slug>
Stream live run + step events for a routine. Polls every 2s, dedupes events, prints in chronological order with ANSI colour by status.
Ctrl-C / SIGTERM exit cleanly.
crewship routine versions <slug>
* marker tags the current HEAD.
crewship routine versions show <slug> --version N
Show one immutable version’s metadata and full DSL definition.
Backed by
GET /api/v1/workspaces/{ws}/pipelines/{slug}/versions/{version}.
crewship routine diff <slug> --from N --to M
Unified diff between two versions’ definitions (#1422 item 5) — versions show <n> dumps one version at a time for external diffing; this is the
native in-product equivalent. The diff is computed over pretty-printed
JSON, so a single field change reads as a single-hunk diff instead of the
whole minified blob changing.
Identical versions (same
definition_hash) print a one-line confirmation
instead of an empty diff. --format json returns {slug, from_version, to_version, from_hash, to_hash, identical, unified_diff}.
crewship routine rollback <slug> --to N calls this same endpoint after a
successful rollback to print a “What changed” view against the
version it just rolled back from — best-effort, so a diff-fetch failure
never fails the rollback itself.
crewship routine iterate <slug>
Run a scored improvement loop over a saved routine: run → a grader
agent scores the output against your rubric ({"score": 0-100, "feedback": "..."}) → below target, an optimizer agent rewrites the
definition → local validation → you confirm → the definition saves as a
new immutable version whose change_summary records the round and
score (iterate round 2: score 74/100 — misses the TL;DR). The loop
stops at --target or after --rounds.
Guardrails, by construction:
- Every save goes through the normal gates — the server-side
test-run gate and governance maker-checker apply exactly as for a
human author. A definition that gains risky steps (
http,code, egress) lands asproposedand the loop stops with a message; the optimizer prompt also instructs against adding such steps. - Everything is versioned — each accepted round is one row in
routine versions;crewship routine rollback <slug> --to Nundoes any of it. - Human-in-the-loop by default — each save asks for confirmation;
--yesis for unattended runs and stays auditable via the version trail. - A run parked on an approval waitpoint aborts the loop (iterate does not drive approval flows); deferred/deduped runs abort too.
--format json emits the same machine-readable.
crewship routine rollback <slug>
Creates a new version on top of HEAD whose definition equals v3’s. History is preserved; you can roll forward by another rollback.
crewship routine export <slug>
Output:
crewship-pipeline-bundle/v1 JSON to stdout. By default any type: script files the routine references are inlined into the bundle so it is portable. Suitable for pipe to routine import or commit to git.
crewship routine import [bundle.json]
Pre-validates JSON locally before sending — typos at the keyboard get a local error rather than a 400 from the server.
crewship routine cancel <run_id>
pipeline.run.failed with reason “cancelled”. Already-terminal runs return 409.
crewship routine tree <run_id>
Show a run together with its child runs — those spawned via call_pipeline steps, deferred dispatch, or replay. Useful for tracing a fan-out or a parent→child chain end-to-end.
GET /api/v1/workspaces/{ws}/pipeline-runs/{run_id}/tree.
Output columns: RUN ID, PARENT ((root) for the top run), ROUTINE, STATUS, VIA (triggered_via), COST.
crewship routine replay <run_id>
Re-run a prior run with its original captured inputs. The new run is stamped is_replay=true + replay_of=<run_id> (steps can short-circuit side effects via {{ env.is_replay }}) and inherits the source run’s tags so it groups with the original.
Backed by
POST /api/v1/workspaces/{ws}/pipelines/runs/{run_id}/replay (body: {"pinned_version": N} when --version is set). Output: Replayed <run_id> → new run <new_id>: <status> ($cost), plus the run output if non-empty.
crewship routine metadata <run_id>
Mutate a run’s metadata scratchpad. Later steps read the result as {{ run.metadata.x }}. Each flag takes a JSON object; pass at least one.
Backed by
PATCH /api/v1/workspaces/{ws}/pipeline-runs/{run_id}/metadata. Prints the updated metadata object.
crewship routine signal <run_id>
Deliver a payload to a running run parked on a wait:event step (input-stream injection). The payload becomes that wait step’s output.
Backed by
POST /api/v1/workspaces/{ws}/pipeline-runs/{run_id}/signal.
Needs a run id, so it only works when you already have one. To wake every
run parked on an event without knowing which they are, use
crewship signal send instead.
crewship routine errors
List the workspace’s failed runs bucketed by a stable error fingerprint (failing step + normalized message) so like failures group together. Pick a fingerprint and replay the whole bucket with bulk-replay.
Backed by
GET /api/v1/workspaces/{ws}/pipelines/runs/errors. Output columns: FINGERPRINT, COUNT, ROUTINE, STEP, SAMPLE ERROR (truncated to 60 chars). No failures prints No failed runs. 🎉.
crewship routine bulk-replay
Replay every failed run under one fingerprint — the fix-and-retry companion to errors. Ship the fix, grab the fingerprint, then re-trigger the whole bucket.
Backed by
POST /api/v1/workspaces/{ws}/pipelines/runs/bulk_replay. Output: Bulk replay: <replayed>/<requested> runs re-triggered for fingerprint <fp>.
crewship routine pending
List or cancel deferred routine triggers — the parked dispatches created by run --delay, --ttl, --debounce-key, or --priority. A parent command with two children.
pending list
GET /api/v1/workspaces/{ws}/pipelines/pending (200 OK, member-scoped), which returns at most 100 not-yet-fired rows with id, pipeline_slug, optional debounce_key, priority, and RFC3339Nano fire_at. Output columns: PENDING ID, ROUTINE, PRIORITY, DEBOUNCE KEY, FIRES AT. Nothing pending prints No deferred triggers pending.
pending cancel <pending_id>
update capability (MANAGER+).
Backed by POST /api/v1/workspaces/{ws}/pipelines/pending/{pending_id}/cancel,
which returns 200 OK with { "ok": true, "cancelled": "<pending_id>" }.
Missing, expired, already-fired, or already-cancelled items return 404;
missing database wiring returns 503.
crewship routine schedules
Manage cron-driven triggers. Scheduler runs in-process and ticks every 30s.
schedules list
slug@vN (e.g. daily-digest@v3). The --json output carries it as target_pipeline_version, plus last_status (COMPLETED | FAILED | SKIPPED | WAITING — WAITING means the run parked on an approval gate, which is healthy, not a failure).
schedules create
create is the only command that mints a schedule ID, and every other
schedule command takes that ID with no prefix-matching fallback — so to
script the family, read it back with a machine format rather than parsing
the human output:
schedules update <id>
Pass any subset of --cron / --timezone / --name / --enabled / --inputs / --catchup / --pin-version / --unpin / --max-failures / --wake-slug / --wake-inputs / --no-wake / --fail-closed to update. --max-failures is the positive consecutive-failure threshold at which the schedule auto-disables; omitting it keeps the existing threshold. An existing version pin survives updates that don’t mention it; --pin-version N re-pins, --unpin removes the pin so fires track head again. Likewise the wake gate is preserved unless touched: --wake-slug sets/replaces the probe, --wake-inputs replaces its inputs, and --no-wake removes the gate so the schedule fires on every tick again (--no-wake and --wake-slug/--wake-inputs/--fail-closed are mutually exclusive). The fail-closed policy is preserved unless mentioned: --fail-closed holds the run on a probe failure, --fail-closed=false restores fail-open. --catchup sets skip, once, or all; omitting it preserves the current policy.
schedules enable <id> / schedules disable <id>
Toggle without altering the cron expression.
crewship routine schedules enable <schedule_id>
Enable a schedule. The next scheduler tick can fire it; the cron expression
and other schedule settings are unchanged.
Schedule <schedule-id> enabled. With --format json, the
acknowledgement contains the schedule id and enabled: true.
schedules now <id>
Force-fire ad-hoc (out-of-cycle invocation for testing). Honours the schedule’s version pin — it executes exactly what the next cron tick would, and answers 409 if the pinned version no longer exists.
schedules delete <id>
--yes skips the confirmation prompt.
Machine-readable output
Everyschedules subcommand honours the global -f/--format
(table|json|yaml|ndjson). list and create emit the full API row;
now, update, enable, disable, and delete emit an acknowledgement
carrying the schedule id plus the verb that was applied:
crewship routine webhooks
Manage event-driven triggers. Each webhook is token-addressed (POST to /api/v1/webhooks/{token}), optionally HMAC-signed for delivery integrity, and rate-limited per token.
webhooks list
--json flag is a deprecated alias for --format json.
A version-pinned webhook shows the pin in the ROUTINE column as slug@vN. LAST STATUS is COMPLETED | FAILED | DEDUPED | WAITING (WAITING = the dispatched run parked on an approval gate — healthy, resumes on approval).
webhooks create
webhooks url <id>
Print the public URL without re-revealing the signing secret. Fails if the
token is no longer retrievable — see below.
crewship routine webhooks url <webhook_id>
Print the public URL for an existing webhook without revealing its signing
secret. The command lists webhooks in the active workspace and matches the
exact ID.
The default base URL comes from the configured server (or
CREWSHIP_SERVER); the printed value is <base-url>/api/v1/webhooks/<escaped-token>.
If the ID is not found, the command exits with webhook <id> not found.
webhooks delete <id>
crewship routine waitpoints
Inspect + decide on pending HITL approval waitpoints.
waitpoints list
waitpoints show <token>
Full prompt + metadata for a single waitpoint.
waitpoints approve <token> / waitpoints reject <token>
{{ steps.<wait_step_id>.output }}.
crewship routine trust
Manage standing approval grants — the answer to “I have approved this same gate twenty times”.
A grant is scoped to one gate of one routine and pinned to that routine’s current definition hash. Editing the routine moves the hash, so no grant matches and the gate asks again. A grant never becomes a silent path: when it fires it writes an ordinary approved waitpoint attributed to the operator who granted it.
MANAGER+ is required to grant or revoke. Listing is readable by anyone who can see the routine.
trust list <slug>
STATE is live (still firing), revoked (somebody withdrew it), or spent (expired or out of uses). A DEFINITION marked (stale) belongs to a routine body that has since changed — the grant is already inert.
Revoked grants stay in the list on purpose: the audit question is who trusted this gate and who took it back, which a live-only list cannot answer.
trust grant <slug> --step <step_id>
A second grant for the same gate and definition returns
409 rather than resetting the existing grant’s use counter.
When the governing crew is at
autonomy_level: strict, standing grants are ignored entirely — strict means every governable action reaches an operator, regardless of what has been granted. The governing crew is the routine’s author crew (a routine runs in its author’s context), or the invoking crew on a cross-crew invocation.trust revoke <slug> <grant-id>
The audit trail
Granting and revoking each write a journal entry, because disarming a human gate is the bluntest decision the approval system offers and it used to be the only one that left no trace:
Both are attributed to the deciding user (
actor_type: user). definition_hash is the load-bearing field — a grant only fires against that exact routine body, so an entry without it records that something was trusted but not what.
approval. namespace because they are the same control at two levels, so listing both families together answers “who let this through, by any route”:
crew_id, agent_id, mission_id or trace_id, so crewship journal --crew/--agent/--mission/--trace-id cannot narrow to them. --since and --actor-type user can. The refs (trust_grant_id and friends) are not searchable: -q searches summary and payload only, and refs are in neither — but the routine slug and step id are repeated into the summary, so -q <slug> does find a gate’s decisions. crewship journal get <entry-id> is what prints refs and payload; the list view shows neither.
Global flags
All routine subcommands accept these global flags:See also
- Routines guide — concepts, DSL spec, two-tier execution, troubleshooting
- CLI overview — global flags + auth
- Scheduling guide — recurring background work primitives