Docker Environments
How Nemesis8 builds and manages isolated agent containers.
Overview
Each Nemesis8 session runs in a Docker container built from a single Dockerfile maintained in the repo. The container bundles every AI provider CLI, a Python MCP venv, the Rust entry binary, and a standard set of system tools.
Containers are ephemeral by design — they start clean, receive your credentials and working directory via bind mount, run the agent, and are removed on exit. Persistent state (sessions, provider configs) lives on the host under ~/.nemesis8/.
What's in the image
| Layer | Contents |
|---|---|
| Base | node:24-slim — Node.js LTS on Debian Slim |
| System tools | git, gh, curl, jq, ffmpeg, fzf, ripgrep, python3, bubblewrap, tini |
| Rust toolchain | rustup stable — installed to /opt/rust/ (not shadowed by bind mounts) |
| Provider CLIs | claude-code, codex, gemini-cli, openclaw — installed globally via npm |
| Python MCP venv | /opt/mcp-venv — all MCP tool dependencies pre-installed |
| MCP tools | /opt/mcp-installed/ — Python MCP servers copied at build time |
| Entry binary | /usr/local/bin/nemisis8-entry — built from source during image build |
Building the image
# Default build — all four providers (claude, codex, gemini, openclaw)
nemisis8 build
# Slim build — only what you need
nemisis8 build --build-arg INSTALL_PROVIDERS=claude,codex
# Add optional extras (e.g. BAML)
nemisis8 build --build-arg INSTALL_EXTRAS=baml
# Force full rebuild
nemisis8 build --no-cache
The INSTALL_PROVIDERS build arg controls which provider CLIs are installed. Valid values: claude, codex, gemini, openclaw. Ollama sessions reuse the codex binary with an alternate OPENAI_BASE_URL — no separate install needed.
The Rust entry binary is compiled inside the Docker build. The first build takes a few minutes. Subsequent builds are fast because Docker caches all layers above the source COPY step.
Volume mounts
When a session starts, Nemesis8 bind-mounts several host paths into the container:
| Host path | Container path | Purpose |
|---|---|---|
| ~/.nemesis8/home | /opt/codex-home | Provider home dir — auth files, provider configs |
| <working dir> | /workspace | Your project — readable and writable by the agent |
| ~/.nemesis8/sessions | /opt/sessions | Session history and context persistence |
The provider home dir (/opt/codex-home) is where the entry binary writes provider configs (MCP servers, system prompt, API keys) before handing off to the provider CLI. It survives container restarts because it's host-mounted.
The entry binary
nemisis8-entry is the Rust binary that runs inside the container as PID 1 (via tini). It is responsible for:
- Reading the provider definition from
/opt/defaults/providers/<provider>.toml - Writing the provider's config file (MCP servers, system prompt injection)
- Setting up environment variables (API keys, model selection, env overrides)
- Exec-ing into the provider CLI (e.g.
claude,codex,gemini)
# The entry binary is called automatically — you don't invoke it directly.
# To see what it would do for a provider:
nemisis8 --provider claude --dry-run interactive
MCP tool servers
MCP (Model Context Protocol) servers are the tools available to the agent inside the container. They are Python scripts in /opt/mcp-installed/, pre-installed at image build time.
# List what's registered
nemisis8 mcp list
# Add a custom MCP server (persisted to provider config)
nemisis8 mcp add my-tool python3 /opt/mcp-installed/my_tool.py
MCP configs are written per-provider into the appropriate config format (TOML for Codex, JSON for Claude/Gemini) before each session start.
Cache invalidation
The Dockerfile injects a CACHE_BUST build arg above the COPY MCP/ and Rust build steps. Nemesis8 passes a timestamp as this arg so that a nemisis8 build always re-copies MCP sources and recompiles the entry binary — while keeping the slow provider install layers cached.
# Nemesis8 does this automatically:
docker build --build-arg CACHE_BUST=$(date +%s) ...
Provider CLI layers (the npm install step) are only invalidated when you explicitly pass --no-cache or when install-providers.sh changes. Normal nemisis8 build reuses those cached layers.