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.
README.md(this file): quick start + daily usagedocs/COMMANDS.md: detailed command behavior and side effectsdocs/CONFIG.md: full config schema and semanticsdocs/GLIMPSE.md: user-facing Glimpse/host UI setup and usagedocs/TROUBLESHOOTING.md: common problems and fixesdocs/ARCHITECTURE.md: internal architecture overviewCONTRIBUTING.md: contributor workflow and quality checklist
- Rootless containerized agent runs (Podman)
- Multi-agent support:
piclaudecodexgeminiopencodeshell(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
--lockdownruns 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
Required on host:
- Rust toolchain (to build/run
agsfrom source) - Podman (rootless recommended)
gitssh-keygenssh-addbash
Optional but useful:
make(for convenience targets)secret-tool(GNOME keyring/libsecret integration)- Browser executable (for
--browsermode) zenityorkdialog(for auth proxy allow/deny prompts; auto-denied if neither is available)
Tip: run
ags doctorafter setup to verify your environment.
From repository root:
# build debug binary
cargo build -p ags
# build optimized release binary
cargo build -p ags --releaseRun without installing:
cargo run -p ags -- --agent piOptional self-link into ~/.local/bin/ags:
cargo run -p ags -- install --link-selfIf an existing file/symlink should be replaced:
cargo run -p ags -- install --link-self --forceYou can also use Make targets (see below).
cargo run -p ags -- installThis writes:
~/.config/ags/Containerfile~/.config/ags/tmux.conf~/.config/ags/pi/extensions/guard.ts~/.config/ags/pi/settings.json(if missing)
Use config/config.example.toml as your template:
mkdir -p ~/.config/ags
cp config/config.example.toml ~/.config/ags/config.tomlThen 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.
cargo run -p ags -- setupsetup 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
cargo run -p ags -- update
cargo run -p ags -- update-agentscargo run -p ags -- doctor
cargo run -p ags -- --agent shell -- -lc 'br --version && bv --version && dcg --version && tmux -V && test -f ~/.tmux.conf'Equivalent convenience flow:
make setup
make doctor
make update
make update-agents
make runAvailable targets:
make setupmake doctormake updatemake update-agentsmake runmake run-browsermake installmake install-selfmake uninstallmake aliases
Run Pi agent:
ags --agent piRun inside a tmux session (opt-in):
ags --agent pi --tmuxRun with browser sidecar:
ags --agent pi --browserRun in hardened lockdown mode for untrusted repos:
ags --agent claude --lockdownLockdown 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 --yoloRun other agents:
ags --agent claude
ags --agent codex
ags --agent gemini
ags --agent opencode
ags --agent shellPass arguments through to the underlying agent CLI using --:
ags --agent pi -- --continue
ags --agent claude -- --model sonnet
ags --agent claude --defaults -- --model opusUse --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.
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-kittyterminal support viakitty-terminfo- no plugin manager dependency
If you want the agent itself to start inside tmux, pass --tmux:
ags --agent pi --tmux
ags --agent shell --tmuxThis is intentionally not the default.
If tmux is reported as missing when using --tmux, rebuild the sandbox image first:
ags updateQuick 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.tomlMCP 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 = trueTo skip the allow/deny dialog for known OAuth providers:
[auth_proxy]
auto_allow_domains = ["mcp.linear.app"]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.internalAGS_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.
If you want sandboxed agent code to open Glimpse windows on your host desktop, enable [host_ui] in your config.
Start here:
docs/GLIMPSE.mdfor setup and troubleshootingdocs/CONFIG.mdfor the[host_ui]field reference
ags setup— generate keys, ensure Pi assets in mounted host path, optional keyring secret setupags doctor— run environment + config health checksags update— rebuild container image fromContainerfileand refresh bundledbr/bv/dcgbinariesags update-agents— install/update agent CLIs in persistent volumesags install [--link-self] [--force] [--add-agent-mounts]— install assets/config layout, optional self-link, optional config mount block appendags uninstall— currently reserved/no-op cleanupags create-aliases— create managed wrappers and/or shell alias blocksags completions --shell <bash|zsh|fish>— print shell completion script
ags create-aliases --mode wrappers|aliases|both --shell fish|zsh|bash --force- default mode:
wrappers - if
--shellomitted, shell is autodetected from$SHELL
# 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--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)
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:
- user/global config (
~/.config/ags/config.toml, or--config <path>if provided) - 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.
[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_envand/orsecret_store
- Map env var names to source(s):
[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
- Enables browser sidecar integration used with
[update]- Controls Pi package spec and pnpm minimum release age for updates
- 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
--lockdownto minimize host exposure for that run. - In lockdown, Bash command classification fails closed if
destructive_command_guard(dcg) is unavailable or errors; runags doctor/ags updateif Bash commands are unexpectedly blocked. - Treat
passthrough_envand 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 blocksgit worktree prunein sandbox sessions because not all host worktrees are necessarily visible from inside the container.
crates/ags/— Rust CLI implementationconfig/Containerfile— base sandbox image definitionconfig/tmux.conf— minimal tmux defaults copied into the sandbox imageconfig/config.example.toml— full config templateagent/extensions/guard.ts— runtime guard extension mounted for Piagent/settings.example.json— example Pi settings templateagent/auth-proxy-shim— container-side$BROWSERreplacement for auth proxyMakefile— convenience command wrappers
- Run
ags doctorfirst. - 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].commandis valid - verify debug port is available
- ensure
- If auth proxy prompts are auto-denied: install
zenityorkdialog - If secrets are not found:
- verify env vars exist and are non-empty
- or verify
secret-toolentries match configured attributes
Contributions are welcome.
For the full contributor guide, see CONTRIBUTING.md.
# build
cargo build -p ags
# format
cargo fmt
# lint
cargo clippy -p ags -- -D warnings
# test
cargo test -p ags- Create a focused branch.
- Make small, clear commits.
- Add/update tests for behavior changes.
- Run fmt/clippy/tests locally.
- Update docs (README/config example/help text) when behavior changes.
- Open PR with:
- summary of user-visible changes
- config/migration notes (if any)
- test coverage notes
- Better diagnostics in
doctor - Config schema/documentation improvements
- Additional agent/profile support
- Better cross-platform behavior and install UX
- Safer defaults and security hardening
