Skip to main content

crewship crew

A crew is a team of AI agents that share one runtime container and a common Shared Ship volume. Use these commands to create and tune crews, manage members and cross-crew connections, wire up MCP servers, drive the devcontainer build pipeline (provision, rebuild, cache), and read or write files in the crew’s shared workspace.

Subcommands


crewship crew list

List all crews in the workspace.
Output columns: SLUG, NAME, AGENTS, NETWORK, MEMORY, CPUS (plus runtime/cached-image/provisioning columns when --runtime is set).

crewship crew get

Show detailed information about a crew.
Output fields: Name, Slug, ID, Description, Memory, CPUs, TTL, Network Mode, Allowed Domains, Created.

crewship crew create

Create a new crew.

Sizing a crew

--memory-mb and --cpus are checked by the server against two different floors. The hard floor is Docker’s own6 MB and 0.01 CPU. The daemon refuses to create a container below either, so a value under them comes back as a 400 naming the field. Failing here is strictly better than failing at wake time, where the daemon’s own error (“Range of CPUs is from 0.01”) names neither the crew nor the field and every run wedges on it. The --cpus ceiling cannot be fully validated server-side, because the daemon’s real upper bound is the host’s core count. The usable floor is advisory2048 MB and 0.5 CPU by default. A crew sized between the two is created, and the CLI prints a warning:
The numbers behind the default: a warmed agent CLI holds 1.5–2 GiB once its token caches load, and 512 MB was measured OOM-killing real runs. 0.5 CPU is a quarter of the shipped 2.0 default — the CPU limit is a hard quota, so a smaller fraction stretches toolchain startup proportionally, past the run timeout. This is a warning rather than a refusal because a small crew can be a deliberate choice, and refusing does not make an undersized crew any bigger — it only stops it existing. Memory is a cgroup ceiling, not a reservation, so sizing every crew at the floor does not commit that much RAM on an idle host. Moving the floor. Both values are instance settings, so an operator who knows their workload can change them:
Raising runtime.agent_min_memory_mb warns earlier and lowers every crew’s concurrency budget; lowering it does the reverse. A value that does not parse, or that falls outside the hard bounds, is ignored in favour of the default.
On upgrade: crews that were set to 0 change size. crewship crew update --memory-mb 0 used to store the literal 0 instead of resolving it, and the runtime then substituted its own fallback of 8192 MB — twice the documented default, and 2.0 CPUs became a fallback too. Those rows are corrected on first boot after this release, so an affected crew moves from an effective 8192 MB to the 4096 it always said it had, and its concurrent-run budget goes from 1 back to 2. Crews with an explicitly configured size are not touched. Run crewship crew get <slug> to see where a crew landed, and --memory-mb <n> if it needs more.

Host capacity

A crew’s own size says nothing about whether the host can afford to start its container. Twenty crews waking on the same cron minute used to start twenty containers in parallel; the only limit in the product sat inside the run, after every one of those containers already existed. Crewship now holds a container start — before the container is created — while the host cannot afford another one, and starts it when it can. A held start is not a failed one and not a hung one; crewship capacity shows what is being held and why, and crewship now says so on its status board.
Four thresholds, all instance settings:
Why the floor is one agent plus a reserve, and not a percentage. The question is absolute — does the next container fit — so a fraction of total memory answers the wrong one: “keep 10% free” is 819 MiB on an 8 GiB host and 51 GiB on a 512 GiB host, for identical work. The agent’s own memory figure is already configured; the reserve is what is left for the kernel, the container runtime and its shims, crewshipd, and enough page cache that the host stays responsive. Why starts are staggered. Creating a network namespace takes a single global kernel lock whose cost grows steeply with concurrency — measured at 1.45 ms serial and ~418 ms at 24× concurrency on a production fleet. Spreading a twenty-crew wake over a few seconds makes every start in it cheaper than firing them together would.
The host-memory signal is read from /proc/meminfo and /proc/pressure/memory, which exist on Linux only. On macOS — where the apple container provider runs — the host-memory gate is inactive, and crewship capacity says so rather than reporting a gate that is quietly doing nothing. The concurrency bound and the stagger still apply there; they need no kernel file. /proc/pressure/memory additionally requires a kernel built with CONFIG_PSI; where it is absent the pressure veto simply never fires, and is never treated as infinite pressure.
Admission control is deliberately narrow. It answers “do not start the twenty-first container while the host is thrashing” — it does not tune cgroups, evict, rebalance, or pause anything that is already running. (A running container cannot be paused to free memory: docker pause is one write to cgroup.freeze and the cgroup keeps every page.)

Idle crews are stopped

A crew container that has done nothing for 4 hours is stopped. That is the server default, applied to any crew whose --ttl was never set; set --ttl <hours> to change it for one crew, or --ttl 0 to opt that crew out entirely. crewship crew get shows which of the three states a crew is in: Nothing is lost when a container stops. /workspace, /output and /crew are host-persistent mounts and survive; the writable layer and volumes survive; only running processes and the scratch tmpfs (/tmp, /secrets) do not. The next wake starts the container again, which costs a few hundred milliseconds — less than the model round trip of the run that triggered it. A busy container is never stopped, even long past its TTL. Four things count as busy:
  • a running type: script routine step
  • a detached agent session (a run whose CLI is still alive in tmux)
  • an attached terminal (the dashboard’s container terminal)
  • a live exposed port
Service sidecars are not touched. A crew’s declared services: (redis, postgres, …) run as their own containers alongside the crew container, not inside it, so stopping an idle crew leaves them running. Crewship stops the agent runtime it owns and manages nothing else.

crewship crew update

Update a crew. Only changed flags are sent.

Issue prefixes

An issue identifier is <prefix>-<n>. The prefix is the crew’s --issue-prefix, or, when it is not set, the first three letters of the crew slug upper-cased — so a crew slugged engineering files ENG-1 without anyone configuring anything.
Two crews in a workspace may share a prefix. They then share one sequence and interleave — engineering files ENG-1, engine files ENG-2 — because the number comes from a counter keyed on the workspace and the prefix, not on the crew. Nothing is rejected and nothing collides: identifiers are unique per workspace, and one sequence per prefix is what makes that true by construction. Changing a crew’s prefix does not renumber or rewrite the identifiers it has already minted, and does not restart numbering: the new prefix picks up above whatever that prefix already holds in the workspace.
--memory-mb and --cpus reach a running container only when it is recreated. They are cgroup limits, fixed when the container is created, so a crew that is already up keeps the old ones while crewship crew get reports the new ones. When the crew is running, the update says so:
A stopped crew needs no action and gets no notice: a container whose limits no longer match its crew is rebuilt, not restarted, the next time the crew wakes. crewship crew container-status shows the configured and effective figures side by side — see Limits:.

crewship crew image-status

Report whether a crew’s running container is behind the image tag it was built from. A pure read — it never pulls and never restarts anything.
Status: current and Status: unknown (…) are different answers. When the registry is unreachable, the crew has no container, or it runs a locally built crewship-cache:* image, nothing could be compared — the command says so rather than reporting the crew as up to date.
Full background, including the daily check and the notification it raises: Keeping crew images current.

crewship crew refresh-image

Pull the crew’s configured image, then drop its runtime container so the next agent exec recreates it from the fresh copy.
The pull happens first: a failed pull leaves the crew exactly as it was rather than without a container and without a current image. Requires the update role action (OWNER, ADMIN, MANAGER).
Agents executing in the container when it is removed are interrupted.
Not the same as restart-agents. restart-agents drops the container without pulling — that picks up a devcontainer image you have already rebuilt locally. refresh-image pulls first, which is what picks up a base image that has moved on in the registry.

crewship crew delete

Delete a crew. Prompts for confirmation.
Deleting a crew removes its agents and runtime context. --yes bypasses the prompt — use it only in scripts.
The crew’s agents are retired with it, which frees their slugs as well as the crew’s: re-applying the manifest that created them works straight away. Before v1.x the agents survived their crew and kept holding their slugs, so the re-apply answered 409 Agent slug already taken in this workspace until each one was deleted by hand (#1712).

crewship crew status

Show live crew status including agents, recent assignments, and open escalations. Requires login and workspace context. The command resolves the crew by slug or ID, then reads GET /api/v1/crews/{crewId}, GET /api/v1/agents?crew_id={crewId}, GET /api/v1/crews/{crewId}/assignments, and GET /api/v1/crews/{crewId}/escalations. A missing crew is 404; each list is workspace-scoped and a failed dependency is reported as a command error.
Displays a compound view with three sections:
  • AGENTS — all agents with their slug, role, and status
  • ASSIGNMENTS (last 5) — recent task assignments with status colors
  • ESCALATIONS (open) — pending or open escalations
Agent and assignment statuses are printed as returned by the API. Open escalations are those with status PENDING or OPEN; closed escalations are not shown in the open section. The command is a read-only member operation and does not resolve assignments or escalations.

crewship crew standup

Show crew standup summary (last 24h activity).

crewship crew peer-conversations

List peer conversations in a crew.
Output columns: ID, FROM, TO, QUESTION, STATUS, ESCALATED, CREATED

crewship crew suggest

Get AI-powered crew suggestions based on a goal.

Crew Members

crewship crew member list

List members of a crew.
Output columns: ID, USER, EMAIL, JOINED

crewship crew member add

Add a user to a crew.

crewship crew member remove

Remove a member from a crew.

Crew Connections

Crew connections (“crew links” in the UI) are what let one crew hand work to another: with a link, a lead can assign to an agent in the other crew (/assign with a crew field), crews can message each other and share files. Without one, every attempt is refused. --direction unidirectional means work flows from the FIRST crew to the second only. Re-running connect on a pair that is already linked updates that link rather than creating a second one; naming the pair the other way round makes it bidirectional.

crewship crew connect

Create a connection between two crews.

crewship crew disconnect

Remove a crew connection by connection ID.

crewship crew connections

List all crew connections in the workspace.
Output columns: ID, FROM, TO, DIRECTION, STATUS, CREATED

crewship crew mcp

Show or set MCP server configuration for a crew.
--set and --set-file are mutually exclusive. The JSON must contain a "mcpServers" top-level object.

crewship crew credential-readiness

Report which of a crew’s credentials are for a CLI the crew’s container does not have. The sandbox runtime image ships git, curl and jq. Tools like gh, aws, az, gcloud, kubectl, docker, terraform, npm and ansible only exist in the container when the crew’s devcontainer config declares the matching feature (or mise installs the tool). A valid credential and a working agent are therefore two different things — a healthy GitHub PAT on a crew with no github-cli feature still gets the agent gh: command not found, with nothing connecting the two facts.
This command only reports. It never edits the crew’s devcontainer config and never triggers a rebuild — adding a feature changes what runs inside the container, so it stays your call. Apply the fix with crewship crew config, then crewship crew rebuild.
A provider with no known CLI (Notion, Stripe, anything unrecognised) reports nothing rather than guessing. Matching is on the tool name, not the feature ref, so an equivalent feature counts: docker-outside-of-docker satisfies a DOCKER credential and a mise nodejs satisfies an NPM one. Credentials are considered when they are workspace-scoped, scoped to this crew, or assigned to one of its agents with a live lease. Revoked and deleted credentials are ignored.

crewship crew services

Show the crew’s live sidecar service inventory, including status, image, inferred type, and published ports. This is the running-container view, not a snapshot of the services declared in the last configuration.
Output columns: NAME, TYPE, STATUS, IMAGE, PORTS Backed by GET /api/v1/crews/{crewId}/services.

crewship crew containers

Show every container the crew has on the runtime right now — its agent runtime container and its sidecars — with live state, CPU, memory, and how many agents run in the runtime container.
Output columns: NAME, KIND, STATUS, IMAGE, CPU, MEM, AGENTS KIND is crew (the agent runtime) or sidecar (a declared service). NAME is the real container name, so it can be pasted straight into docker logs. A - in CPU, MEM or AGENTS means unmeasured, not zero: a stopped container has no usage reading, a runtime without stats support reports none at all, and only the crew row has an agent count.
Three commands answer three different questions. containers is the whole-crew docker view. crew container-status answers about the crew’s one runtime container in depth, including configuration drift. crew services answers about the sidecars under their manifest service names.
Backed by GET /api/v1/crews/{crewId}/containers.

crewship crew config

Manage runtime configuration for a crew — the devcontainer devcontainer.json, mise tool config, and optional runtime base image override. Together these drive what crewship crew provision builds.
--show, --export, and --clear are read-or-reset operations; the three upload flags apply a new value. Combine upload flags in one invocation to update multiple fields atomically. After changing runtime configuration, run crewship crew rebuild to invalidate the container cache and apply the new build.

Container-privilege controls

The highest-blast-radius runtime settings have dedicated flags rather than requiring a hand-edited devcontainer.json. They merge onto the crew’s stored config (image, features and mise stay intact) and the server re-validates every one on save — see Container isolation → Runtime escape hatches.
The crew’s /crew directory is an agent-writable host bind that survives container removal. A start hook that executes anything from there is a persistence surface — treat it as code you wrote or audited.
Security flags form their own mode: they cannot be combined with --show, --export, --clear, or the upload flags in a single invocation. The crew must already have a devcontainer_config (there would otherwise be no base image to merge onto).

crewship crew provision

Trigger devcontainer provisioning for a crew. Kicks off the same build pipeline the server runs when an agent first starts in a fresh workspace. Streams live build progress until the build completes or fails — pass --no-watch to fire-and-forget.
Provision builds an image. It does not start a container.Crew "x" provisioned. means the image exists — nothing is running. The container is created lazily on the crew’s first agent run, and crewship crew container-status <crew> reports stopped until then. On a cache hit provision prints Using cached image and finishes in seconds having started nothing at all.To start the container, use crewship crew start.

crewship crew provision status

Check provisioning status for a crew. Prints the current status, cached image tag, config hash, and resolved devcontainer config. Pass --watch to stream live progress until the build completes. Exit code is always 0 — branch on the Status field (ready, building, failed, not-provisioned) in downstream scripts rather than relying on the exit code. When the most recent build failed, the command also prints the persisted Error and a Build log (tail) — the last ~100 lines / 8 KB of BuildKit stderr (secret-scrubbed) that name the failing step. This is read back from the provisioning journal, so it survives a server restart and the live stream ending: you can debug a failed feature build after the fact without having watched it happen. -f json returns the same tail under log_tail.

crewship crew rebuild

Invalidate the crew’s cached devcontainer image and re-provision. Use after changing crewship crew config values — provision alone will reuse the cached layer keyed by the old config hash. Streams live progress unless --no-watch is passed.

crewship crew start

Start a crew’s runtime container and wait until it is running.
This is not crew provision. Provision builds the container image; this creates and starts the container itself, running the same sequence an agent run performs — the crew’s provisioned image, its mounts, env, capabilities and resource limits, and any declared sidecar services. A crew with no image yet is provisioned first, so start works on a cold crew (that build can take minutes). Idempotent. Starting a running crew returns its container and exits 0, so a deploy script can start-then-write without branching. Reach for it when you need the container up without spending tokens:
Files under shared/ are owned by the container user, so the server replays the write inside the container. On a stopped crew that write fails with 409 file is owned by the crew runtime — this is the command that answers it. Anything the start had to do without (a container provider with no sidecar support, for instance) is printed under Notices: rather than logged, because “up, but without its declared postgres” changes what you do next.

crewship crew stop

Stop a crew’s runtime container, along with any sidecar services it declared.
The crew’s image and its shared files are untouched — only the running container goes away. The next agent run (or crewship crew start) brings it back. Because container memory and CPU limits are fixed at container-create time, this is also how a resize takes effect: crew stop then crew start recreates the container with the crew’s current limits. See container-status, whose config_drift block reports when a running container no longer matches its crew. Stopping an already-stopped crew succeeds — the caller asked for a stopped crew and got one, so a script never has to bracket the call in a status check.
Sidecars stop with the crew. A crew that declares services: gets them stopped on the same call, which is the point — a “stopped” crew whose Postgres still held its memory would not be stopped in any sense the operator meant. Named volumes are not removed, so data survives.

crewship crew container-status

Show the crew’s runtime container state.
Container: is one of running, creating, stopped, error, not_configured (no container runtime configured on the server) or unknown (the runtime could not be reached). Backed by GET /api/v1/crews/{crewId}/container-status. --format json (or yaml) emits the endpoint’s payload as it stands, which is how an agent reads the figures behind the Limits: block below — including fields this command does not print:
config_drift is absent when the container matches its crew, and when the provider reported no limits to compare against. An absent effective_* is “this provider said nothing”, never zero.

Config: — is this container running today’s configuration?

A crew container is created once and reused for as long as it keeps running. Everything that hardens it is applied at create time and nowhere else: the init process that reaps orphaned processes, the core: 0 limit that stops a crashing agent writing a core dump full of its credentials onto disk, supplementary groups, swap being off, the /dev/shm size, the restart policy. Upgrade the server while a crew is up and that crew keeps the configuration it was created with — indefinitely, and until now silently.
Three things follow from that line, and none of them is an emergency:
  • Nothing is broken. The crew runs exactly as it did before the upgrade. What it lacks are improvements, some of which are security hardening.
  • A stopped container fixes itself. When a crew whose container is stopped is next woken, a container carrying an older configuration is rebuilt rather than restarted — at that moment the rebuild costs nothing (the crew’s root filesystem is read-only, so its writable layer holds nothing, and the wake was going to pay for a container start anyway). With the idle TTL stopping crews after four hours, a fleet converges on its own.
  • A running container is never torn down for it. That would kill whatever the crew is executing. Run crewship crew restart-agents <slug> when the crew is idle, or leave it to the TTL.
No Config: line at all means the provider does not report it — the Apple container provider does not today. Absence is “unknown”, not “current”.

Limits: — is this container running today’s crew configuration?

The same shape of gap, one level down. Config: asks whether the container is older than the build; Limits: asks whether it is older than this crew’s own settings. container_memory_mb and container_cpus are cgroup limits, and a cgroup limit is set when the container is created — it cannot be changed on a running one. So crewship crew update <slug> --memory-mb 8192 stores the new figure, crewship crew get reports it, and the container keeps the old one:
The two numbers come from different places on purpose: the configured one is the crews row, the effective one is read off the running container itself. No line at all means they agree, or that the provider reported no limits to compare — an absent limit is not a limit of zero. A stopped crew fixes itself here too: a container whose limits no longer match its crew is rebuilt rather than restarted the next time the crew is woken. The report says which of the two you are looking at, because the answer to “what do I do about it” is different:
No remedy is named there on purpose — restart-agents on a stopped crew answers restarted=0, which reads as the report being wrong. A running container is never torn down for a resize — unlike a network-policy change, where the stale policy is a live exposure, a stale memory limit is not, and killing a run to apply it would cost more than it saves. crewship crew update says so on the spot when the crew is running, so the gap does not have to be discovered here.

crewship crew restart-agents

Force-remove the crew’s runtime container. The next agent exec recreates it from the current cached image, so agents pick up a new system prompt, new MCP config, and new env vars without a full rebuild. Idempotent — succeeds with restarted=0 when no container was running.
Backed by POST /api/v1/crews/{crewId}/restart-agents. The handler returns {"restarted": <n>}. Use restart-agents for hot config refreshes; reach for rebuild only when the image itself has changed. restart-agents is also the fix for a stale sidecar: after a redeploy, a still-running crew container keeps executing the OLD bind-mounted crewship-sidecar (memory recall and egress policy can silently degrade). Crewship detects this on the next agent run and records a sidecar.stale severity-error entry in the activity feed (GET /api/v1/journal?severity=error) — recycle the container with restart-agents to pick up the fresh sidecar. On servers built via make build / make build:go, the expected sidecar hash is baked into the server binary at build time, so detection also catches a stale artifact — a deploy that updated the server but never rebuilt/recopied crewship-sidecar (the on-disk file is as old as the running one, which runtime file-hashing alone cannot see). In that case the server additionally logs a stale sidecar ARTIFACT detected error: restart-agents is not enough, because a fresh container would remount the same old file — rebuild the sidecar (make build:sidecar), redeploy it, then run restart-agents. Builds without the baked-in hash (plain go build, go run) fall back to comparing against the on-disk binary, as before.
restarted: <n> (n > 0) confirms the container was actually dropped; a fresh one is created cold on the next exec. restarted: 0 means no running container was found for this crew — expected when the crew is idle, but if you know a container is up and still see 0, you’re on a build that predates the container-name-matching fix (the matcher looked for crewship-team-<slug> and missed the real <prefix>-team-<slug>-<crewID> name on any multi-instance or post-cross-tenant-fix deployment, so the drop silently no-op’d). Upgrade the server.

crewship crew apply-avatar-style

Set the avatar_style override for every agent in a crew in one call, or clear existing per-agent overrides so they fall back to the template default. Mirrors the crew toolbar’s “Apply to all agents” avatar action.
Exactly one of --style or --reset is required. Backed by POST /api/v1/crews/{crewId}/apply-avatar-style. The response reports updated (agent row count affected) plus either style or reset: true. This also drops any stored avatar renders for the crew’s agents, since those depict the previous style. Affected agents go back to generating from their seed and are re-stored on next view.

crewship crew files

Inspect or write files in the crew’s /crew/shared/ directory — the inter-agent Shared Ship namespace. Alias: crew file. Server routes live in internal/api/proxy_files.go; the CLI download path mirrors crewship agent files so the table / json / yaml output feels identical across scopes.

crewship crew files list <slug-or-id>

crewship crew files get <slug-or-id> <path>

Stream a file from the crew shared volume. Defaults to stdout when no --out is given so the output is pipe-friendly; pass --out <file> (or - to force stdout) to land bytes on disk.
Disk writes use the same atomic-tempfile-then-rename(2) pattern as agent files --download, so a Ctrl-C or transport hiccup mid-copy does not clobber an existing good file.

crewship crew files save <slug-or-id> <path>

Upload bytes to the crew shared volume. Source comes from --file (local path), --content (inline string), or stdin when neither flag is given. --content and --file are mutually exclusive.
Save issues a raw PUT /api/v1/crews/{crewId}/files/save?path=… with Content-Type: application/octet-stream so binary uploads round-trip byte-for-byte.

crewship crew files delete <slug-or-id> <path>

Remove a file from the crew shared volume — the CLI-native way to clean up a probe script or scratch file instead of falling back to rm on the host. Alias: crew files rm. Prompts for confirmation unless --yes is given. Path-traversal is rejected server-side, identical to save.
Delete issues DELETE /api/v1/crews/{crewId}/files/delete?path=… and is idempotent — removing a file that is already gone still succeeds. On a running crew whose shared tree the runtime owns (UID 1001), the removal is routed through the container so it lands regardless of host-side file ownership.

crewship crew cache

Manage the devcontainer image cache shared across crews. Cache tags use the crewship-cache:* prefix and are keyed by a hash of devcontainer.json + mise config + runtime image, so two crews with identical configs share a single image.

crewship crew cache list

Output columns: TAG, SIZE, CREATED, USED BY (comma-joined list of crew slugs that reference the image — empty when unreferenced).

crewship crew cache prune

Remove old or unreferenced cached images. With no flags, defaults to --older-than 30d and leaves referenced images alone.
Pruning a referenced image forces the next crewship crew provision on that crew to rebuild from scratch (seconds to minutes). --force bypasses the confirmation prompt — use it only in scripts.

See also