@shaomingbo/devx
v0.5.0
Published
Devcontainer scaffolding CLI with per-project AI credential isolation
Maintainers
Readme
devx
Devcontainer scaffolding CLI with per-project AI credential isolation.
Generate production-grade .devcontainer/ configs for any project. Each project gets isolated Docker named volumes for Claude Code and Codex credentials, so switching between projects never leaks login state.
Prerequisites
- Docker Desktop or OrbStack
- Node.js >= 18
- Dev Container CLI (
npm install -g @devcontainers/cli)
Install
npm install -g @shaomingbo/devxOr run directly:
npx @shaomingbo/devx initQuick start
# 1. Generate .devcontainer/ config via interactive wizard
devx init
# 2. Build and start the dev container
devx up
# 3. Inside the container, log in to AI tools
claude login
codex loginCommands
devx init
Interactive wizard that generates .devcontainer/ configuration files:
devcontainer.json-- container settings, mounts, extensionsDockerfile-- base image and language runtimespost-create.sh-- mise, AI tools, package manager setup, ai-dotfiles symlinks, cc/cx aliasespost-start.sh-- startup hooksdocs/HANDOFF.md-- onboarding documentation for the project
The wizard asks for:
- Primary stack --
web-fullstack,web-spa, orrn-expo - Capabilities -- web, React Native (Expo)
- Package manager -- pnpm, npm, yarn, or bun
- Node version -- 22-lts, 20-lts, or latest
- Extra languages -- Python, Go, Rust, Java
- AI tools -- Claude Code, Codex CLI
Re-running devx init detects existing config and offers to reuse, modify, or start fresh. Modified files are detected via content hash before overwriting.
devx up
Pre-checks Docker, .devcontainer/ directory, devcontainer CLI availability, port conflicts, and disk space, then runs devcontainer up.
devx doctor
Runs 8 health checks and reports results:
| Check | What it verifies | |-------|-----------------| | Docker daemon | Docker is running and reachable | | Credential volumes | AI tool volumes exist for this project | | devcontainer.json | Valid JSON with required fields | | Disk space | At least 5 GB available | | Port availability | Configured ports are not occupied | | Volume age | Credential volumes are under 90 days old | | Compose file | docker-compose.yml is valid (if present) | | Compose services | Configured services exist in compose (if present) |
devx doctor # human-readable output
devx doctor --json # machine-readable JSONdevx add service <name>
Add a database or cache service. Generates docker-compose.yml and switches devcontainer.json to compose mode.
devx add service postgres
devx add service redisAvailable services:
| Service | Image | Default port | |---------|-------|-------------| | postgres | postgres:16 | 5432 | | redis | redis:7-alpine | 6379 | | mysql | mysql:8 | 3306 | | mongodb | mongo:7 | 27017 |
Services include healthchecks (where applicable), persistent named volumes, and default credentials for local development.
devx creds reset
Delete all AI credential volumes for the current project. Useful when credentials expire or you need to re-authenticate.
devx creds resetThe command checks for running containers before deletion and prompts for confirmation.
Credential isolation
Each project gets isolated Docker named volumes for AI tool credentials:
devx-creds-<projectHash>-claude -> /home/node/.claude
devx-creds-<projectHash>-codex -> /home/node/.codexThe projectHash is the first 12 hex characters of the SHA-256 hash of the project's absolute path, computed at runtime.
What is isolated:
- Claude Code login state (
~/.claude) - Codex CLI login state (
~/.codex)
What is shared (by design):
- Git config (
~/.gitconfig, read-only bind mount) - SSH keys (
~/.ssh, read-only bind mount)
Security note: This is convention-based isolation, not a security boundary. Any process with Docker socket access can read any named volume. Do not rely on this for sensitive production credentials.
Personal AI dotfiles
If the host has ~/ai-dotfiles/, devx up bind-mounts the entire directory into the container at /home/node/ai-dotfiles at runtime (only when it exists on your machine). post-create.sh then symlinks the per-tool subdirs into your container home: claude/* → ~/.claude/*, codex/* → ~/.codex/*. This picks up everything — CLAUDE.md, skills/, agent-docs/, etc. — with zero per-file maintenance. Credential files and machine-specific config like settings.json are deliberately excluded (see below).
The mount is not baked into the committed .devcontainer/ config, so a teammate without ~/ai-dotfiles is never affected and devx up never fails on a missing bind source (the symlink step silently skips when the directory is absent).
What is and isn't linked:
- The symlink step walks each subdir's top-level contents. Hidden entries like
.gitare skipped by the glob, and a top-level denylist of filenames is never linked: credential-like files (.credentials.json,auth.json,.env) so your container keeps its own isolated-volume credentials, plus machine-specific config (settings.json,settings.local.json) so host-specific paths/preferences don't follow into the container —settings.jsonis seeded with a container default instead (see below), whilesettings.local.jsonis simply never linked and has no seed. If an earlier devx version had already symlinked one of these denylisted files, re-running post-create removes that stale link (only when it still points back at the host source) so the seeded default, where one exists, takes over; a real file or a symlink you redirected elsewhere is left untouched. This filter only applies to the top level of each tool subdir; same-named files nested inside a wholesale-linked directory (e.g.skills/) are not filtered. Because the whole~/ai-dotfilesis bind-mounted, all of its contents are visible to the container regardless of symlinks, so do not store real credentials anywhere inside~/ai-dotfiles. - If a real (non-symlink) file or directory already exists at the target, it is kept, not overwritten. This is also your opt-out escape hatch: replace a symlink with a real file or directory inside the container and post-create will leave it alone on the next run.
The mount is writable. devcontainer up --mount has no readonly option, so processes inside the container can modify your host ~/ai-dotfiles files — and because the whole directory (including its .git) is exposed, if your ~/ai-dotfiles is auto-synced (e.g. git push) those edits can propagate to your other machines. Only rely on this if you trust the code you run in the container.
Shell aliases. post-create adds cc and cx shortcuts to ~/.bashrc and ~/.zshrc for each enabled tool: cc → claude --dangerously-skip-permissions, cx → codex --dangerously-bypass-approvals-and-sandbox. These bypass flags are intentional — the container is the isolation boundary. Note cc shadows the system C compiler inside the container; call /usr/bin/cc directly if you need it.
settings.json is seeded, not linked. Because your host settings.json is denylisted (it tends to carry host-specific hook paths like /Users/you/... and machine-local preferences that don't resolve inside the container), the container seeds its own default instead. To customize per-container, replace the seeded ~/.claude/settings.json with a real file — post-create's seed guard leaves an existing real file alone on the next run.
IDE support
VS Code (primary): Extensions and settings are configured in devcontainer.json under customizations.vscode.
Zed (experimental): Set ide.primary to "zed" or "both" in .devx/config.yaml to generate .zed/settings.json with mapped LSP and formatter settings.
Configuration
Project configuration is stored in .devx/config.yaml (committed to git for team sharing). Example:
version: 1
project:
name: my-app
primaryStack: web-fullstack
capabilities:
- web
runtime:
node: 22-lts
packageManager: pnpm
extraLanguages: []
aiTools:
enabled:
- claude-code
- codex-cli
credentialStrategy: isolated-volume
services: []
ports:
- 3000
- 5173
- 9229
ide:
primary: vscodeDevelopment
git clone https://github.com/shaomingbo/devcontainer-cli.git
cd devcontainer-cli
npm install
npm run build
npm test # 283 tests
npm run dev # watch modeLicense
MIT
