Skip to main content

crewship start

Starts the Crewship server. Single Go binary listens on HTTP (default :8080), serves the embedded Next.js UI, and connects to a container provider for agent runs.

What happens on start

  1. Configuration resolution. Reads --config if given, else defaults from env (CREWSHIP_*) and built-in defaults.
  2. Database open. Opens SQLite at ~/.crewship/crewship.db (or --db override). Enforces WAL mode, 0600 file perms, foreign keys.
  3. Pre-migration snapshot. If any migrations are pending, SnapshotBeforeMigrate writes a VACUUM INTO copy of the live DB to <dbpath>.pre-migrate-vN-to-vM-<UTC>.bak before any DDL runs. See Backup & Restore — automatic pre-migration snapshots.
  4. Migrations apply. Runs every pending migration in internal/database/migrate.go order. Collision detection fails loudly if the local DB has a different name applied at a given version.
  5. Telemetry init. Reads consent from app_settings. With no consent row, prerelease builds default to enabled (opt out with crewship telemetry off); stable builds stay disabled until you opt in. See Telemetry.
  6. Update check. Fires a goroutine that queries the GitHub Releases API (cached 24h in ~/.crewship/cache/). Prints a banner to stderr if a newer release is available. Skip with CREWSHIP_SKIP_UPDATE_CHECK=1.
  7. Providers initialize. Docker (or whichever container runtime is detected), localfs storage, bbolt state. --no-docker skips the container provider — useful for read-only browse mode without running agents.
  8. HTTP server starts. Binds 0.0.0.0:8080 by default. WebSocket on the same port at /ws. IPC socket at <data dir>/crewship.sock — the data dir being CREWSHIP_DATA_DIR when set and $HOME/.crewship when it is not, so /tmp/crewship.sock applies to the packaged /var/lib/crewship install and nothing else. If another process is already listening on that socket, start fails with an error naming the path instead of taking the socket over.
  9. First-run welcome. If post-migration the users table is empty AND stdout is a TTY, prints a one-screen banner pointing at the browser onboarding wizard (PR #441). Suppressed on non-TTY so systemd journal / log scrapes stay clean. Query errors warn-and- continue rather than fail the start — a stale or half-migrated DB is already surfaced via the migration log.
Boot typically takes 1–3 seconds on a warm machine; first-ever start (empty DB, full migration sweep) takes 5–10 seconds.

Flags

There are no --port, --host, or --license flags on crewship start. HTTP port and bind address come from config / env only — set CREWSHIP_PORT (default 8080) and bind 0.0.0.0 by default (see the env table below). Licensing is read from config / env, not a command-line flag; without a license, community-edition limits apply (max crews, agents, members).

Environment variables

Beyond the flags above, crewship start respects: As of PR #446, crewship start auto-bootstraps NEXTAUTH_SECRET, ENCRYPTION_KEY, and CREWSHIP_INTERNAL_TOKEN on first boot — curl install.sh | bash → crewship start works with no env files to hand-edit. Subsequent boots read the persisted file. Explicit env vars always win, so Vault / Kubernetes secret mounts / systemd EnvironmentFile= keep working unchanged. Run crewship doctor to see where each secret lives (“env-provided” vs “auto-managed in <path>”). See Configuration → Environment for the full bootstrap pipeline.

Multi-instance setup

Crewship can run multiple instances on one host by suffixing the data directory and port. The dev.sh script handles this for development; for production, point --db and CREWSHIP_PORT at distinct paths:
Each instance is fully isolated — separate DB, separate container network (CREWSHIP_CONTAINER_NETWORK=crewship-agents-1), separate IPC socket (CREWSHIP_SOCKET_PATH=/tmp/crewship-1.sock). Giving each instance its own CREWSHIP_DATA_DIR already derives a distinct IPC socket and bbolt file under that directory, so the explicit CREWSHIP_SOCKET_PATH / CREWSHIP_BOLT_PATH overrides above are only needed when you want specific paths.
Setting only CREWSHIP_PORT is not enough to separate two instances. Both files derive from the data dir, so two instances that leave CREWSHIP_DATA_DIR unset under the same account resolve the same $HOME/.crewship and collide on both. Give each one its own CREWSHIP_DATA_DIR — or, if you want the paths spelled out, its own CREWSHIP_BOLT_PATH and CREWSHIP_SOCKET_PATH.
Both files are exclusive by nature, and sharing either one fails loudly rather than silently:
  • Sharing the bbolt file: the second instance logs that it is waiting for the lock, naming the file, then gives up after ten seconds with state database is locked by another process: <path> (waited 10s; find the holder with: lsof <path>). It does not wait indefinitely — if your start exits after about ten seconds, a shared state file is the first thing to check.
  • Sharing the socket: refused at startup, without unlinking the socket the running instance is listening on.

Graceful shutdown

crewship start traps SIGINT and SIGTERM:
  • Stops accepting new HTTP requests
  • Finishes in-flight requests up to 30s
  • Flushes Sentry events (2s timeout)
  • Closes the database with WAL checkpoint
  • Closes the docker client
Force-kill with kill -9 if shutdown takes longer than 30s; expect a WAL replay on next boot (SQLite handles it automatically, just slower than a clean shutdown).