A general-purpose development container: the Claude, Codex and Antigravity CLIs
plus everyday dev tooling, on Ubuntu 24.04.
Built for sandbox work — spin one up on any machine with Docker and get the same environment every time, without reinstalling toolchains by hand.
Quick start · What's inside · Helpers · Details · Layout
Two ways to get it. Both give the same image.
| Pull the published image | Build it yourself |
|---|---|
docker run -it --rm \
ghcr.io/h-network/base:latestNo clone, no build. |
git clone https://github.com/h-network/base.git
cd base
docker compose build
docker compose run --rm dev |
Published for linux/amd64 and linux/arm64, so Docker pulls whichever matches
the machine. :latest tracks main; version tags (:1, :1.2, :1.2.3) are
published from git tags and are what you want to depend on — they do not move.
Building always fetches the current release of each agent CLI, so a rebuild is how you refresh them. A published tag is frozen at whenever it was built.
| Agent CLIs | claude, codex, agy |
| Helpers | startAgent, setupConfigDir |
| Dev | git, gh, python3, python3-venv, python3-pip, build-essential |
| Shell | tmux (configured), vim-tiny, openssh-client, sudo |
| Base | ubuntu:24.04, UTF-8 locale |
Roughly 450 MB.
startAgent # $AGENT_CLI, default claude
startAgent codex
startAgent claude --resume # extra arguments pass throughEach CLI spells "don't stop to ask me" differently — --dangerously-skip-permissions
for claude and agy, --dangerously-bypass-approvals-and-sandbox for codex.
startAgent knows which is which so you don't have to.
Warning
Approval prompts are skipped by default, because the flags above are meant
for exactly this situation: a disposable container running as an unprivileged
user. That assumption breaks the moment you bind-mount a host directory you
care about — set AGENT_SKIP_PERMISSIONS=0 to keep the prompts.
| variable | |
|---|---|
AGENT_CLI |
default CLI when none is named (default claude) |
AGENT_SKIP_PERMISSIONS |
1 (default) skips approval prompts, 0 keeps them |
AGENT_CLAUDE_TOOLS |
claude's tool list (default Bash Read Write Edit Glob Grep; empty = unrestricted) |
Only claude can restrict its tool set from the command line — agy and codex have no equivalent, so they run with their full set.
setupConfigDir work # → ~/.claude-work + ~/.codex-work
setupConfigDir work --same # ...and copy the existing logins across
setupConfigDir # show what this shell is using
setupConfigDir default # back to ~/.claude and ~/.codexExporting CLAUDE_CONFIG_DIR by hand points the CLI at an empty directory,
so it quietly runs on stock defaults instead of the profile you set up.
setupConfigDir copies your profile in first — settings.json, config.toml,
and any skills/, agents/ or CLAUDE.md beside them. Session history and
logins are left behind, which is what makes the new dir separate; --same
copies the logins too.
It sets CLAUDE_CONFIG_DIR and CODEX_HOME together, and applies to the
calling shell only — a new shell is back on the defaults.
Runs as ubuntu (uid 1000), not root
The agent CLIs misbehave under root — Claude Code refuses
--dangerously-skip-permissions there. sudo is available without a password.
Nothing is bind-mounted by default
compose.yaml uses named volumes, so agent logins and /workspace survive
--rm without inheriting host file ownership. Work is expected to live in git,
cloned inside the container.
If you do bind-mount a host directory, note that the image is uid 1000 — on a
host where you are not uid 1000, writes will fail. Either chown -R 1000:1000
the directory or run with --user $(id -u):$(id -g).
Python packages need a venv
Ubuntu 24.04 is PEP 668 managed, so system-wide pip install is refused by
design:
python3 -m venv .venv && .venv/bin/pip install <package>No credentials are baked into the image
Authenticate inside the container (claude, codex, gh auth login); the
compose volumes persist it.
Dockerfile the image
LICENSE Apache 2.0
NOTICE what the licence covers, and what it does not
compose.yaml build + run, named volumes
tmux.conf copied to ~/.tmux.conf
startAgent.sh → /usr/local/bin/startAgent
setupconfigdir.sh → /etc/profile.d/ (a shell function, so it can export)
.github/workflows/build.yml builds and publishes to GHCR
docs/assets/banner.svg the banner above
docs/assets/badges/ the badges above — self-hosted, not shields.io, so
the README fetches nothing outside github.com
docs/assets/mkbadges.py regenerates docs/assets/badges/
Push a version tag; the workflow builds both architectures and publishes them.
git tag v1.2.3 && git push origin v1.2.3main publishes :main and :latest on every push. There are no tarball
releases — the image is pulled from GHCR.
Apache License 2.0. Every file in this repository carries an
SPDX-License-Identifier: Apache-2.0 header, and the image declares
org.opencontainers.image.licenses=Apache-2.0.
That covers this repository's own files — the Dockerfile, scripts and config.
It does not cover what the build installs into the image: Ubuntu's packages,
gh, and the three agent CLIs all keep their own terms. NOTICE has
the details, and both files ship inside the image at
/usr/share/doc/h-network-base/.
Note
The agent CLIs are not open-source components. Publishing an image built from this repository redistributes them, which the Apache grant here says nothing about — check each vendor's terms first.