Environment Variables
All Crewship configuration can be set via environment variables. These override values from the YAML config file. The mapping is defined inapplyEnvOverrides in internal/config/config.go.
Server
IPC
Container
Runtime image pinning
Before starting a crew container, Crewship resolves the runtime image tag to an OCI manifest digest (a registryHEAD) and then pulls that digest, not the
tag. A tag can be repointed between the check and the fetch; a digest cannot.
The digest is recorded on the crew’s provisioning.step journal entry
(payload.digest, plus payload.pinned), stamped with the run’s trace_id,
so the audit trail can answer which image produced this run.
Read it back with:
provisioning.step payload, which crewship journal already returns.
Offline and air-gapped installs are unaffected. When the registry cannot be
reached at all, the digest lookup returns nothing and Crewship keeps using the
local copy exactly as before — it just logs the local digest alongside, so even
an offline run is attributable.
When the local image is provably stale. This is the case that changed.
Two different failures land a host in the same state — the registry answered
the digest check, and the tag the container will start from resolves to a
different manifest. That is provable drift, not a guess, so Crewship
refuses to start the container rather than silently running the wrong image.
CREWSHIP_ALLOW_STALE_RUNTIME_IMAGE=1 is the single host-wide opt-out for
both routes.
Route 1 — the pull failed. Reaching a pull with a local copy present means the
digest check succeeded and the local copy did not match it:
HEAD
generously and throttles blob pulls).
Route 2 — the pull succeeded but the tag could not be moved. A digest-pinned
pull leaves the image on disk unnamed, so Crewship re-creates the repo:tag
alias itself. If the daemon refuses that and an older copy of the tag is still
there, the tag keeps pointing at the old manifest and every downstream lookup —
ContainerCreate included — addresses the image by tag. Crewship re-reads the
tag before deciding, and refuses on the same terms:
docker tag that fixes it properly. Digests are abbreviated (sha256:aaaa…)
in the examples above for width — the real error prints them in full, and the
docker tag line it gives you is runnable as printed.
What the opt-out does and does not relax. With
CREWSHIP_ALLOW_STALE_RUNTIME_IMAGE=1 both routes proceed, log a warning naming
both digests, and journal the local digest — what actually ran — with
payload.pinned: false. The escape hatch relaxes execution only. It never
relaxes the audit record: a provisioning.step row never claims a digest that
did not run, opt-out or not.
One case is deliberately left alone: if the re-tag fails and the daemon answers
404 for the tag afterward, there is no stale image to run and no digest to
record. The provisioning.step row is still written — it just carries no
digest and pinned: false — and the daemon’s own error surfaces at container
create, which is where it is most legible.
A read-back that fails rather than answering 404 is not the same thing and is
not treated as one: a timeout or a busy daemon says nothing about what the tag
resolves to, so Crewship falls back on what it proved before the pull. If a
local copy was present then (which is what sent it to the pull in the first
place), the tag is still the stale one and the start is refused.
Locally built devcontainer cache images (crewship-cache:*) exist in no
registry and therefore have no digest. Their provisioning.step rows omit the
digest key entirely; their provenance is the base image recorded on the
build’s own steps.
Set by Crewship inside the container
These are not configuration — Crewship sets them on the crew container itself, and an agent (or apostCreateCommand) can read them.
CREWSHIP_CONTAINER_PREFIX is essential for multi-instance deployments. Without it, multiple Crewship instances will create containers with colliding names like crewship-team-engineering.Storage
State
Public-facing URL
Origin enforcement (CORS / EnforceOrigin)
Rate limiting & proxy trust
Metrics
Webhooks / hooks (SSRF guard)
Profiling & observability
These are off by default and intended for operators debugging performance.Crash reporting (Sentry)
Email (password recovery)
Google sign-in (optional)
Logging
CLI and runtime context
These names are used by CLI commands, test harnesses, or the agent runtime rather than by the server’s main YAML configuration. They are listed here so a deployment or script can distinguish an intentional context variable from a typo.Authentication
As of PR #446 (
internal/secrets), the three persisted secrets — ENCRYPTION_KEY, NEXTAUTH_SECRET, and CREWSHIP_ADMIN_TOKEN_HMAC_KEY (the managed list in internal/secrets/bootstrap.go) — are bootstrapped on first start: missing values are generated with crypto/rand, persisted atomically to <dataDir>/secrets.env at mode 0600, and re-exported into the process environment so existing os.Getenv call sites see them unchanged. Explicit env vars override the file; partial persistence is handled (one missing key is filled, the other valid keys are preserved). CREWSHIP_INTERNAL_TOKEN is handled separately — the config loader generates it per boot when unset and does not persist it, so it rotates on each restart. For clustered deployments, set all four explicitly via your secret manager.Auto-Derived Values
CREWSHIP_NEXTJS_URL: If not explicitly set, defaults tohttp://localhost:{CREWSHIP_PORT}. In single-binary mode, the internal resolver calls itself on the same port.CREWSHIP_INTERNAL_TOKEN: Generated fresh per boot by the config loader when unset; not persisted, so it rotates on restart. Pin it explicitly only for multi-instance IPC bus sharing.
Encryption
Composio integrations
Keeper (AI Security Gatekeeper)
Local models (coding agents)
LLM Proxy
Paymaster (Billing Modes)
These variables tag every cost-ledger row written from inside an agent run. The orchestrator sets them on the agent’s environment from the credential type before exec; the sidecar reads them once at startup and includes them on everyPOST /api/v1/internal/cost/record call.
Operators do not set these manually for normal use. They are propagated automatically based on the credential’s auth type (API key →
metered, OAuth/subscription → flat_rate). They are listed here only for sidecar-image authors and tooling that intercepts the orchestrator handoff.Ollama (Episodic Memory + Keeper)
Feature toggles & runtime tuning
Backup webhooks
Operational skip flags (dev / CI)
These bypass safety or convenience behaviours. Never set them in production.License
Seed Data
These variables are used by the./dev.sh seed command:
Container Runtime
The Docker provider checks
DOCKER_HOST first, then auto-detects from candidate socket paths.
Devcontainer Cache GC
Crewship runs a background sweeper every 30 minutes that detects three kinds of leaks: temporary provisioning containers orphaned by acrewshipd crash
(matched by the crewship-provision-* name and the
crewship.temp=provision label — see
Devcontainers → Background GC
for why the name is the one that authorises deletion), unreferenced
crewship-cache:* images left behind when the process is killed between
docker commit and the database write that links the image to a crew, and
intermediate crewship-feat:* BuildKit feature images (per-feature layers
that are regenerable and never directly referenced by a crew row).
Temp containers older than one hour are always removed. Cache and feature
images are logged only by default; deletion must be explicitly enabled.
A 5-minute age floor protects images that were committed in the last few
minutes (closing the race between
docker commit and the DB update inside
Provision()), so enabling auto-delete is safe even on busy systems.
Leave
CREWSHIP_CACHE_GC_AUTODELETE unset on developer machines. Enable
it on long-running production hosts where reclaiming disk matters more
than preserving incidental cached images. Inspect the orphan list in the
logs first to verify nothing important would be removed.CLI client
These configure thecrewship CLI on a developer/operator machine (not the server). They override values in ~/.crewship/cli-config.yaml. Resolution order and parsing live in internal/cli/config.go.
Installer
Read byscripts/install.sh (the curl … | bash install path), not by the running server.
Complete Example
Validation
The config is validated at startup (Config.Validate). These constraints are enforced: