Skip to main content

crewship run

run invokes a named agent and streams its response over WebSocket. Unlike ask, the agent slug is positional (no default-agent fallback) and the command supports interactive sessions, follow-ups on an existing chat, and shell-friendly streaming. Defined in cmd/crewship/cmd_run.go.
Each invocation creates a new chat by default (origin=CLI, so the web UI sidebar tags it). Pass --chat <chat-id> to continue an existing thread. Auth: crewship login plus workspace context. Both checks are skipped in --dry-run / --estimate offline modes.

Subcommands

Session provenance

run get answers the questions a run record could not answer before: which CLI binary served this run, on which credential, and did everything it was configured with actually load. The values are ground truth from the CLI’s own session-init event, not from what Crewship asked for.
Both lists are deduplicated, bounded, and honest about what they could not read:
  • A shortfall line. … and 2 more the CLI reported in a shape this record could not identify means the CLI named more than the record can show. The alarm is never dropped for want of a readable name — a partial list that reads as complete is worse than one that admits it is partial.
  • (list capped) means the run hit the per-list bound. Only a run in real trouble reaches it — an agent retrying a denied tool in a loop, or an --mcp-config where most entries fail validation.
  • unrecognized_shape as a name means the CLI reported the field in a shape this build does not enumerate. The report is still surfaced, because whether a session was degraded is decided by the CLI having reported it, never by our being able to parse it.
The same rule holds on every surface: the chat card, the run.session_init journal entry and this view all treat presence as the signal. Fields are omitted entirely when unknown (older runs, and non-Claude adapters, which report none of this) — absence means “never reported”, not “empty”. The same provenance is recorded twice more: as a run.session_init journal entry at session start (crewship journal --type run.session_init, severity error when a server was skipped), and on the chat’s “Session started” card while the run is live. The journal entry and the run record are the durable copies — the chat card is live-stream only.

Flags

Stdin is read in exactly two cases. With no prompt argument and no --prompt, piped stdin is read to EOF and becomes the prompt (echo hi | crewship run mia). With a prompt given, stdin is appended as context only when you pass --stdin (git diff | crewship run mia --stdin "review"). Otherwise stdin is never touched, so a harness, CI step or cron job whose stdin is a pipe nobody closes cannot hang the command; when stdin is a pipe or a file the CLI prints a one-line [stdin not read …] hint on stderr.

Examples

Run an agent

Read the prompt from a file

Continue an existing chat

--chat skips the POST /api/v1/agents/{id}/chats step and sends the prompt straight to the existing session over agent:{agentId} WS.

Stdin as context

Interactive REPL

Ctrl-C cancels the current turn (sends a cancel message over WS) without killing the REPL. A second Ctrl-C exits.

Cancel-friendly streaming

Save the answer to disk

Saved bytes are sanitised — any ANSI / OSC sequences a tool result emitted are stripped before they hit the file, so cat adr.md is safe.

List recent runs

KIND says which engine produced the row: agent for an ad-hoc agent/chat run, pipeline for a routine run (#2284). A routine run’s TRIGGER cell is empty — the pipeline engine does not populate it — so the column is how a script tells the two apart without guessing. run get shows the same value as its Kind: row. Use --format json for piping (crewship run list --format json | jq '.[] | select(.status=="FAILED")').

Fleet-ops insights

run insights aggregates the workspace’s ad-hoc agent runs — chat, CLI, webhook and cron invocations of an agent — over a window into an ops snapshot: success/fail split, duration percentiles (p50/p95), and breakdowns by trigger, crew, and model. Routine runs are not counted: run list reads both engines (#2284), but the insights aggregate and the stats tiles were deliberately left ad-hoc-only, so a workspace that only runs routines reports No runs in this window here. Backed by GET /api/v1/runs/insights?window=<w>. The scope is applied before the aggregate is computed, so totals, percentiles and every breakdown describe that agent or crew alone — not a workspace-wide snapshot with one section filtered. Honours the global --format json / --format yaml / --format ndjson for scripting; the default is a human-readable table.

Streaming protocol

run subscribes to session:{chatId} and posts via agent:{agentId}. Event types it renders: An agent runs one message at a time. A send that arrives while the agent already has a live run is bounced with agent_busy and no done follows it — that frame ends the exchange. run reports it and exits non-zero rather than waiting, so retry once the live run finishes. When the crew’s environment image has to be built first — a new crew, or a cache image that was removed — the send gets crew_provisioning followed by a done. That done only closes the deferral: the server replays the message on the same session once the build finishes, and run keeps waiting for that run’s own answer and done. A crew_provisioning with status failed means the build never started; run exits non-zero instead of waiting. Chat sends bounce; assignment dispatches do not. A dispatch that loses the same per-agent lock — an /assign or an @mention of a busy agent — is queued behind the live run with queued_reason: agent_busy and drained by the completion pump instead. Prefer that route when you want work to wait its turn rather than be rejected. A dropped WebSocket connection mid-run exits non-zero so wrapping scripts (crewship run x "y" || alert) catch it.

Common errors

  • prompt is required (provide as argument, --prompt flag, or use --interactive) — every path requires content unless you’re starting a REPL.
  • ws read: ... — the WebSocket dropped before done. Most often a server restart.
  • agent error: <message> — the model or a tool returned a hard error event. The exit code is non-zero and the message is sanitised before display.
  • agent busy: <message> — the agent already had a live run, so this message was rejected and never reached it. Nothing ran and nothing was persisted; send it again once the agent is free.
  • environment build failed to start: <message> — the crew needed a new environment image and the build could not be queued. Nothing ran; fix the cause shown and send again.
  • save commit: ... — --save tempfile couldn’t be atomically renamed (disk full, permission denied). Reported separately from a stream error so neither one masks the other.

See also