4.0 KiB
Running career-ops in Docker
Use this when the host can't install Playwright/Chromium directly (e.g. Ubuntu
26.04, NixOS without the playwright-driver shell, locked-down corporate
laptops). The image is based on Microsoft's official Playwright image, which
ships Chromium preinstalled and works on any Linux kernel Docker supports.
No feature is dropped: PDF generation, scanner, liveness checker, dashboard (Go), batch workers, update system — everything runs inside the container. Your project directory is bind-mounted, so reports, CVs, profile, tracker, and all generated artifacts live on the host as before.
Prerequisites
- Docker Engine 24+ with the Compose plugin (
docker compose version) - ~2 GB free disk for the image
First-time setup
# from project root
./cops up # builds image (first run takes a few minutes) and starts container
./cops doctor # confirms node + playwright + chromium + go are present
That's it. Container stays running in the background. Re-runs are instant.
Daily use
The ./cops wrapper forwards any command into the container.
| Task | Command |
|---|---|
| Health check | ./cops doctor |
| Verify pipeline | ./cops verify |
| Generate PDF | ./cops pdf output/cv.html output/cv.pdf |
| Scan portals | ./cops scan |
| Check liveness | ./cops liveness <url> |
| Merge tracker | ./cops merge |
| Dedup tracker | ./cops dedup |
| Normalize statuses | ./cops normalize |
| Update check | ./cops update:check |
| Apply update | ./cops update |
| Rollback | ./cops rollback |
| Interactive shell | ./cops shell |
| Raw node script | ./cops node check-liveness.mjs <url> |
| Build dashboard | ./cops bash -c 'cd dashboard && go build -buildvcs=false -o career-dashboard . && ./career-dashboard --path ..' |
Unknown subcommands fall through to docker compose exec so anything works:
./cops npm test
./cops bash -c 'find reports -name "*.md" | wc -l'
Lifecycle
./cops up # start (idempotent)
./cops down # stop and remove the container (volumes kept)
./cops rebuild # full rebuild (use after Dockerfile or deps change)
./cops logs # tail container logs
How it works
Dockerfile— installs Node, Playwright/Chromium (preinstalled in base image), Go (for the dashboard), LaTeX (forgenerate-latex.mjs), and project deps.docker-compose.yml— bind-mounts the project at/appso host edits appear inside the container immediately.node_moduleslives in a named volume to avoid host/container ABI mismatches..dockerignore— keeps generated and personal data out of the build context.
API keys
Drop your keys in .env at the project root or export them in the shell that
runs ./cops. The compose file forwards GEMINI_API_KEY, ANTHROPIC_API_KEY,
and OPENAI_API_KEY into the container.
echo "GEMINI_API_KEY=..." >> .env
./cops gemini:eval
Data persistence
Everything under the project root is on your host filesystem:
cv.md,config/profile.yml,modes/_profile.md,portals.ymldata/applications.md,data/pipeline.md,data/scan-history.tsvreports/,output/,interview-prep/,jds/
Nothing important is stored inside the container. ./cops down is safe.
Updating
Career-ops updates work the same as native:
./cops update:check
./cops update
If package.json deps change, run ./cops rebuild once to refresh the image
layer that holds node_modules.
Troubleshooting
docker: not found — install Docker Engine + Compose plugin first.
Playwright still complains — you're running the host's Node, not the
container's. Always go through ./cops.
Permission errors on generated files — the container runs as root by default. If host files end up root-owned, either:
- run
sudo chown -R "$USER" .once, or - add
user: "${UID}:${GID}"todocker-compose.yml(exportUID/GIDin your shell first).
Slow first build — base image is ~1.5 GB. Subsequent builds reuse layers and finish in seconds.