kind: Crew
What it is
kind: Crew is the full-CRUD authoring surface for one crew: Create on
first apply, Update on drift, Unchanged when the declared spec already
matches the server. Where CrewTemplate is a
one-shot deploy of a server-side blueprint (no in-place updates),
kind: Crew owns every field of the crew row directly — runtime image,
devcontainer overlay, mise toolchain, and sidecar services.
Both kinds write to the same crews table; the difference is
provenance and lifecycle. An exported workspace round-trips through
kind: Crew for crews whose slug doesn’t match a known template (the
common case, since operators usually rename on deploy).
The kind is implemented in internal/manifest/kinds/crew.go.
Agents are separate documents. A standalonekind: Crewdocument defines only the crew row (and its sidecars / container config). Its agents are authored either as standalonekind: Agentdocuments that reference this crew bycrew_slug, or inline under akind: Workspacebundle’s nested crew shape. The standalone Crew document does not carry anagents:list.
YAML schema
Top-level spec fields
spec.devcontainer
Models the subset of devcontainer.json operators commonly tweak;
unmodeled keys pass through via raw: (typed fields win on collision).
spec.runtime_imageis the canonical image. The legacyspec.devcontainer.imageis the same thing — set one only; a divergent pair is rejected as a paste mistake.
spec.mise
spec.services[]
Each entry is one sidecar on the crew’s private bridge network. The
wire shape mirrors the server’s serviceWire.
spec.files[]
Local files (scripts, fixtures, configs) delivered into the crew’s shared
volume at crewship apply time — visible in-container under /crew/shared.
This is how a routine’s deterministic scripts travel with the manifest
instead of a manual crewship crew files save after every rebuild. Re-applied
on every apply (idempotent PUT through the same /files/save endpoint).
type: script routine step (see docs/manifest/routine.md “Script steps”)
can then run them token-zero: path: scripts/parse_vypis.py. A missing or
oversized local file fails the plan (and --dry-run), not mid-apply.
Bundled files are written to the crew’s /crew/shared bind source on the
host, so they are present the moment the crew container comes up — including
crews that have no agents and whose container is provisioned lazily on
the first routine run. Inspect them with crewship crew files list <crew> --path shared.
Examples
Minimal
With devcontainer sizing + mise toolchain
With a Postgres sidecar
CLI reference
REST endpoint mapping
How each manifest field maps onto the create/update request body:
Endpoints used:
Validation rules
CrewDocument.Validate (offline) enforces:
apiVersion/kind, when set, equalcrewship/v1/Crew.metadata.nameandmetadata.slugare non-empty; slug is kebab-case.spec.color, when it starts with#, is a valid 6-digit hex code.spec.runtime_imageis required (no sane default; the server tolerates NULL but falls back to a wrong-for-you built-in image).spec.devcontainer.image, when set, must equalspec.runtime_image.devcontainer.memory_mb/cpusare non-negative.- Each service: DNS-label name, unique within the crew, image present, numeric ports only, parseable healthcheck durations, named (not bind) volumes with unique mounts.
Apply behavior
ApplyUpsert (default)
- Remote missing →
ActionCreate: POST the full body. - Remote present, fields drift →
ActionUpdate: a sparse PATCH of only the drifted fields. Empty declared scalars and nil devcontainer/mise/services are skipped — so the manifest never overwrites a value the operator set via the UI. - Remote present, no drift →
ActionUnchanged.
devcontainer_config / mise_config / services_json are compared
after JSON normalisation, so server-side key reordering doesn’t trigger
phantom drift. services: [] (empty array) clears all sidecars; an
absent services: key leaves them alone.
Round-trip via export
crewship export workspace calls ExportCrews, which renders one
kind: Crew per crew (sorted by slug). The devcontainer / mise JSON is
decoded back into the typed sub-fields where possible, with anything
unmodeled stashed under raw: so the round-trip stays byte-stable.
Columns the manifest doesn’t model (cached_image, config_hash,
container_ttl_hours, network_mode) are dropped.
See also
- Agent — references this crew via
spec.crew_slug. - CrewTemplate — one-shot deploy of a server blueprint.
- Integration — crew-scoped MCP servers.
- Workspace — the top-level bundle that nests crews + agents.
- Backend:
internal/api/crews_create.go,internal/api/crews_update.go,internal/api/crew_services.go. - This kind’s Go implementation:
internal/manifest/kinds/crew.go.