Skip to main content

crewship apply

Apply a YAML manifest that describes a crew or workspace. Re-running apply is idempotent and convergent: missing resources are created, drifted ones updated, and resources that disappeared from the manifest are deleted (with confirmation). Mutations go through normal REST endpoints so RBAC, audit logging, and WebSocket events fire the same way they would for an interactive user.
For the narrative tour and the manifest format, see Guides → Workspace Manifests.

Flags

--strict and --replace are mutually exclusive. Apply also requires an authenticated session (crewship login) and a workspace context — both are inherited from the current CLI profile. Use --skip-test-gate when applying a manifest whose routine depends on credentials that are still PENDING from the same apply: the test_run would attempt to invoke the routine before its credentials exist, fail, and block save. Operators with OWNER/ADMIN role bypass the gate; everyone else must seed the credentials first and re-run apply without the flag.

Examples

Idempotent re-apply

The most common shape. Reads credential values from env vars matching each env: entry in the manifest. Re-running converges drift.

Dry-run as a CI check

Prints the plan, never mutates. Exit code is 0 unless validation fails. Useful as a PR check that catches “this manifest is malformed before review”.

Strict mode for ephemeral workspaces

Use when you spin up a brand-new workspace per branch — strict catches the case where a previous run wasn’t cleaned up.

Replace an existing crew

Deletes anything matching the manifest’s slugs and recreates from scratch. Use when you’ve broken the schema so badly that upsert can’t reconcile.

Read from stdin

Useful for piping from sed, op inject, or a templating step.

KEY=VALUE secrets file

secrets.env:
The format mirrors Docker Compose’s --env-file: no env-var expansion happens, the file is the source of truth.

Plan + confirm flow

Apply is two-pass: it computes the full plan first, prints it, asks for confirmation on anything destructive, and only then executes.
The leading character on each line tells you the action:

Reading a failed run

Apply is fail-fast: the first error aborts the run, and every plan item behind it is left untouched. That makes the counters a prefix, so a failed run never prints Applied: — it prints what it managed, says it failed, and then names what it did not do:
The NOT APPLIED block exists because the counters cannot answer the only question you have at that moment — which of them landed? Nothing was attempted for the listed items, so re-running after fixing the cause is safe. Grepping for Applied: is a valid success check. Grepping for the absence of a non-zero exit code is better.

Refusing deletes outright

Sync mode makes deletion the default for anything that fell out of the manifest, and some deletions are not a rollback away: removing an agent takes its memory and its Composio OAuth binding with it, and that binding is a browser consent no manifest can replay. --no-delete turns “this run deletes nothing” from a claim a human makes by reading the plan carefully into one the machine checks:
Nothing is mutated — the refusal happens after the plan is built and before the first request. It deliberately outranks --yes (the flag every automated invocation already carries, so a guard --yes could switch off would not be one), and it fails --dry-run too, so the rehearsal and the performance agree. The check runs twice, against two different plans. The CLI refuses against the plan it rendered for you; manifest.Apply refuses again against the plan it builds from its own fresh read of the server, immediately before executing it. Without the second one a resource that disappeared between the two reads would add a delete to the second plan that the first never showed, and --yes would wave it through. SDK callers get the same guarantee via manifest.Options{NoDelete: true}, which returns manifest.ErrDeletesRefused. Worth making the default on production manifests.

Credential resolution

Manifests never carry secret values. crewship apply resolves the env: slot through a chain of sources, in order:
  1. --secrets-file <path> if supplied
  2. --from-env (process environment) if supplied
  3. Otherwise the credential is created as status=PENDING and printed at the end
PENDING credentials never inject their placeholder into the agent’s environment. Agents that need a pending credential fail with credential not configured until you set the value through the UI or crewship credential update.

What gets deleted on sync

Resources synced (= deleted when missing from the manifest, with confirmation):
  • crews (in workspace bundles)
  • agents within each declared crew
  • agent skill bindings
  • agent credential bindings
  • MCP servers on each declared crew
Resources not synced (additive only):
  • skills at workspace scope — drop them via crewship skill rm
  • credentials themselves — drop them via UI or crewship credential delete

Exit codes

apply doesn’t surface a “code 2 = changes applied” because every CI pipeline already knows the previous state via git. Use --dry-run for the “did anything change?” check.

Common errors

  • crew "code-review" already exists — drop --strict to update in place, or pass --replace to recreate.
  • aborted: destructive plan requires confirmation (pass --yes)apply saw a - line in the plan and stdin isn’t a TTY. Pass -y/--yes in CI, or run interactively.
  • invalid services_json: services["xyz"]: name must be a DNS label — service names must be valid RFC 1035 DNS labels (1–63 chars, lowercase letters/digits/-, starting with a letter and ending with letter or digit) since they become bridge-network DNS aliases.
  • skill "X" references unknown credential env "Y" — every env_refs: entry must point at a credential declared in the same manifest (in the crew or at workspace scope).

Next step after apply

When the manifest declares spec.devcontainer on any crew, apply prints a hint at the end:
The original design auto-provisioned containers, but the apply CLI had already exited by the time provisioning streamed progress — so we surface the chained command instead of hiding it behind a flag. Run the printed line(s) to build the crew’s container image.
crew provision builds an image. It does not start a container, and on a cache hit it finishes in seconds having started nothing — the container is created lazily on the crew’s first agent run.This matters when a manifest ships crew_files into shared/: those paths are owned by the container user, so overwriting one on a stopped crew returns 409 file is owned by the crew runtime. Start the crew, then re-apply:
crew start is idempotent, so it is safe to put in front of every apply that ships crew files.

See also