Ephemeral container sandboxes for running AI coding assistants safely.
cd sandboxes/agentman
./run.zsh --workspace ~/code/myproject --publicAI coding assistants execute code, install packages, and access your filesystem. Running them with unrestricted access creates exposure—to your SSH keys, cloud credentials, and other projects.
Testman provides ephemeral, isolated containers where AI tools operate with access limited to a single project directory. Each session starts fresh. Syscall-level auditing captures everything the agent does.
Designed to work with kodemachine for defense in depth: VM isolation at the host level, container isolation at the project level.
┌─────────────────────────────────────────────────────────────┐
│ Host / VM │
│ │
│ testman/sandboxes/agentman/run.zsh │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Ephemeral Container (podman --rm) │ │
│ │ - AI assistants execute here │ │
│ │ - Filesystem: ~/workspace (mounted project dir) │ │
│ │ - Syscall auditing via strace │ │
│ │ - Destroyed on exit │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ~/.testman/containers/<project>/ │
│ config/ → persists AI conversation history │
│ logs/ → syscall and filesystem audit logs │
└─────────────────────────────────────────────────────────────┘
cd sandboxes/base
# Public image (privacy-safe, no personal config)
./build.zsh --public
# Private image (requires TESTMAN_SSH_KEY and TESTMAN_DOTFILES env vars)
./build.zsh --privatecd sandboxes/agentman
# Basic usage
./run.zsh --workspace ~/code/myproject --public
# With syscall auditing
./run.zsh --workspace ~/code/myproject --public --audit
# With port mapping for dev servers
./run.zsh --workspace ~/code/myproject --public --map-ports 3000,8080# AI assistants available (installed at runtime)
claude # Claude Code
gemini # Google Gemini CLI
aider # Aider
# ... and more
# Your project is at ~/workspace
cd ~/workspace| Directory | Purpose |
|---|---|
sandboxes/base/ |
Foundation image and ephemeral runner |
sandboxes/agentman/ |
AI coding assistants (Claude, Gemini, Aider, etc.) |
sandboxes/TEMPLATE/ |
Template for creating new tool-specific sandboxes |
sandboxes/lib/ |
Shared functions |
Every run creates a fresh container with --rm. No state accumulation.
Persistence comes from mounted volumes:
~/.testman/containers/<project>/config/→ AI conversation history~/.testman/containers/<project>/logs/→ Audit logs~/workspace→ Your project directory
Enable with --audit:
./run.zsh --workspace ~/project --public --auditLogs syscalls (openat, read, write, connect, execve) and filesystem
events (modify, create, delete) to ~/.testman/containers/<project>/logs/.
Project names are auto-generated from workspace paths:
./run.zsh --workspace ~/code/webapp --public
# → Project name: webapp-a8f1 (basename + hash)Override with --name:
./run.zsh --name myproject --workspace ~/code/webapp --publicExpose container ports to host:
./run.zsh --workspace ~/project --public --map-ports 3000,8080,9090Ubuntu 24.04 ARM64 with:
- Shell: zsh, neovim, vim, tmux, starship prompt
- Tools: bat, ripgrep, fd, jq, htop, tree, httpie
- Languages: Node.js 20, Python 3.12, Go 1.23 (via asdf)
- Browser automation: Playwright + Chromium
- Security: strace, inotify-tools (for auditing)
- Containers: Podman (for nested container workflows)
- GUI: XFCE4, VNC, Firefox, Chromium (for headed mode)
For personal development with SSH access and dotfiles:
# Set environment variables
export TESTMAN_SSH_KEY="$(cat ~/.ssh/id_ed25519.pub)"
export TESTMAN_DOTFILES="https://github.com/user/dotfiles.git"
# Build private image
./build.zsh --privateThe private image includes:
- SSH server (port 22)
- Your dotfiles (cloned from TESTMAN_DOTFILES)
- Your SSH key for authentication
Use the template for tool-specific sandboxes:
cp -r sandboxes/TEMPLATE sandboxes/mytoolEdit sandboxes/mytool/run.zsh and replace placeholders:
{TOOL_NAME}→ Human-readable name{TOOL_COMMAND}→ Command to check{INSTALL_COMMAND}→ Installation command{PACKAGE_NAME}→ Package name
Tools install at runtime—no separate Containerfile needed.
- Ephemeral: Fresh container every run, no state accumulation
- Isolated: Each project gets separate config and logs
- Auditable: Syscall tracing for untrusted tools
- ARM64 only: Optimized for Apple Silicon and ARM servers
- Podman only: Rootless containers, no Docker dependency
- Podman
- ARM64 host (Apple Silicon Mac, ARM Linux server)
- For private builds:
TESTMAN_SSH_KEYandTESTMAN_DOTFILESenvironment variables
- kodemachine - Ephemeral VM manager for macOS. Use with testman for defense in depth.
- Blog: Disposable Dev Environments - Architecture overview
MIT