Skip to content

thomaspeklak/agent-sandbox

Repository files navigation

agent-sandbox

agent logos in a sandbox

ags is a Rust CLI that launches AI coding agents inside a rootless Podman sandbox.

It is designed to keep your host clean while still giving agents controlled access to your repo, selected tools, and selected secrets.

Documentation map

  • README.md (this file): quick start + daily usage
  • docs/COMMANDS.md: detailed command behavior and side effects
  • docs/CONFIG.md: full config schema and semantics
  • docs/GLIMPSE.md: user-facing Glimpse/host UI setup and usage
  • docs/TROUBLESHOOTING.md: common problems and fixes
  • docs/ARCHITECTURE.md: internal architecture overview
  • CONTRIBUTING.md: contributor workflow and quality checklist

What this tool provides

  • Rootless containerized agent runs (Podman)
  • Multi-agent support:
    • pi
    • claude
    • codex
    • gemini
    • opencode
    • shell (interactive bash with agent environments mounted)
  • First-run setup for SSH auth + signing keys
  • Persistent per-agent host volumes by default (lockdown uses ephemeral staged homes)
  • Configurable mounts, tool binaries, and secret sources
  • Optional hardened --lockdown runs for inspecting untrusted/foreign repos with reduced host exposure
  • Optional browser sidecar support for browser-enabled workflows
  • Auth proxy for secure sandbox browser opens and OAuth loopback callbacks
  • Health checks via ags doctor
  • Convenience alias/wrapper generation via ags create-aliases

Requirements

Required on host:

  • Rust toolchain (to build/run ags from source)
  • Podman (rootless recommended)
  • git
  • ssh-keygen
  • ssh-add
  • bash

Optional but useful:

  • make (for convenience targets)
  • secret-tool (GNOME keyring/libsecret integration)
  • Browser executable (for --browser mode)
  • zenity or kdialog (for auth proxy allow/deny prompts; auto-denied if neither is available)

Tip: run ags doctor after setup to verify your environment.


Build and install

From repository root:

# build debug binary
cargo build -p ags

# build optimized release binary
cargo build -p ags --release

Run without installing:

cargo run -p ags -- --agent pi

Optional self-link into ~/.local/bin/ags:

cargo run -p ags -- install --link-self

If an existing file/symlink should be replaced:

cargo run -p ags -- install --link-self --force

You can also use Make targets (see below).


First-time setup

1) Install baseline assets and config layout

cargo run -p ags -- install

This writes:

  • ~/.config/ags/Containerfile
  • ~/.config/ags/tmux.conf
  • ~/.config/ags/pi/extensions/guard.ts
  • ~/.config/ags/pi/settings.json (if missing)

2) Create and edit config

Use config/config.example.toml as your template:

mkdir -p ~/.config/ags
cp config/config.example.toml ~/.config/ags/config.toml

Then replace placeholders with real values and paths.

Optional per-repo overrides can live at:

PROJECT_ROOT/.ags/config.toml

When present, AGS loads your user/global config first, then applies the repo-local overlay. Repo-local scalar/table fields win, while repeatable sections like [[mount]] are appended so projects can add mounts without replacing your base config.

3) Run setup

cargo run -p ags -- setup

setup will:

  • Generate SSH keys if missing:
    • ~/.ssh/ags-agent-auth
    • ~/.ssh/ags-agent-signing
  • Print public keys so you can add them to GitHub
  • Ensure Pi guard/settings assets exist in the host path mounted to /home/dev/.pi
  • Optionally prompt to store configured secrets via secret-tool

4) Build/update sandbox image and agent installs

cargo run -p ags -- update
cargo run -p ags -- update-agents

5) Verify

cargo run -p ags -- doctor
cargo run -p ags -- --agent shell -- -lc 'br --version && bv --version && dcg --version && tmux -V && test -f ~/.tmux.conf'

Quick start (Makefile)

Equivalent convenience flow:

make setup
make doctor
make update
make update-agents
make run

Available targets:

  • make setup
  • make doctor
  • make update
  • make update-agents
  • make run
  • make run-browser
  • make install
  • make install-self
  • make uninstall
  • make aliases

Daily usage

Run Pi agent:

ags --agent pi

Run inside a tmux session (opt-in):

ags --agent pi --tmux

Run with browser sidecar:

ags --agent pi --browser

Run in hardened lockdown mode for untrusted repos:

ags --agent claude --lockdown

Lockdown keeps network access and workspace visibility, but disables secrets, SSH agent forwarding, generic config/tool mounts, host bridges/sidecars, and direct mounting of real agent home state. Instead AGS stages a sanitized ephemeral agent home/runtime for the selected agent and discards session/history artifacts when the run exits.

Disable AGS Pi/Claude guards for one run:

ags --agent pi --yolo
ags --agent claude --yolo

Run other agents:

ags --agent claude
ags --agent codex
ags --agent gemini
ags --agent opencode
ags --agent shell

Pass arguments through to the underlying agent CLI using --:

ags --agent pi -- --continue
ags --agent claude -- --model sonnet
ags --agent claude --defaults -- --model opus

Use --defaults / -D to prepend AGS-managed passthrough defaults for the selected harness. Today that means Claude gets --strict-mcp-config --dangerously-skip-permissions, Gemini gets --yolo, and other agents currently add nothing.

tmux inside the sandbox

The sandbox image includes tmux with a minimal version-controlled config for team-pane workflows. Defaults include:

  • default prefix remains Ctrl-b
  • mouse support enabled
  • pane/window creation starts in the current pane directory
  • xterm-kitty terminal support via kitty-terminfo
  • no plugin manager dependency

If you want the agent itself to start inside tmux, pass --tmux:

ags --agent pi --tmux
ags --agent shell --tmux

This is intentionally not the default. If tmux is reported as missing when using --tmux, rebuild the sandbox image first:

ags update

Quick check:

ags --agent shell -- -lc 'tmux -V && test -f ~/.tmux.conf && tmux new-session -d -s smoke && tmux kill-session -t smoke'

Use a non-default config file:

ags --agent pi --config /path/to/config.toml

MCP auth persistence

MCP servers that use OAuth (e.g. Linear) store auth tokens in ~/.mcp-auth inside the container. Without a persistent mount, tokens are lost on every session restart. Add this to your config:

[[mount]]
host = "$HOME/.mcp-auth"
container = "/home/dev/.mcp-auth"
mode = "rw"
kind = "dir"
create = true

To skip the allow/deny dialog for known OAuth providers:

[auth_proxy]
auto_allow_domains = ["mcp.linear.app"]

Host service access from inside sandbox

ags runs agent CLIs inside the container, so localhost refers to the container itself.

To connect to services running on your host machine, use host.containers.internal instead.

ags also exports runtime hints inside the container:

  • AGS_HOST_SERVICES_HOST=host.containers.internal
  • AGS_HOST_SERVICES_HINT (human-readable reminder)

And for agents with prompt hooks (pi, claude, codex), ags injects a short startup hint into the agent prompt context.

Example:

ags --agent shell -- -lc 'curl http://host.containers.internal:3000/health'

Postgres example (psql is available in the sandbox image after ags update):

ags --agent shell -- -lc 'PGPASSWORD="${PGPASSWORD:-postgres}" psql -h "${AGS_HOST_SERVICES_HOST}" -p "${PGPORT:-5432}" -U "${PGUSER:-postgres}" "${PGDATABASE:-postgres}"'

Tip: add PGPASSWORD, PGUSER, PGDATABASE, and PGPORT to [sandbox].passthrough_env if you want host values to flow into the container automatically.

Host-owned Glimpse windows

If you want sandboxed agent code to open Glimpse windows on your host desktop, enable [host_ui] in your config.

Start here:

  • docs/GLIMPSE.md for setup and troubleshooting
  • docs/CONFIG.md for the [host_ui] field reference

Commands reference

Core commands

  • ags setup — generate keys, ensure Pi assets in mounted host path, optional keyring secret setup
  • ags doctor — run environment + config health checks
  • ags update — rebuild container image from Containerfile and refresh bundled br/bv/dcg binaries
  • ags update-agents — install/update agent CLIs in persistent volumes
  • ags install [--link-self] [--force] [--add-agent-mounts] — install assets/config layout, optional self-link, optional config mount block append
  • ags uninstall — currently reserved/no-op cleanup
  • ags create-aliases — create managed wrappers and/or shell alias blocks
  • ags completions --shell <bash|zsh|fish> — print shell completion script

create-aliases options

ags create-aliases --mode wrappers|aliases|both --shell fish|zsh|bash --force
  • default mode: wrappers
  • if --shell omitted, shell is autodetected from $SHELL

Shell completions

# add extra same-path directory mounts for a single run
ags --agent claude -d ~/code -d ~/Downloads

# bash
ags completions --shell bash > ~/.local/share/bash-completion/completions/ags

# zsh
ags completions --shell zsh > ~/.zfunc/_ags

# fish
ags completions --shell fish > ~/.config/fish/completions/ags.fish

Global run flags

  • --agent <pi|claude|codex|gemini|opencode|shell> (required for run mode)
  • --browser
  • --tmux
  • --stop-when-done (requires --tmux)
  • --psp
  • --psp-keep
  • --yolo
  • --root
  • --lockdown (harden the run by disabling host bridges, secrets, SSH agent, generic mounts/tools, direct agent-home mounts, host-loopback networking, and adding size-limited tmpfs mounts for that run)
  • --defaults / -D (prepend AGS-managed passthrough defaults for the selected harness)
  • --config <path>
  • --add-dir <path> / -d <path> (repeatable, run only; still allowed in lockdown)

Configuration guide

Default base config path:

  • ~/.config/ags/config.toml

Optional repo-local overlay path:

  • PROJECT_ROOT/.ags/config.toml

If the base config is missing, ags auto-creates a minimal default file on first run.

Precedence order:

  1. user/global config (~/.config/ags/config.toml, or --config <path> if provided)
  2. repo-local overlay (PROJECT_ROOT/.ags/config.toml) when running inside a git repo/worktree

Repo-local scalar/table fields override the base config. Repeatable sections ([[mount]], [[agent_mount]], [[tool]], [[secret]]) are additive.

Use config/config.example.toml for full schema examples.

Important sections

  • [sandbox]
    • Container image name and core paths
    • SSH key paths
    • bootstrap files
    • base env passthrough allowlist
  • [[agent_mount]]
    • Dedicated required mounts for agent home-state paths (explicit, no implicit agent mounts)
  • [[mount]]
    • Additional bind mounts from host to container
    • supports mode, kind, when, create, optional
  • [[tool]]
    • Tool binary mount
    • optional nested [[tool.directory]] mounts
    • optional nested [[tool.secret]] sources
  • [[secret]]
    • Map env var names to source(s): from_env and/or secret_store
  • [auth_proxy]
    • auto_allow_domains: list of domains to skip the allow/deny prompt for (e.g. ["mcp.linear.app"])
  • [browser]
    • Enables browser sidecar integration used with --browser
  • [update]
    • Controls Pi package spec and pnpm minimum release age for updates

Security notes

  • Use least-privilege, short-lived tokens whenever possible.
  • Only mount what the agent needs.
  • Prefer read-only (ro) mounts unless write access is required.
  • For untrusted or foreign repos, prefer --lockdown to minimize host exposure for that run.
  • In lockdown, Bash command classification fails closed if destructive_command_guard (dcg) is unavailable or errors; run ags doctor/ags update if Bash commands are unexpectedly blocked.
  • Treat passthrough_env and configured secrets as sensitive data paths.
  • npm/pnpm lifecycle scripts are disabled in the sandbox (ignore-scripts=true).
  • Rotate/revoke credentials quickly if compromise is suspected.
  • The auth proxy requires explicit user approval (via desktop dialog) before opening any URL requested by the sandbox agent. URLs are never opened silently.
  • OAuth loopback callbacks are relayed through the host proxy — the container never listens on host network ports directly.
  • This repo ships a project-local dcg policy (.dcg/packs/git-worktree-sandbox.yaml) that blocks git worktree prune in sandbox sessions because not all host worktrees are necessarily visible from inside the container.

Project layout

  • crates/ags/ — Rust CLI implementation
  • config/Containerfile — base sandbox image definition
  • config/tmux.conf — minimal tmux defaults copied into the sandbox image
  • config/config.example.toml — full config template
  • agent/extensions/guard.ts — runtime guard extension mounted for Pi
  • agent/settings.example.json — example Pi settings template
  • agent/auth-proxy-shim — container-side $BROWSER replacement for auth proxy
  • Makefile — convenience command wrappers

Troubleshooting

  • Run ags doctor first.
  • If image is missing/stale: run ags update.
  • If agent CLIs are missing/stale: run ags update-agents.
  • If browser mode fails:
    • ensure [browser].enabled = true
    • verify [browser].command is valid
    • verify debug port is available
  • If auth proxy prompts are auto-denied: install zenity or kdialog
  • If secrets are not found:
    • verify env vars exist and are non-empty
    • or verify secret-tool entries match configured attributes

Contributing

Contributions are welcome.

For the full contributor guide, see CONTRIBUTING.md.

Development setup

# build
cargo build -p ags

# format
cargo fmt

# lint
cargo clippy -p ags -- -D warnings

# test
cargo test -p ags

Suggested PR workflow

  1. Create a focused branch.
  2. Make small, clear commits.
  3. Add/update tests for behavior changes.
  4. Run fmt/clippy/tests locally.
  5. Update docs (README/config example/help text) when behavior changes.
  6. Open PR with:
    • summary of user-visible changes
    • config/migration notes (if any)
    • test coverage notes

High-value contribution areas

  • Better diagnostics in doctor
  • Config schema/documentation improvements
  • Additional agent/profile support
  • Better cross-platform behavior and install UX
  • Safer defaults and security hardening

About

Sandbox for agents with podman

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors