AI agent development container with Claude Code, Codex, RTK, mise, APM, entire, and git-wt pre-installed.
Add to your project's compose.yml:
services:
agent:
image: ghcr.io/syati/agent-stack:latest
volumes:
- .:/workspace
- /var/run/docker.sock:/var/run/docker.sock # host Docker access
- ${HOME}/.gitconfig:/home/agent/.gitconfig:ro # git config
- ${HOME}/.claude:/home/agent/.claude
- ${HOME}/.codex:/home/agent/.codex
- mise-data:/home/agent/.local/share/mise
env_file:
- .env
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
mise-data:- Docker socket: allows the container to control host Docker (
docker compose run,docker exec, etc.). Remove if not needed. - Bind mounts (
~/.claude,~/.codex): persist auth and session data on the host. Survivesdocker compose down -v. - Named volume (
mise-data): persists mise-installed runtimes across container recreations. Cleared bydocker compose down -v. - gitconfig: mounts host git config (read-only) so
git commitandgit pushwork inside the container.
Start the container and connect:
docker compose up -d
docker compose exec -it agent bashUse docker compose exec (not docker attach). Each exec spawns an independent process, so multiple agents can run in parallel without stdin conflicts.
With sheldon, add to ~/.config/sheldon/plugins.toml:
[plugins.agent-stack]
github = "Syati/agent-stack"Or source the plugin directly in your ~/.zshrc:
source /path/to/agent-stack/agent-stack.plugin.zshMultiple instances can run in parallel — each agent call creates a separate container. Use git-wt worktrees to avoid file conflicts when multiple agents work on the same repo.
Runs as non-root user agent (home: /home/agent, shell: zsh). Working directory is /workspace.
| Tool | Description |
|---|---|
| Claude Code | Anthropic's AI coding CLI |
| Codex | OpenAI's AI coding CLI |
| RTK | Token-optimized CLI proxy (60-90% token savings) |
| mise | Dev tool version manager |
| APM | Agent Package Manager for MCP/skills |
| entire | AI session capture for git |
| git-wt | Simplified git worktree management |
| gh | GitHub CLI |
| ripgrep | Fast grep (auto-used by RTK) |
| agent-browser | Browser automation for AI agents |
| build-essential | C/C++ compiler toolchain |
Create ~/.agent-stack.env (used by the shell function):
GITHUB_PERSONAL_ACCESS_TOKEN=ghp_...
If you use 1Password CLI, you can use op:// references:
GITHUB_PERSONAL_ACCESS_TOKEN=op://Private/github-pat/credential
When op is available, references are resolved via op inject automatically. Without op, the file is passed as-is.
See compose.yml for a working example.
git clone https://github.com/Syati/agent-stack.git
cd agent-stack
cp .env.example .env
# edit .env with your keys
make build # build image
make dev # start container
make shell # open shell
make claude # run Claude Code
make codex # run Codex
make clean # stop and removeagent-browser is pre-installed in the container. Start Chrome on the host with remote debugging, then connect from the container.
Host side (make chrome or manually):
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 \
--remote-debugging-address=0.0.0.0 \
--user-data-dir=$HOME/.chrome-agent \
--no-first-run \
--no-default-browser-check \
--password-store=basic \
--disable-blink-features=AutomationControlledContainer side (run chrome-connect to resolve WebSocket URL and connect):
chrome-connectPort is configurable via CHROME_REMOTE_PORT in .env (default: 9222).
MIT