---
title: Docker Images
description: "Choosing and building the image an agent runs in — what the agent images contain, per-agent CLIs and config paths, building with heretic-cli image, custom bases, and matching container UIDs"
canonical: https://giglabo.com/heretic/docs/heretic-cli/configuration/docker-images
locale: en
---

# Docker Images

> Markdown twin of https://giglabo.com/heretic/docs/heretic-cli/configuration/docker-images
> Fetch this instead of the HTML page: same content, a fraction of the bytes.
> Site structure and the full page list for agents: https://giglabo.com/llms.txt

Choosing and building the image an agent runs in — what the agent images contain, per-agent CLIs and config paths, building with heretic-cli image, custom bases, and matching container UIDs

Every agent runs in a container, and the profile's `image:` field decides which one:

```yaml
# ~/.heretic/agents/claude.yaml
image: giglabo/claude-heretic:latest
```

The image is pulled automatically on `heretic-cli run <agent>` when it is not present locally. A failed pull stops the run with `Failed to pull image <image>: …`.

## Choosing an image

| Option | When |
|--------|------|
| `giglabo/claude-heretic:latest` | the default Claude Code image, and what `heretic-cli init` suggests |
| `heretic-cli image build …` | you need extra toolchains, a different agent CLI, or a specific UID |
| your own Dockerfile | you already maintain a dev image and want to add an agent CLI to it |

```bash
heretic-cli image build                       # → heretic-agent:latest (Claude)
heretic-cli image build --agent copilot       # → heretic-agent-copilot:latest
heretic-cli image build --agent all --combined -n heretic-agent -t all
```

Full flag reference: [`heretic-cli image`](https://giglabo.com/heretic/docs/heretic-cli/commands/image).

## What a heretic agent image contains

Built by `heretic-cli image build`, on `node:22-bookworm-slim` unless you pass `--base`:

| Component | Purpose |
|-----------|---------|
| Node.js 22 | runtime for the agent CLIs, which are npm packages |
| npm, plus yarn and pnpm via corepack | JavaScript package managers |
| git | repository work inside the container |
| `gh` (GitHub CLI) | PRs, issues and reviews from inside the agent — on by default, `--no-github-cli` removes it |
| curl, jq | required by the build-sidecar client |
| openssh-client | required by the SSH backend |
| vim, unzip, gnupg, xz-utils, ca-certificates | everyday basics |
| `/opt/sidecar/{sidecar-exec,ssh-exec}` plus a writable `wrappers` directory on `PATH` | tool-execution backends |
| `/entrypoint.sh` baked as `ENTRYPOINT` | root mode, wrapper generation, interactive and workflow modes |
| non-root `agent` user, uid/gid 1000 | matches the common host uid so bind mounts stay writable |

Optional toolchains — Python, Go, Java, Rust, Docker CLI — are **not** included unless you ask for them (`--with-python`, `--with-go`, `--with-java`, `--with-rust`, `--with-docker`, or `--with-all`).

> **Note: Node.js is always installed**
>
> Even without `--with-node`, Node is present on non-`node:` bases because the agent CLIs are npm packages. `--with-node` adds corepack (yarn, pnpm) and lets you pin the version with `--node-version`.

## Agent CLIs

| `--agent` | npm package(s) | Configuration inside the container | `agent_type` for the profile |
|-----------|----------------|-----------------------------------|------------------------------|
| `claude` | `@anthropic-ai/claude-code`, `mcp-remote` | `~/.claude/settings.json`, `/workspace/.mcp.json` | `claude` |
| `copilot` | `@github/copilot` | `~/.copilot/mcp-config.json` | `copilot-cli` |
| `opencode` | `opencode-ai` | `~/.config/opencode/config.json` | `generic` |
| `gemini` | `@google/gemini-cli`, `mcp-remote` | environment only | `generic` |

`agent_type` is what heretic uses to decide where to mount the generated MCP config and which home directory to bind — see [Agent Profiles](https://giglabo.com/heretic/docs/heretic-cli/configuration/agent-profiles).

## Changing the image

```bash
heretic-cli agents edit claude          # guided
heretic-cli agents edit claude --editor # full YAML
```

```yaml
# ~/.heretic/agents/claude.yaml
image: my-custom-agent:v2
```

Per project, via a local override:

```yaml
# .heretic/cli/claude.yaml
extends: claude
image: my-project-agent:latest
```

## Recipes

**Full-stack: JavaScript plus Python**

```bash
heretic-cli image build \
  --agent claude \
  --with-python --python-version 3.12 \
  -n claude-fullstack
```

```yaml
image: claude-fullstack:latest
```

**Agent that builds containers**

```bash
heretic-cli image build --agent claude --with-docker -n claude-docker
```

```yaml
image: claude-docker:latest
dind: true      # mounts the host Docker socket
```

> **Warning: Prefer sidecars over the Docker socket**
>
> `dind: true` gives the container host-level control of Docker. If all you need is a toolchain the image lacks, use [build sidecars](https://giglabo.com/heretic/docs/heretic-cli/configuration/sidecars) instead — no socket, no privileged mode.

**Polyglot CI image, multi-arch, pushed to a registry**

```bash
heretic-cli image build --agent claude --with-all \
  -r ghcr.io/acme -n heretic-agent -t 1.0.0 -a both -p
```

**Slim image plus builders for the toolchains**

```bash
heretic-cli image build --agent claude -n claude-slim
heretic-cli image build-sidecar node
heretic-cli image build-sidecar python
```

```yaml
image: claude-slim:latest
volumes:
  - { source: "${CWD}", target: /workspace }
tool_backends:
  sidecars:
    - { runtime: node, image: heretic-builder-node:latest }
    - { runtime: python, image: heretic-builder-python:latest }
```

## Matching UIDs

Bind-mounted files are created with the container user's uid. If your host account is not uid 1000, build with matching ids so the agent does not leave root-owned or unreadable files behind:

```bash
heretic-cli image build --agent-uid "$(id -u)" --agent-gid "$(id -g)"
```

The image also chowns `/opt/sidecar/wrappers` to that uid, and the entrypoint refuses to start the tool backends if the directory is not writable (`FATAL: /opt/sidecar/wrappers is not writable by …`). Changing the container user afterwards with `extra.user` can trip that check.

## Extending an existing image

```dockerfile
FROM my-company/dev-base:latest

RUN npm install -g @anthropic-ai/claude-code mcp-remote

# Optional: tool-backend support
COPY sidecar-exec /opt/sidecar/sidecar-exec
COPY ssh-exec /opt/sidecar/ssh-exec
RUN chmod +x /opt/sidecar/* \
 && mkdir -p /opt/sidecar/wrappers \
 && chown 1000:1000 /opt/sidecar/wrappers
ENV PATH="/opt/sidecar/wrappers:${PATH}"

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/bin/bash"]
```

Generate the pieces so they stay in sync with your CLI version:

```bash
heretic-cli image generate --format sidecar-exec > sidecar-exec
heretic-cli image generate --format ssh-exec     > ssh-exec
heretic-cli image generate --format entrypoint   > entrypoint.sh
```

> **Warning: Without the baked ENTRYPOINT some features silently do nothing**
>
> Root mode (`--root`) and the tool backends depend on `/entrypoint.sh` running as the container entrypoint. On an image without it, wrappers are never generated. `heretic-cli run --root` works around this by bind-mounting the CLI's embedded entrypoint over `/entrypoint.sh`.

## Verifying an image

```bash
docker run --rm -it heretic-agent:latest bash -lc 'claude --version; node -v; gh --version'
docker run --rm heretic-agent:latest bash -lc 'ls /opt/sidecar; echo $PATH'
heretic-cli image build --dry-run          # inspect the Dockerfile and entrypoint first
```

## Next Steps

- [image](https://giglabo.com/heretic/docs/heretic-cli/commands/image) — every build flag and the generated Dockerfile
- [Sidecars](https://giglabo.com/heretic/docs/heretic-cli/configuration/sidecars) — toolchains without image bloat
- [Agent Profiles](https://giglabo.com/heretic/docs/heretic-cli/configuration/agent-profiles) — wiring the image into a profile
- [Standalone image guide](https://giglabo.com/heretic/docs/heretic/docker-images) — the shell-script builder and Windows notes

## Related

- HTML version of this page: https://giglabo.com/heretic/docs/heretic-cli/configuration/docker-images
- Site map for agents: https://giglabo.com/llms.txt
