devcon is a Linux-only CLI that launches AI coding agents like Codex CLI or Claude Code in fresh Docker containers that already have your working directory wired up. Install globally (npm install -g devcon) and run devcon codex (or devcon claude) from any project to get a locked-down shell within seconds. If no image is configured, Devcon defaults to a local devcon:latest image that bundles both Codex CLI and Claude Code; the first time you run a tool the CLI offers to build this image for you.
- Spin up a disposable Docker container per invocation.
- Bind-mount the current working directory at
/workspace/<current-folder-name>and run as your host UID/GID so file permissions stay intact. - Optionally bind-mount extra host directories for a single run via
--mount PATH(repeatable), mounted under/workspace/<folder-name>in the container. - Keep the host home directory private by default. Opt in with
--homeorDEVCON_SHARE_HOME=1, or whitelist individual directories viawritablePathsso credentials like~/.codexcan still be shared. - Hide
.env*,.git-credentials, and other critical Git metadata from the container by overlaying empty bind mounts before the container starts. - Detect when the default
devcon:latestdocker image is missing and (after ayconfirmation) build it automatically fromdocker/devcon/Dockerfile. - Provide a simple tool registry (
codex,claudeby default) allowing you to define which Docker image and command should run for each agent. - Optional
--consciousmode that boots a persistent local archive and wires memory tools into Codex/Claude via MCP.
You need Docker installed and running. Only Linux hosts are supported for now because the CLI relies on Unix-specific APIs such as getuid/getgid.
If you're working from a clone (like this repo), build and install the CLI locally:
npm install
npm run build
npm install -g .devcon <tool> [flags] [-- tool arguments]
# Rebuild the default tool images (all tools or a specific one)
devcon update
devcon update codex
devcon rebuild # full no-cache rebuild for all auto-build tools
devcon rebuild codex # full no-cache rebuild of a single tool/image
devcon webhub --allow ~/work/project-a --allow ~/work/project-b
devcon sensitive list # show effective sensitive patterns and matches
devcon sensitive add secrets/** # add a custom sensitive pattern
devcon sensitive remove secrets/**
devcon skip-scan list # show skip-scan directories (defaults + custom)
devcon skip-scan add .cache # add a directory name to skip during scans
devcon skip-scan remove .cache
devcon --mount ../shared codex # add one extra host directory for this run only
devcon run --with-git -- ls # open an interactive shell (default image) and run a command
devcon --conscious codex # enable persistent archive memory for this runExamples:
# Show the docker command without running it
devcon codex --dry-run
# Enable conscious mode (archive memory + MCP tools)
devcon --conscious codex
# Launch Claude Code but keep your home directory out of the container
devcon claude --no-home
# Force IPv4 inside the container (disable IPv6)
devcon -ipv4 codex
# Use host networking (helpful with VPNs that block Docker bridge DNS/NAT)
devcon --network-host codex
# Override the docker image just for this run
devcon codex --image ghcr.io/my/codex:latest -- --trace
# Temporarily share the entire home directory (default is no home mount)
devcon codex --home
# Mount another host directory for this run only
devcon --mount ../shared codex
devcon --mount ~/work/notes --mount /tmp/datasets codexUse --web to launch a tool in a tmux-backed session and immediately expose it through the built-in web terminal:
devcon --web codexYou can also set explicit connection settings:
devcon --web --web-host 0.0.0.0 --web-port 7682 --web-password 'strong-password' codexNotes:
--webrequirestmuxon the host.- If no password is provided (
--web-passwordorWEB_PASSWORD), devcon generates one-time credentials and prints them. - By default devcon auto-generates a tmux session name. Override via
--web-session NAME. - The container keeps running in tmux until it exits or you stop it (
tmux kill-session -t <name>).
Manual mode is still available via npm run web if you want to attach the web UI to an existing tmux session (TMUX_TARGET=...).
Security note: do not expose the web terminal directly to the public internet without TLS and upstream access control.
webhub gives you a single browser UI that can launch and manage multiple tmux-backed devcon web sessions, each in a whitelisted directory.
Launch:
devcon webhub --allow ~/work/project-a --allow ~/work/project-bOptional host/port/password:
devcon webhub --allow /workspace --host 0.0.0.0 --port 7690 --password 'strong-password'Behavior:
- Webhub only allows launching sessions inside directories passed with
--allow(repeatable). - It launches sessions via internal
devcon --web --web-no-server ...and streams tmux output directly. - When webhub exits (
Ctrl+C), it stops hub-managed tmux sessions.
Environment alternatives:
DEVCON_WEBHUB_ALLOWLIST=/path/a:/path/bDEVCON_WEBHUB_HOST=0.0.0.0DEVCON_WEBHUB_PORT=7690DEVCON_WEBHUB_PASSWORD=strong-password
Useful flags (place before -- that separates devcon flags from tool args):
--dry-run– Print the assembleddocker runinvocation instead of executing it.--home/--no-home– Force-enable or force-disable home-directory sharing for this run.--image=NAME– Override the docker image configured for the tool.--with-git– Unmask.gitand inject a sandboxed git identity (devcon-bot <devcon@example.com>) inside the container.--temp-git– Keep host.gitmasked but mount a temporary git repo/worktree in the container (sandboxed identity pre-configured).--mount PATH– Add an extra bind mount for the current run only (repeatable). Mounted under/workspace/<folder-name>(e.g.--mount ../shared=>/workspace/shared) and scanned/masked with the same sensitive-path rules as the main project mount.--export-patch[=PATH]– With--temp-git, export patches after the run to PATH (or.devcon/drafts/<timestamp>.patch).--network-host/-network-host– Use host networking (often required on VPNs that block Docker bridge DNS/NAT).--ipv4/-ipv4– Force IPv4-only networking by disabling IPv6 inside the container.--web– Run the tool inside tmux and expose it through the built-in web terminal.--web-host HOST– Override web server bind host (default:0.0.0.0).--web-port PORT– Override web server port (default:7682).--web-password PASS– Set web terminal login password (auto-generated if omitted).--web-session NAME– Set tmux session name for web mode.--conscious/-conscious– Enable conscious mode (persistent archive + MCP memory tools).--conscious-path PATH– Override conscious state directory (defaults to~/.config/devcon/conscious).--help/--list– Show usage plus the registered tools.- Startup preflight: when bridge networking cannot resolve
api.openai.combut host networking can, Devcon prompts to switch this run to--network-host. - Startup preflight timeout defaults to 2500ms per probe and can be adjusted with
DEVCON_NETWORK_PROBE_TIMEOUT_MS.
Pass tool arguments after -- so they are not parsed by devcon. Examples:
devcon codex --with-git -- git status
devcon codex -- --dry-run "my prompt"devcon --conscious <tool> performs an idempotent bootstrap on startup:
- Creates state under
~/.config/devcon/conscious(or--conscious-path), namespaced per conscious project atprojects/<project-id>/. - On first run in a git repo, prompts for project setup if no
.git/devcon/project-idexists:- create new project (asks for project name),
- link this repo to an existing conscious project,
- clone an existing conscious project into a new one (fork memory, then diverge).
- Persists the chosen project identifier under
.git/devcon/project-id(git-internal, not tracked). - Initializes archive storage (
archive-db.json) for that project if missing. - Generates a per-session retrieval snapshot under
sessions/. - Starts (or reuses) a persistent per-project memory sidecar container and auto-registers MCP access for Codex/Claude as
devcon-archive. - Removes that MCP registration again when the CLI process exits to avoid stale config drift.
Container isolation notes:
- The tool container does not mount the persistent archive directly in conscious mode.
- Persistent archive storage is mounted into the sidecar only (
~/.config/devcon/conscious->/state). - Conscious sidecar mode is not compatible with
--network-host. - Override sidecar image via
DEVCON_CONSCIOUS_SIDECAR_IMAGE(defaults todevcon:latest). - Memory persistence policy knobs:
DEVCON_CONSCIOUS_MEMORY_POLICY=off|encourage|require(defaultencourage)DEVCON_CONSCIOUS_MEMORY_POLICY_THRESHOLD=<N>(default4read calls before reminders/gating)
MCP tools exposed in conscious mode:
archive_overview(session bootstrap: fetch taxonomy + labels +overview_token; call this before other archive tools)archive_bootstrap(recommended first call in a fresh chat: overview + concrete initial findings, including user preferences when present)archive_create_path(create a new folder path when no existing path matches)archive_search(fast index search; returns summary + previews)archive_get(fetch full stored details for a finding id; optionalrevision_idfor historical versions)archive_versions(list revision history for a finding)archive_writearchive_update(append a new revision to an existing finding by id)archive_mark_used
Write flow constraints:
archive_searchexpects thatarchive_overviewhas been called once in the current MCP session.archive_bootstrapcan satisfy that same session bootstrap requirement.archive_writenow requires bothoverview_tokenandpath_id.archive_updaterequiresoverview_tokenandid.- Tokens are short-lived and tied to taxonomy version; if stale, call
archive_overviewagain. - For durable user preferences, write entries under
/user/preferenceswith labeluser-preference. - Storage is already scoped to the current conscious project. Avoid redundant folders like
engineering/<project-name>. - Internally,
archive-db.jsonis a hot index and full per-finding details are stored inrecords/*.json. - Updates are append-only at the finding level: each update/write appends a revision that can be listed/fetched later.
- With
DEVCON_CONSCIOUS_MEMORY_POLICY=encourage, archive tool callbacks include a reflection prompt to consider persisting reusable insights (while skipping one-off details). - With
DEVCON_CONSCIOUS_MEMORY_POLICY=require, after enough read-only archive exploration (..._THRESHOLD) further archive reads are blocked until at least onearchive_write/archive_update. archive_searchcan automatically fall back to cross-repo matches when strict repo scope returns none (repo_fallback).
Automatic behavior:
- Pre-launch retrieval seed runs automatically from the current task args/repo context.
- On successful runs, if the workspace started clean and now contains git changes, Devcon auto-captures a low-confidence finding into the archive (heuristic learning capture).
Conscious storage management commands:
devcon conscious list
devcon conscious inspect --current
devcon conscious tree --project <project-name-or-id>
devcon conscious wipe-project --current # asks for confirmation
devcon conscious wipe-project --project <project-name-or-id> --yes
devcon conscious wipe-all # asks for confirmation
devcon conscious wipe-all --yesNotes:
wipe-projectclears stored memory data for that project and stops its sidecar container if present.--projectaccepts either the human project name or the generated project id.wipe-allclears the full conscious root and stops alldevcon-conscious-*sidecar containers.- Both wipe commands require interactive confirmation unless
--yesis provided.
The bundled tools (codex, claude) point to an image named devcon:latest that bakes in both CLIs. On the first run Devcon checks whether that tag exists locally; if not, you’ll see a short explanation plus a Build it now? [y/N] prompt. Answer y and the CLI runs:
docker build -f docker/devcon/Dockerfile -t devcon:latest docker/devconThe build context lives inside the npm package, so everything works even if you run devcon codex from a random project. If you prefer a custom image, pass --image my/tag or set image in ~/.config/devcon/tools.json—auto-build only triggers for the default image.
To manually refresh the bundled images (for example to pick up new Codex CLI releases), run:
devcon update # rebuilds every tool with an auto-build config
devcon update codex # limit the rebuild to a single tool/imagedevcon update uses a cache-busting build argument to re-run the npm install layer without throwing away the whole Docker cache, so base layers stay hot while the bundled CLIs get refreshed.
When you need a clean slate (ignore every cached layer), use:
devcon rebuild # fully rebuilds every tool with an auto-build config
devcon rebuild codex # fully rebuild just the Codex/Claude base imageAdditional handy invocations:
devcon run --with-git -- ls # open an interactive shell (default image) and run a command
devcon run --temp-git # open a shell with a temp git repo (host .git stays masked)
devcon run --temp-git --export-patch # auto-export patch to .devcon/drafts on exitNotes on --temp-git:
- Host
.gitstays masked;GIT_DIR/GIT_WORK_TREEare set in the container and a sandboxed identity is pre-configured. - On first use, Devcon seeds an initial commit inside the temp repo so you can format-patch changes without specifying a range.
- Combine with
--export-patch[=PATH]to write patches automatically after the run; baseline commit is omitted from the patch. Uncommitted changes are snapshotted into a temp commit before export.
Devcon merges the built-in tools with an optional JSON file. Create ~/.config/devcon/tools.json (or point DEVCON_TOOLS_FILE somewhere else) to declare images, commands, and optional environment variables per tool:
{
"codex": {
"image": "devcon:latest",
"command": ["codex"],
"writablePaths": ["~/.codex"]
},
"claude": {
"image": "devcon:latest",
"command": ["claude"],
"writablePaths": ["~/.config/claude"]
},
"custom-codex": {
"image": "ghcr.io/my-org/codex-cli:latest",
"command": ["/bin/bash", "-lc", "codex --full-auto"],
"shareHome": true,
"homeReadOnly": true,
"writablePaths": ["~/.codex"],
"env": {
"CODEX_CONFIG": "/home/jannik/.config/codex/config.toml"
}
}
}Fields per tool:
image(required) – Docker image tag to run.command– Array describing the command to execute inside the container. Omit it to rely on the image entrypoint.env– Additional environment variables to inject.workdir– Alternative container working directory (defaults to/workspace/<current-folder-name>).shareHome– Override the CLI default for sharing the host home directory (default isfalse).homeReadOnly– Whentrue, the home directory mount is forced read-only; pair withwritablePathsto selectively re-enable write access to specific paths.writablePaths– Array of directories (absolute or~/-prefixed) that should remain mounted read/write even if the home directory is not mounted. The directories must live under your host home directory; missing directories are created automatically.
Environment toggles:
DEVCON_SHARE_HOME=1– Make home-directory sharing the default for all tools (equivalent to passing--homeevery time).DEVCON_HOME_READONLY=1– When the home directory is shared, mount it read-only by default. Individual tools can override viahomeReadOnly: falseor expose specificwritablePaths.
- Every run masks
.env,.env.*,.git/config,.git/index,.git/HEAD,.git-credentials, and.git/credentialsfrom the container by mounting empty placeholders over those paths after the workspace volume is attached. - To keep host repo metadata private by default, the entire
.gitdirectory is hidden inside the container unless you opt in (e.g., via a custom tool definition). - Opt-in git access: pass
--with-gitto unmask.gitfor a run; Devcon injects a sandboxed git identity (devcon-bot <devcon@example.com>) inside the container. - Containers inherit your host UID/GID so they have no more privileges than you already do.
- Each invocation runs with
--rmand without Docker daemon side-effects, ensuring there is no long-lived state. - The host home directory is unmounted by default; opt in explicitly and/or keep it read-only (
DEVCON_HOME_READONLY=1) while allowing write access only to trusted locations viawritablePaths. - The default Codex/Claude image builds locally and never ships secrets to a registry.
- Default sensitive patterns:
.env,.env.*,**/.env,**/.env.*,.git,.git-credentials. - Manage additional patterns in
~/.config/devcon/sensitive.jsonviadevcon sensitive:devcon sensitive list– show defaults, custom patterns, and what matches in the current workspace.devcon sensitive add "<pattern>"– add a glob-style pattern (e.g.secrets/**).devcon sensitive remove "<pattern>"– remove a custom pattern.
- The pattern scan skips common heavy directories (
node_modules,.git,dist,build,.next,.turbo,.cache,tmp,temp,.venv,venv,target,out,.yarn,.pnpm-store,coverage) to stay fast. Add or remove skip entries via~/.config/devcon/skip-scan.jsonordevcon skip-scancommands. - Masking is decided at container startup. New sensitive files created after
devconlaunches won’t be auto-masked; create placeholders (e.g.,touch path/.env) before starting or restart the session after adding secrets.
npm run dev– Execute the TypeScript entry point directly withts-node.npm run build– Compile intodist/.npm run clean– Remove build artifacts.
Feel free to open issues or PRs for additional agents or tighter security defaults.