Skip to main content

crewship issue

Issue tracking wired directly into agent dispatch. Use these commands to create and triage issues, manage labels, comments, relations, and sub-issues, and hand work to an assigned agent (start / stop / review). Issues can also be bound to a routine so a fixed workflow runs whenever the issue is started.
Alias: crewship issues

Subcommands


crewship issue list

List issues in the workspace with optional filters.
Output columns: ID, TITLE, STATUS, PRIORITY, ASSIGNEE, CREATOR, CREW, LABELS, UPDATED A human table ends with showing 1–50 of 1 015 · next page: --offset 50, read from the X-Total-Count / X-Limit / X-Offset headers every paged list sends. Machine formats stay flat — json / yaml a bare array, ndjson one issue object per line — since scripts decode them directly (the one exception is --counts, above); quiet stays one id per line. The response also carries X-Has-More (#2286) for clients that only read that boolean.

crewship issue get

Show issue details including comments.
The identifier can be the issue identifier (e.g., BE-42) or the full ID. Output fields: Identifier, Title, Status, Priority, Crew, Assignee, Assignee Type, Owner, Delegate, Description, Due Date, Mission Type, Labels, Comments count, Created By, Created, Updated, ID. Owner and Delegate are the typed projection of the issue’s human owner and agent delegate (owner/delegate in the API — #2297, independent of each other and of the legacy Assignee/Assignee Type pair above). Each shows the resolved name, or - when nobody occupies that slot. In --format json / --format yaml, the same data is owner/delegate objects ({id, name}), omitted entirely when unset. Comments are displayed below the detail section.

Who created an issue

Every issue records its creator. The Created By field (and the CREATOR column in issue list) shows the resolved name, suffixed with (agent) when the issue was created by an agent through a tool call rather than by a human:
In --output json, the same information is available as the created_by object ({type, id, name}, where type is user or agent) plus authored_via (user_api or agent_tool_call).

crewship issue create

Create a new issue.
Owner and delegate are independent slots (#2297): assigning a person never clears the agent already delegated, and delegating to an agent never changes the owner. To clear both, crewship issue update <id> --assignee "".

crewship issue update

Update an issue. Only changed flags are sent.

crewship issue delete

Delete an issue. Prompts for confirmation.
Deletion is permanent. --yes skips the prompt — reserve it for scripts.

crewship issue comment

Add a comment to an issue.
The comment body can be passed as positional arguments after the identifier, or via the --body flag (which takes precedence).
A bare @slug typed into the body (positionally or via --body) is not a mention — it is plain text, and the mentioned agent is never notified or dispatched. The server only recognises the Markdown link form [@slug](crewship:agent/<agentId>) (internal/mentions, docs/guides/issue-mentions.mdx). Use --mention to write a real one.

crewship issue labels

List all workspace labels.
Output columns: NAME, COLOR, GROUP

crewship issue work

Take over an issue, hand it to a person or agent, or submit human work for review. Requires workspace OWNER, ADMIN, or MANAGER access. The owner stays accountable even when the current worker changes.
An exact retry returns the saved receipt. A changed request under the same ID or a stale revision fails with a conflict. Human takeover fences new agent work and requests cancellation of active runs. Handback and submission wait until those runs have stopped. Handing back to an agent prepares a new step; use crewship issue start to execute it. submit moves human work to review.

crewship issue review-policy

Set whether a person has to accept the work before this issue counts as done. Requires workspace OWNER, ADMIN, or MANAGER access.
The flag has no default on purpose: a bare call is refused rather than guessing, because dropping acceptance removes a gate somebody set. The policy can change only while the issue is TODO or BACKLOG with no live assignment — once work starts the server answers 409 instead of moving the goalposts under the worker.

crewship issue result

Print one run’s result summary, outcome and status — what the worker reported back, where crewship issue runs lists only that the run happened.
Takes the issue identifier and the assignment id — the id field of crewship issue runs <identifier> -f json. It is not the RUN column of that command’s table: that column is the journal trace id, and passing it answers 404 Run not found for this issue. A run that belongs to another issue answers 404 rather than reading across issues; a run that reported nothing says so instead of printing an empty result.

crewship issue start

Start an issue — dispatches work to the assigned agent.

crewship issue stop

Stop an issue. Ships in two tiers, both fired by this one command:
  • Tier 1 (cooperative, always applied). Marks pending/in-progress tasks CANCELLED and stamps cancel_requested_at on every live assignment; a run that hasn’t started its exec yet never starts, and the runner polls the stamp at every step boundary. No further step is scheduled.
  • Tier 2 (hard, opt in with --hard). After the Tier 1 stamp lands, ends each live run’s own tmux session (tmux kill-session -t agent-{slug}, run as a brand-new exec into the run’s same container), escalating to a direct kill -KILL on that session’s own process group if it hasn’t exited after a short grace period. Most agent runs own a tmux session named for their own agent slug — a container-visible identity — so this never runs a container-level kill and never signals by OS pid: the crew’s container is shared by every agent on the crew, and a pid resolved from outside the container is not safe to signal from inside it (#2365 — the pre-fix mechanism did exactly that and silently signalled nothing). Only the run’s own session is ever touched; a sibling agent’s session keeps running untouched. A run whose exec bypassed tmux entirely (an oversized prompt delivered via stdin, or a container without tmux installed) has no session to end — confirmed first by listing its pane pids before touching anything, then reported NOT_FOUND immediately rather than sending a signal that reaches nothing. Bounded to a few seconds; what was signalled and the result (TERMINATED_TERM, TERMINATED_KILL, ALREADY_EXITED, NOT_FOUND, PENDING_EXEC — the run was RUNNING but its exec had not appeared within the wait window, so there was nothing to signal yet; Tier 1’s stamp still ends it CANCELLED when it reports back — UNSUPPORTED, ERROR) is recorded on the run (also readable via crewship issue runs -f json’s hard_stop_result/hard_stop_at) and in the issue’s journal. Without --hard, a step already mid-exec simply finishes that exec and is then recorded CANCELLED regardless of what it reports — nothing mid-exec is interrupted.
Also reaches a run an @mention dispatched on an issue that was never started (BACKLOG/TODO): the assignment gets the same cancel_requested_at stamp (and, with --hard, the same signal if it’s already RUNNING), and the issue’s own status is left unchanged. stop still refuses when the issue is not IN_PROGRESS/REVIEW and has no live run to reach.

crewship issue review

Review an issue — approve or request changes.
The review is a compare-and-set (#2448). The command always sends both revisions, so a plain call is safe; the server answers 409 and leaves the issue where it is when:
  • the revision or brief revision no longer matches (The issue changed. Refresh before reviewing.);
  • a run or a Lead review is still live on the issue (Work or Lead review is still running — issue stop it or wait);
  • on approve, a person submitted the work and the brief changed after that submission (Submit an updated result before approving);
  • on approve, the latest agent execution ran against an older brief (Run the updated work before approving).
400 when the issue is not IN_PROGRESS/REVIEW. Full rules: API reference → Issues → Review Issue.

crewship issue comments

List comments on an issue. Hits GET /api/v1/crews/{crewId}/issues/{ident}/comments after resolving <identifier> to its crew via fetchIssue.
Output columns: ID, AUTHOR, TYPE, BODY (truncated to 60 chars, newlines flattened), CREATED.

crewship issue activity

Dump the mission-activity timeline for an issue. Hits GET /api/v1/crews/{crewId}/issues/{ident}/activity. Server caps the result at 50 rows DESC — pipe through jq if you need older history.
Output columns: WHEN (relative time), ACTOR (type/name), ACTION, DETAILS (truncated to 60 chars).

crewship issue events

The same mission_activity rows as activity, but ordered by seq (the B1 event log’s monotonic per-issue cursor) instead of created_at, and NOT capped at 50 — this is the endpoint the board’s client-side gap detector calls to resync after a WebSocket frame is dropped under load (F43, work package B11, #2368). Hits GET /api/v1/crews/{crewId}/issues/{ident}/events?after_seq=. The server caps a single response at 500 rows; the CLI (like the client-side gap detector) follows after_seq pages automatically until it has everything up to the issue’s current latest_seq, so --format json’s events array is always the full requested range, never just the first page.
Output columns: SEQ, WHEN (relative time), ACTOR (type/name), ACTION, DETAILS (truncated to 60 chars). In --format json, the response is {"events": [...], "after_seq": N, "latest_seq": N} — latest_seq is the issue’s current high-water mark, so a client with no new events can still tell “caught up at N” from “server has never heard of this issue”.

crewship issue runs

List every run attributed to an issue — mission tasks, mention-dispatched runs, and delegation-hop runs alike — the data the dashboard’s issue “Runs” tab shows. Hits GET /api/v1/crews/{crewId}/issues/{ident}/runs after resolving <identifier> to its crew via fetchIssue.
Output columns: RUN (the journal run id — what crewship journal --run-id and the Activity page take; — when the assignment never reached a run), AGENT (slug), TASK (truncated to 28), STATUS, OUTCOME, STARTED (relative time), DURATION, SOURCE, RESULT (error message or result summary; ANSI-sanitised, truncated to 50 chars). SOURCE is why the run is attributed to the issue: task (the issue’s own mission-task plan), mention (an @mention dispatch), or delegation (a sub-agent’s own further /assign call mid-mission). In --format json, the same run also carries mission_id (the issue’s mission ID; omitted on a legacy row that predates assignments.mission_id), run_id / trace_id, agent_id and agent_slug, and hard_stop_result / hard_stop_at (work package B7b, #2365) — what a Tier 2 issue stop --hard did to this run and when, omitted on a run that was never hard-stopped. Not shown as a table column; read it with --format json so a live check can confirm a hard stop actually landed without reading the journal. OUTCOME is the §9.6 routing decision (work package B6, #2349) — NO_CHANGE, SUCCEEDED, WORK_CREATED, PARTIAL, NEEDS_HUMAN, FAILED, or CANCELLED; - on a run that predates the outcome column. It answers a different question than STATUS: a COMPLETED run that never reported a recognised outcome shows FAILED here, with its error naming "no outcome reported" — an absent outcome is treated as a bug, not a silent success. NEEDS_HUMAN is the one outcome that raises an inbox item (crewship inbox list --kind run_needs_human). Full vocabulary and routing table: API reference → Issues → Outcome.

crewship issue sessions

Session lifecycle: issue_agent_sessions is work package B1 of the Issues & Routines architecture (docs/prd/PRD-ISSUES-AND-ROUTINES-2026.md). A mention resolves or creates a session — mentioning the same agent on the same issue twice reuses it rather than creating a second. As of B4 (#2348) the session’s state moves pending → active → idle/error with active_run_id set while a run is live; since B6 (#2358) a run that reports NEEDS_HUMAN parks the session in awaiting_input until the inbox item is answered. Only the idle → stale sweep is not wired yet — nothing writes stale. As of B5 (#2345), every session-bearing dispatch also reads the session back into the agent’s context — see crewship issue checkpoints below and Sessions, checkpoints and the context pack.
List the durable, per-(issue, agent) sessions a mention has opened on an issue. Hits GET /api/v1/crews/{crewId}/issues/{ident}/sessions after resolving <identifier> to its crew via fetchIssue.
Output columns: AGENT, STATE, LAST SEQ (last_consumed_seq), VERSION (agent_version, - when the agent has no config history), UPDATED (relative time).

crewship issue checkpoints

Work package B5 of the Issues & Routines architecture (docs/prd/PRD-ISSUES-AND-ROUTINES-2026.md §9.5, #2345). A checkpoint is the done/plan/facts/blockers/next_step/confidence block a session-bearing run reports when it finishes; the next run on the same session is handed the latest one as part of its §11.1 context pack, so it does not repeat completed work.
List a session’s checkpoint history. Hits GET /api/v1/crews/{crewId}/issues/{ident}/sessions/{sessionId}/checkpoints after resolving <identifier> to its crew via fetchIssue and the session via GET .../sessions.
Output columns: RUN (the run that wrote it, - if none), SEQ (seq_at_write), DONE (truncated to 40), NEXT STEP (truncated to 40), CONFIDENCE, PARSED (true/false — false means the run ended without a valid ---CHECKPOINT--- block), CREATED (relative time).

crewship issue changes

Show the base-branch git diff produced by the crew working an issue — the data the dashboard’s issue “Changes” tab renders. Hits GET /api/v1/crews/{crewId}/git-diff.
Without --patch, prints a per-file summary table (STATUS, FILE, +, −). When the crew workspace has no git repo, prints No git repository in this crew's workspace — nothing to diff.; with no changes against the base branch, prints No changes against the base branch.

crewship issue subtasks

List sub-issues — children whose parent_issue_id equals this issue’s id. Mirrors the SubIssues panel on the issue-detail page. Aliases: subissues, sub-issues.
Output columns: ID, TITLE (truncated to 50), STATUS, PRIORITY, ASSIGNEE.

crewship issue relate

Create a typed link between two issues. Wraps POST /api/v1/crews/{crewId}/issues/{ident}/relations.

crewship issue relations

List existing relations on an issue. Alias: relates.
Output columns: ID, TYPE, TARGET (identifier), TITLE (truncated to 40), STATUS.

crewship issue unrelate

Remove a relation by its relation ID (not the issue identifier). Hits DELETE /api/v1/relations/{id}.

Attach a GitHub pull request or GitLab merge request to an issue. Wraps POST /api/v1/crews/{crewId}/issues/{ident}/code-links.
The provider is recognised from the URL’s path (/pull/ → GitHub, /-/merge_requests/ → GitLab), so recognising a self-hosted instance of either needs no provider-specific configuration. Crewship then fetches the request through that provider’s API using a stored GITHUB / GITLAB credential in the workspace. Two things a self-hosted forge does still need: a credential labelled with its host (below), and — if it lives on a private/intranet address — the operator opt-in described in Git links. Without the opt-in the fetch is refused with blocked-host. For a self-hosted forge, set the credential’s account label to the forge’s host so it is matched by host:
Common failures (each a distinct RFC 7807 code): no-credential (412), blocked-host (422 — the forge is on a private address; see Git links), credential-rejected (502 — the token was revoked), rate-limited (429), already-linked (409). List an issue’s pull-request links. Aliases: code-links, prs.
Output columns: ID, STATE, REF (owner/repo#number), TITLE, BRANCH (source → target), SYNCED. A link whose last refresh failed shows its state as … (stale) — the data is the last one successfully fetched. Re-read a link’s state from its provider. Alias: refresh-link. State is never polled in the background; this is how you ask again.
A failed refresh keeps the last known state and records why on the link. Remove a link by its link ID (the first column of issue links).

crewship issue attach

Attach a local file to an issue. Wraps POST /api/v1/crews/{crewId}/issues/{ident}/attachments.
The type is decided by the file’s extension, against an allowlist — never by what the client claims, because a server that trusted a client-supplied content type would store and later serve markup from its own origin. Allowed: .txt .log .md .csv .tsv .json .yaml .yml .toml .xml .diff .patch .png .jpg .jpeg .gif .webp .avif .pdf .zip .gz .tgz. Anything else is refused with a 415 that lists the set. Maximum 25 MiB; a larger file is refused locally, naming its size, before anything is uploaded. Attaching the same bytes twice is the same attachment, so a retry is safe and does not add a second timeline entry. The agent working the issue can read what you attach — see Issue attachments.

crewship issue attachments

List an issue’s attached files. Alias: files.
Output columns: ID, FILENAME, TYPE, SIZE, BY ((agent) when an agent attached it), ADDED. Filenames are printed with control bytes stripped — they are chosen by whoever uploaded the file.

crewship issue attachment

Download one attachment by its attachment ID (the first column of issue attachments). Alias: download.
Without -o the bytes go to stdout, so the command composes with a pager or a pipeline. The server’s stored filename is never used to choose a local destination: it is a value someone else typed, and letting it name a path is how a download writes somewhere you did not ask for.

crewship issue detach

Remove an attachment by its attachment ID. Alias: unattach.
The stored bytes go too — but only if no other issue, comment or chat in the workspace still references the same file. Attachments are stored by content, so two issues carrying an identical file share one copy.

crewship issue bind-routine

Bind a routine slug to an issue — the server stores the underlying routine_id (pipeline UUID) so subsequent routine renames don’t break the link. Wraps PATCH /api/v1/crews/{crewId}/issues/{ident} with {"routine_id": <id>}.
The slug is resolved client-side via the workspace’s routine list before the PATCH, so a typo surfaces as routine "xyz": <404> instead of a silent no-op.

crewship issue unbind-routine

Clear the routine binding (server normalises empty string to SQL NULL).

crewship issue bulk update

Apply the same field updates to up to 100 issues in a single round-trip. Wraps PATCH /api/v1/issues/bulk. The 100-id cap is enforced both client-side (friendly error) and server-side (400).
At least one of --status / --priority / --assignee / --project / --labels must be supplied. Response surfaces as Bulk update applied to <updated>/<requested> issue(s). — the two counts differ when some IDs were 404 or 403.