FlagDock is a local Docker-based workspace manager for solving CTF challenges with OpenCode and Codex.
It scans a configurable challenge root directory, starts one workspace container per challenge/backend, and syncs final outputs back into the source challenge directory.
- Node.js 22+
- Docker
- Optional OpenCode or Codex credentials/config if you want to use those backends
Install dependencies and copy the workspace config:
npm install
cp flagdock.yaml.example flagdock.yamlPrepare config directories:
mkdir -p .local/opencode .local/codexCopy the example configs you want to use:
cp config_examples/opencode/opencode.json.example .local/opencode/opencode.json
cp config_examples/codex/config.toml.example .local/codex/config.toml
cp config_examples/codex/env.example .local/codex/envStart the manager and launch a challenge:
node bin/flagdock.js start
node bin/flagdock.js challenge start <challenge> --mode auto
node bin/flagdock.js attach <challenge>First run may take a while because FlagDock builds missing Docker images automatically.
flagdock.yaml controls network binding and which backend(s) to start:
workspace:
bindHost: 0.0.0.0
challengesDir: ./challenges
attach:
host: 192.168.0.214
backend:
mode: opencodeworkspace.bindHost: bind address for published container portsworkspace.challengesDir: challenge root directory, relative to the repo root or an absolute pathattach.host: host/IP shown byflagdock attachbackend.mode:opencode,codex, orrace
Provider config files:
.local/opencode/opencode.json
.local/opencode/auth.json
.local/codex/config.toml
.local/codex/env
Example files live in config_examples/:
config_examples/opencode/opencode.json.exampleconfig_examples/codex/config.toml.exampleconfig_examples/codex/env.example
auth.json is intentionally not included as an example. Copy it from an existing OpenCode setup, or generate it by logging into OpenCode first and then placing the resulting file at .local/opencode/auth.json.
- A
challengeis the source problem directory. It contains the prompt (challenge.md) and any distributed files. - A
workspaceis the disposable runtime environment created from a challenge for one backend. It includes the live container, agent sessions, and a working copy of the challenge files. challengecommands act on the challenge lifecycle and its persisted solution state.workspacecommands act only on runtime state. They stop or delete the live working environment without deleting saved outputs.
Each challenge must live under workspace.challengesDir (default challenges/) and include challenge.md:
challenges/<name>/
challenge.md
distfiles/
FlagDock keeps two kinds of internal state under .flagdock/:
.flagdock/
solutions/
<challenge>-<scope>/
opencode/
flag.txt
wp.md
codex/
flag.txt
wp.md
workspaces/
<challenge>/
<backend>/
challenge/
- Runtime workspace copies live under
.flagdock/workspaces/<challenge>/<backend>/challenge/. - Canonical solution outputs live under
.flagdock/solutions/<challenge>-<scope>/<backend>/, where<scope>is derived from the resolved challenge directory.
node bin/flagdock.js status
node bin/flagdock.js challenges
node bin/flagdock.js sessions <challenge>
node bin/flagdock.js challenge start <challenge> --mode auto
node bin/flagdock.js challenge start <challenge> --mode manual
node bin/flagdock.js challenge start --all --mode manual
node bin/flagdock.js challenge reset <challenge>
node bin/flagdock.js challenge reset --all
node bin/flagdock.js workspace stop <challenge>
node bin/flagdock.js workspace stop --all
node bin/flagdock.js workspace clear <challenge>
node bin/flagdock.js workspace clear --all
node bin/flagdock.js attach <challenge> --backend opencode
node bin/flagdock.js attach <challenge> --backend codex
node bin/flagdock.js stop- Use
challenge startto create or resume a workspace from a challenge and optionally start solving. - Use
challenge start --allto batch-start every challenge currently inavailablestate. - Use
workspace stopto keep the current workspace state but stop its containers. - Use
workspace clearto discard the runtime workspace while keeping saved outputs such asflag.txtandwp.md. - Use
challenge resetto return a challenge to a cleanavailablestate.
auto: start solving immediately, continue until a flag is found, then generate a writeupmanual: create the workspace but do not drive the agent
- If a backend already has a non-empty
flag.txt,challenge start --mode autoskips it racestarts both backends; use--backendfor commands likeattach,sessions, andsession new
FlagDock's CTF agent prompt and sandbox environment are adapted from verialabs/ctf-agent.