kind: Workspace
What it is
kind: Workspace is the top-level bundle: a single document that
captures workspace-level credentials + skills plus a list of
crews, each crew nesting its own agents, MCP servers, sidecar
services, and per-crew credential/skill overrides. One
crewship apply of a Workspace document converges the whole
workspace; crewship export workspace round-trips it back.
It is the most convenient shape for shipping or sharing a complete
team setup as one file. The same underlying data can also be expressed
as a set of standalone documents — Crew,
Agent, Skill,
Integration — but kind: Workspace keeps the
shared credentials and skills in one place and nests everything that
belongs to a crew under it.
This kind is modeled in internal/manifest/schema.go
(WorkspaceDocument / WorkspaceSpec) and validated by
internal/manifest/validate.go; unlike the per-record kinds it does
not live under internal/manifest/kinds/.
Credentials are slots, never values. The manifest format has novalue:field for credentials — a Workspace document is always safe to commit to git. Credential values are supplied at apply time viacrewship apply --from-env/--secrets-file, or prompted; any slot left unfilled is created asstatus=PENDINGand shows a “needs value” CTA in the UI.
YAML schema
Top-level fields
spec.credentials[] (slot declaration)
spec.skills[]
Workspace-scoped skill declarations. Each needs exactly one body
source (inline / path / source); see Skill for the
detailed source semantics.
spec.crews[]
Each entry is a crew. The nested shape carries slug, name, icon,
color, an optional devcontainer block, optional per-crew
credentials / skills / mcp_servers / services, and a required
agents: list. Workspace-scoped credentials and skills are visible to
every crew; per-crew entries add to (and can override) them.
- agents — see Agent for the field reference (the
nested form omits
crew_slugsince the parent crew is implicit). At most one agent per crew may beagent_role: LEAD. OnlyAGENTandLEADare valid here —COORDINATORis rejected in the nested form (see the validation rules below). - mcp_servers — the inline form of Integration,
crew-scoped. Each entry’s
transportis one ofstdio,streamable-http,http, orsse. - services — sidecar containers; same shape as
Crew’s
spec.services, including theauto_credentialsblock described below.
spec.crews[].services[].auto_credentials[]
Declares secrets that Crewship generates and manages for you instead of
asking the operator for a value. Each entry produces an
AUTO_MANAGED credential row at apply time (attributed to the crew’s
lead agent), is injected as an env var into the sidecar’s runtime, and
— unless opted out — is appended to every agent’s env_refs in the
same crew so agents can reach the sidecar with the right value.
You rarely fill this by hand: for well-known images (postgres:*,
mysql:*, mariadb:*, mongo:*, rabbitmq:*, elasticsearch:*) the
parser merges in a sugar default that generates the image’s root
password automatically. Explicit entries win over a sugar default with
the same name. See
Auto-managed credentials for
the deep dive.
Host-published ports disable auto_credentials. When a service publishes a port to the host the sidecar leaves the crew’s private bridge, so the external attack surface deserves an operator-chosen secret.validate.gorefusesauto_credentialsin that configuration — declare the credential as a regular slot instead.
Examples
Minimal — one crew, one agent
Multi-crew with shared skill + credentials
Seeexamples/manifests/full-team.workspace.yaml
for a complete two-crew bundle that shares workspace-level credentials
and a house-style skill, then gives each crew its own agents and MCP
servers.
CLI reference
Apply behavior
Applying a Workspace document expands it into the underlying create / update calls for each nested entity, in dependency order: workspace credentials + skills first, then crews and their agents, then the crews’ MCP servers and sidecar services. Every mutation goes through the same REST endpoints the UI uses (/api/v1/credentials,
/api/v1/skills/import, /api/v1/crews, /api/v1/agents,
/api/v1/integrations, …), so RBAC, audit logging, and WebSocket
notifications fire exactly as they would for an interactive user — no
direct DB writes.
Idempotency is by slug within the workspace: re-applying converges
existing rows toward the declared state.
- Upsert (default) — create missing rows, update drifted ones.
--strict— fail if any slug already exists (fresh-bootstrap guard).--replace --yes— destructive recreate.
Validation rules
checkWorkspaceDoc (in internal/manifest/validate.go) aggregates
every failure into one message so you fix them in a single pass:
-
metadata.slugis required and slug-formatted. -
Workspace credentials: each has a non-empty
env,provider, andtype; no duplicateenvwithin the scope. -
Workspace skills: each has a non-empty
slugand exactly one ofpath/source/inline. - Crews: each crew has a slug (slug-formatted, unique within the workspace) and at least one agent.
-
Agents: slug + name required;
agent_role(AGENT | LEAD),cli_adapter, andtool_profileenum-checked; at most one LEAD per crew;skillsandenv_refsresolve against the crew-scope then workspace-scope declarations.COORDINATORis not valid in nested bundles. Inside akind: Creworkind: Workspacedocument the agent-role validator (validAgentRole,internal/manifest/validate.go) admits onlyAGENTandLEAD. The standalonekind: Agentform acceptsCOORDINATORin its own front-end validator, but the nested form rejects it outright — preferAGENT/LEADeverywhere. -
MCP servers and services validate their own shapes (env-mapping
values resolve to known credentials; service names are DNS labels;
named volumes only). MCP
transportmust be one ofstdio,streamable-http,http, orsse—stdiorequirescommand; the three HTTP-family transports requireendpoint. -
Services:
auto_credentials[]entries each need a valid env-var-shapedname(unique within the service, no clash with the crew’scredentials[]);inject_as_env, when set, must be env-var-shaped;length, when positive, is at least the 16-byte floor.
Round-trip via export
crewship export workspace (ExportWorkspace) renders every crew in
the workspace as one kind: Workspace bundle: workspace-level
credentials are emitted as slots (values never travel in the file),
workspace-level skills as slug-only references, and each crew with its
agents and integrations nested under spec.crews. Use
--split-dir ./out/ to emit one file per kind instead of a single
bundle.
See also
- Crew / Agent / Skill / Integration — the standalone equivalents of the nested blocks.
examples/manifests/full-team.workspace.yaml— complete multi-crew bundle.- Schema source:
internal/manifest/schema.go(WorkspaceDocument,WorkspaceSpec). - Validation:
internal/manifest/validate.go(checkWorkspaceDoc). - Export:
internal/manifest/export.go(ExportWorkspace).