agent/sandbox Documentation
Docs/Operate
Reference14 min readdocs/CONFIG.md

Configuration reference

Configure mounts, secrets, browser integration, clipboard access, host UI, and update behavior.

View source Markdown

This document explains the ags config schema, field by field.

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


Where config lives#

Base config path:

  • ~/.config/ags/config.toml

Optional repo-local overlay path:

  • PROJECT_ROOT/.ags/config.toml

You can override the base config at runtime:

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

If the base config path does not exist, ags creates a minimal default file on first run.

Precedence and merge behavior#

When AGS is launched inside a git repo, it resolves PROJECT_ROOT from the active repository/worktree root (git rev-parse --show-toplevel) and then loads config in this order:

  1. base config (~/.config/ags/config.toml, or --config <path> if provided)
  2. repo-local overlay (PROJECT_ROOT/.ags/config.toml) if present

Merge rules:

  • scalar fields: repo-local value overrides base value
  • table/object fields: merged recursively; repo-local keys win
  • repeatable top-level sections are additive:
    • [[mount]]
    • [[agent_mount]]
    • [[tool]]
    • [[secret]]
    • [[prepare_hook]] (global + project host executable declarations)
  • other arrays are replaced by the repo-local value

This lets a project add mounts, tools, and non-command secrets locally without copying your full personal config. For host security, repo-local overlays cannot define command secret sources, including under [[tool.secret]].


Path and env expansion behavior#

For path-like fields, including the executable element (command[0]) of command secret sources, ags supports:

  • ~ expansion (home directory)
  • environment variable expansion:
    • $VAR
    • ${VAR}

Then paths are resolved to absolute paths.

If an env var is undefined during expansion, the reference is left as-is.


Top-level sections#

  • [sandbox] (required)
  • [[agent_mount]] (optional, repeatable, recommended)
  • [[mount]] (optional, repeatable)
  • [[tool]] (optional, repeatable)
  • [[secret]] (optional, repeatable)
  • [browser] (optional)
  • [host_ui] (optional)
  • [update] (optional)

[sandbox]#

Core runtime settings.

toml
[sandbox]
image = "localhost/agent-sandbox:latest"
pnpm_version = "latest"  # or an exact stable version such as "12.9.1"
containerfile = "~/.config/ags/Containerfile"
cache_dir = "~/.cache/ags"
gitconfig_path = "~/.config/ags/gitconfig-agent"
auth_key = "~/.ssh/ags-agent-auth"
sign_key = "~/.ssh/ags-agent-signing"
bootstrap_files = ["auth.json", "models.json"]
container_boot_dirs = ["/home/dev/.ssh"]
passthrough_env = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]
enabled_agents = ["pi", "claude", "codex", "gemini", "opencode"]
extra_dnf_packages = ["git", "gh", "openssh-clients", "ripgrep"]
# Written by `ags tools` when verified downloaded tools are selected:
# tool_download_lock = "tool-downloads.<sha256>.lock.json"
# agent_provider_lock = "agent-providers.<sha256>.lock.json"

Fields#

  • image (string, required)
    • Podman image tag used for runs.
  • pnpm_version (string, optional; default "latest")
    • Selects the image-owned pnpm used for development and managed-agent installation: "latest" follows npm's latest stable release; an exact MAJOR.MINOR.PATCH pins that release.
    • Ranges, other dist-tags, prereleases, and build metadata are rejected. The requested release must exist and pass SHA-512 integrity verification; AGS never falls back to latest for a missing pin.
    • Used by both ags update-image and first-time image creation. After changing it for an existing image, run ags update-image; normal launches do not update images.
    • Repo-local overlays replace the base value. This is image-wide, not a project's packageManager setting: use different image tags for configurations requiring different pnpm versions.
  • containerfile (path, required)
    • Where AGS writes a reference copy of the image recipes: the final-assembly Containerfile, with component recipes under image/ next to it. Builds always use a private snapshot of the recipes embedded in the AGS binary, so editing these copies does not change the image.
  • cache_dir (path, required)
    • Host cache dir for ssh-agent env/socket and tool caches. AGS stores mise-managed Node installations below <cache_dir>/mise; ags node install is the only writer and normal sandbox runs mount that store read-only.
    • Agent updater pnpm downloads live under <cache_dir>/agent-downloads and are never mounted in ordinary sandboxes. Normal pnpm development store/cache data lives under <cache_dir>/workspace-caches/<worktree-identity>; only the current worktree's cache children are mounted writable. Lockdown uses ephemeral pnpm storage.
    • Orphaned workspace caches are collected only by ags prune-workspace-caches, not during launches or agent updates. The command reads the selected host config without repository overlays. Its grace period and deletion budgets are CLI options, not TOML settings. See daily systemd scheduling; use the matching --config for each distinct cache root.
  • gitconfig_path (path, required)
    • Host path for generated git signing config used in container.
  • auth_key (path, required)
    • SSH key for git auth.
  • sign_key (path, required)
    • SSH key for commit signing.
  • bootstrap_files (string array, optional)
    • Reserved bootstrap file list.
  • container_boot_dirs (string array, optional)
    • Directories created in container before launching agent.
  • passthrough_env (string array, optional)
    • Host env vars to pass into container if set and not already resolved from secrets.
  • enabled_agents (string array, optional, managed by ags tools)
    • Selects agent CLIs installed by ags update-agents: pi, claude, codex, gemini, and opencode.
    • When omitted, all current agent CLIs remain enabled for backward compatibility. Set it to [] for shell-only use; shell is always available and must not appear in this list.
    • Unknown and duplicate values are rejected. AGS writes the list in canonical order.
    • Disabled agent runtime caches and known [[agent_mount]] entries are excluded from normal runs. Authentication and settings remain on the host so re-enabling does not require signing in again.
    • Repo-local overlays replace the complete base list rather than appending to it.
    • Use the Agent CLIs panel in ags tools, then run ags update-agents to reconcile persistent runtime volumes.
  • extra_dnf_packages (string array, optional)
    • Advanced representation of the optional tools installed by automatic builds and ags update-image.
    • AGS installs its runtime, fixed Node 24 baseline, mise, common Unix utilities, and fixed development headers as a non-selectable baseline outside this list. The image enables upstream's jdxcode/mise COPR repository for mise (a third-party repository, not part of Fedora's default repositories).
    • When omitted, AGS uses the packages owned by catalog tools marked default: true.
    • Set it to [] to build the fixed baseline without optional tools. Browser mode still requires selecting socat, and --tmux requires selecting tmux.
    • Repo-local overlays replace the complete base list rather than appending to it.
    • Package names use ASCII letters, digits, +, -, ., and _, and must start with a letter or digit.
    • Use ags tools --packages <catalog.json> to edit the list interactively, then run ags update-image.
  • tool_download_lock (path, optional, managed by ags tools)
    • Points to the generated, content-addressed JSON lock for selected tools that are not available as Fedora packages.
    • When omitted, AGS uses its reviewed embedded br 0.5.2, bv 0.22.0, and dcg 0.13.0 downloads for backward compatibility. A generated lock containing [] explicitly selects no downloaded tools.
    • AGS stores this as a relative path and resolves it from the base or repo-local config layer that declared it, so repo overlays remain portable with their checkout.
    • Each locked tool includes a pinned version, archive format, exact executable member, and architecture-specific HTTPS URL and SHA-256 digest.
    • Config loading fails closed if the lock is missing, malformed, uses an unsafe path or URL, lacks x86_64 or aarch64, or contains an invalid checksum.
    • Both automatic image builds and ags update-image verify the selected artifact before installing only its declared executable. Each tool is cached as its own image component, so changing one entry downloads and extracts only that tool.
    • Do not hand-edit this file; update source metadata in the tool catalog and save through ags tools.
  • agent_provider_lock (path, optional, managed by ags tools)
    • Points to the generated agent-providers.<sha256>.lock.json containing typed provider policies for selected agent CLIs.
    • When omitted, AGS uses reviewed embedded policies for all five agents. An explicit lock must contain a compatible provider for every enabled agent.
    • The closed provider types are pnpm for Pi/Gemini, trusted built-in installers for Claude/Codex, and a validated GitHub release policy for OpenCode; arbitrary installer commands are not accepted.
    • AGS resolves the path relative to the config layer that declared it, requires a matching content-addressed filename, and validates agent/provider compatibility.
    • ags update-agents resolves GitHub releases using [update].minimum_release_age, verifies the selected artifact digest, and installs OpenCode transactionally in its dedicated persistent volume.
    • During migration, the former agent_release_source_lock key is accepted when it contains the legacy OpenCode release source. AGS combines that source with embedded providers for the other agents; the next ags tools save replaces it with agent_provider_lock.

[[agent_mount]]#

Dedicated, explicit mounts for agent home-state paths (no implicit runtime mounts).

Known agent-home mounts are active only while their agent is enabled. AGS preserves their configuration entries and host contents when an agent is disabled. Generic [[mount]] entries remain unconditional unless constrained by their own fields.

toml
[[agent_mount]]
host = "~/.pi"
container = "/home/dev/.pi"

[[agent_mount]]
host = "~/.claude"
container = "/home/dev/.claude"

[[agent_mount]]
host = "~/.claude.json"
container = "/home/dev/.claude.json"
kind = "file"

Fields#

  • host (path, required)
  • container (string, required)
  • kind ("dir" | "file", optional, default "dir")

Behavior:

  • mode is always rw
  • when is always always
  • mount is always required (optional=false, create=false)

[[mount]]#

Extra host bind mounts.

toml
[[mount]]
host = "~/.ssh/known_hosts"
container = "/home/dev/.ssh/known_hosts"
mode = "ro"
kind = "file"
when = "always"
create = false
optional = true
source = "config"

Fields#

  • host (path, required)
  • container (string, required)
  • mode ("ro" | "rw", required)
  • kind ("dir" | "file", optional, default "dir")
  • when ("always" | "browser", optional, default "always")
  • create (bool, optional, default false)
    • If host path missing, create it automatically.
  • optional (bool, optional, default false)
    • If host path missing and create=false, skip instead of failing.
  • source (string, optional, default "config")
    • Label used in diagnostics/errors.

Missing-path behavior#

If host path is missing:

  • create=true → path is created
  • else if optional=true → mount is skipped
  • else → run fails (required mount source missing)

If you want sandboxed dcg to use host-managed global config and persist its own user-level state, add mounts like:

toml
[[mount]]
host = "$HOME/.config/dcg"
container = "/home/dev/.config/dcg"
mode = "rw"
kind = "dir"
optional = true

[[mount]]
host = "$HOME/.local/share/dcg"
container = "/home/dev/.local/share/dcg"
mode = "rw"
kind = "dir"
optional = true
create = true

Notes:

  • project-local .dcg.toml is picked up automatically from the workspace mount
  • ~/.config/dcg covers global config, allowlists, and allow-once state
  • ~/.local/share/dcg covers dcg history storage
  • if you do not mount these, sandbox dcg still works with built-in defaults plus project-local config

Recommended host-side dcg starting point:

toml
# ~/.config/dcg/config.toml
[packs]
enabled = [
  "database.postgresql",
  "containers.docker",
]

This keeps dcg core protections on (implicit) and adds common AGS-adjacent packs without inventing AGS-specific policy syntax.


[[tool]]#

Declares a tool binary mount, optional directories, optional secrets.

[[tool]] remains the low-level mechanism for mounting a specific host binary into the sandbox. It is independent of ags tools, which edits sandbox image components through [sandbox].extra_dnf_packages and the generated verified-tool lock without generating [[tool]] entries.

toml
[[tool]]
name = "qwk"
path = "~/.local/bin/qwk"
container_path = "/usr/local/bin/qwk"
mode = "ro"
when = "always"
optional = true

[[tool.directory]]
host = "~/.config/qwk"
container = "/home/dev/.config/qwk"
mode = "rw"
kind = "dir"
create = true

[[tool.secret]]
env = "QWK_LINEAR_API_KEY"
from_env = "QWK_LINEAR_API_KEY"

[[tool]] fields#

  • name (string, required)
  • path (path, required)
  • container_path (string, required)
  • mode (ro|rw, optional, default ro)
  • when (always|browser, optional, default always)
  • optional (bool, optional)

[[tool.directory]]#

Same schema/behavior as [[mount]].

[[tool.secret]]#

Same schema as [[secret]], but tagged to that tool for diagnostics.


[[secret]]#

Maps target env var names to one or more sources.

toml
[[secret]]
env = "GH_TOKEN"
from_env = "GH_TOKEN"

[[secret]]
env = "GH_TOKEN"
command = [
  "$HOME/.local/bin/credential-store-adapter",
  "lookup",
  "--service",
  "github",
]

[[secret]]
env = "GH_TOKEN"
secret_store = { service = "github-cli-login-switcher", username = "general" }
  • env (required): target env var name inside container
  • from_env (optional): source env var from host process environment
  • secret_store (optional): key/value attributes for secret-tool lookup
  • command (optional): non-empty argv string array for a trusted host credential helper

A single entry can include multiple source types. For command, the first element must resolve to an absolute executable path; remaining elements are passed as literal argv entries. AGS expands ~, $VAR, and ${VAR} only in the executable. It invokes the executable directly without a shell, so arguments receive no shell parsing or interpolation.

Legacy fields (still accepted)#

  • provider = "env" | "secret-tool"
  • var (for env provider)
  • attributes (for secret-tool provider)

Resolution behavior#

  • Secrets are processed in config order.
  • For the same target env, first successful source wins.
  • Empty/unresolved sources are ignored.
  • Command lookup has a five-second timeout. AGS kills and reaps a timed-out helper, then tries the next source.
  • Helpers run from the host user's home directory rather than the repository working directory. AGS terminates the helper's process group on timeout or malformed/unbounded output.
  • Command success requires exit status 0 and one non-empty UTF-8 value on stdout. One trailing \n or \r\n is removed. Empty, multiline, NUL-containing, invalid UTF-8, missing, timed-out, and non-zero results are unresolved.
  • Command helpers receive only allowlisted host variables when present: PATH, HOME, USER, LOGNAME, DBUS_SESSION_BUS_ADDRESS, and XDG_RUNTIME_DIR. They do not receive previously resolved secrets.
  • Helper stdout and stderr are never included in normal diagnostics. ags doctor reports executable availability and lookup success or a structural failure without displaying the value or helper output.
  • --lockdown disables all configured secret resolution, including command execution.

Command source security and delivery#

command intentionally executes trusted user configuration on the host before the container starts. It is accepted only from the user/global base config (including an explicitly selected --config file). AGS rejects command sources from repo-local .ags/config.toml overlays, including nested [[tool.secret]] declarations.

The resolved value is inserted into AGS's existing secret environment map and delivered through the existing environment-file/container-environment mechanism. A sandboxed process can inspect the resulting environment variable. Command sources expand host-side credential-store support; they do not provide process-scoped delivery or keep the resolved value outside the sandbox.


1Password Secure Note sets are run-only#

1Password injection has no config.toml key. Do not add an entry, mapping, preset, or allowlist to this file. It is activated only for a single run with repeatable --op-secret-set VAULT/ITEM (or -1 VAULT/ITEM), for example:

console
ags --agent pi -1 'ExampleVault/readonly-database'

The referenced host item must be a SECURE_NOTE; its present string-valued fields are injected by their exact labels into only the final agent process tree. See the README's “1Password Secure Note environment sets” section for ordering, security limits, local-Podman requirement, and a no-value-output smoke test.

[browser]#

Controls optional browser sidecar used with --browser.

toml
[browser]
enabled = true
command = "google-chrome"
profile_dir = "~/.cache/ags/chrome-profile"
window_class = "ags-browser"
startup_timeout_ms = 5000
pi_skill_path = "/home/dev/browser-tools"
command_args = []

Fields#

  • enabled (bool, default false)
  • command (string)
    • Required when enabled.
    • Can be a PATH command (google-chrome) or executable path.
  • profile_dir (path)
    • Required when enabled. Base directory for isolated sessions/<pid>-<random> profiles.
    • Session profiles are deleted on normal exit, including their cookies and login state. Existing files in the base directory are untouched and are not copied into sessions.
  • window_class (string, default "ags-browser")
    • Passed to Chromium as --class; match this class/app ID in Hyprland workspace and grouping rules. Use hyprctl clients to verify the value reported by your browser/backend.
  • debug_port (u16, legacy)
    • Accepted for compatibility but ignored on launch. Each browser receives an OS-assigned port, discovered via its DevToolsActivePort file. Inside each sandbox, the endpoint stays at http://127.0.0.1:9222; socat forwards that fixed port to the session's dynamic host port.
  • startup_timeout_ms (u64, default 5000)
    • How long AGS waits for the browser's debug endpoint to become reachable. Increase this for slow or heavily loaded hosts.
  • pi_skill_path (string)
    • Injected for Pi runs in browser mode (--skill <path>).
  • command_args (string array)
    • Extra args passed to browser command. AGS appends its managed profile, port, and class arguments.

Each run owns its own browser and closes it on normal exit without affecting other sessions. Forced termination can leave a browser and session profile behind; there is no cross-session browser reuse.


[host_ui]#

Controls optional host-owned Glimpse windows for sandboxed code and AGS's own branded approval dialogs.

toml
[host_ui]
enabled = true
binary = "/path/to/glimpse_host_ui"
renderer = "process"
renderer_bin = "/path/to/glimpse"
idle_timeout_ms = 0
log_level = "info"

Fields#

  • enabled (bool, default false)
    • Starts the AGS host UI sidecar for each run.
  • binary (string, default glimpse-host-ui)
    • Path or command for the host UI service.
  • renderer (string, default stub)
    • Renderer backend name passed to the host UI service.
    • Use process for normal interactive Glimpse windows.
    • stub is mainly useful for testing.
  • renderer_bin (path, optional)
    • Required when the chosen renderer needs an external binary, such as renderer = "process".
  • idle_timeout_ms (u64, default 0)
    • Idle timeout passed to the host UI service.
    • 0 disables idle shutdown so the sidecar stays alive for the AGS session.
  • log_level (string, default info)
    • Logging level passed to the host UI service. Native renderer libraries such as Mesa can write diagnostics independently of this setting.

Notes:

  • AGS handles the sandbox wiring automatically once [host_ui].enabled = true.
  • Host UI service stderr, including inherited renderer stderr, goes to a private host-only log instead of the agent terminal. AGS prints the log's exact path at startup.
  • Logs are stored in host-ui-logs/ under the AGS runtime base (normally $XDG_RUNTIME_DIR/ags), outside the socket directory mounted into the sandbox. The directory is owner-only (0700) and each log is owner-only (0600). Logs survive session cleanup; runtime storage is normally cleared at logout or reboot. Without XDG_RUNTIME_DIR, the cache fallback retains them until manually removed.
  • Auth-proxy and clipboard approval prompts use the same host UI sidecar for branded, dark/light-aware dialogs; if disabled, they fall back to zenity/kdialog.
  • Users normally should not set Glimpse transport env vars manually.
  • For end-user setup and troubleshooting, see docs/GLIMPSE.md.

[clipboard]#

Controls the narrow AGS clipboard bridge. The bridge lets sandboxed wl-paste/wl-copy calls talk to a session-scoped host service instead of mounting the real Wayland compositor socket.

toml
[clipboard]
enabled = true
mode = "readwrite"  # off | read | readwrite
max_bytes = 33554432
approval_required = true
approval_seconds = 300
approve_writes = false

Fields#

  • enabled (bool, default true)
    • Starts the AGS clipboard sidecar for normal runs.
    • AGS-launched interactive Pi also loads a session-scoped paste handler: a single paste waits up to five minutes for host approval and completes once, without automatically sending a message. This wait is separate from the access window configured by approval_seconds.
    • Lockdown mode disables it regardless of config.
  • mode (string, default readwrite)
    • off: no clipboard bridge.
    • read: host → sandbox reads only, enough for Pi Ctrl-V image paste.
    • readwrite: also allows sandbox → host writes for copy flows.
  • max_bytes (usize, default 33554432)
    • Maximum clipboard payload size for reads and writes.
  • approval_required (bool, default true)
    • Prompts on the host before sandboxed code can read clipboard contents.
    • Set to false to restore session-wide read access while [clipboard] is enabled.
  • approval_seconds (u64, default 300)
    • Adds an Allow for N seconds choice to the approval dialog.
    • Set to 0 to only offer one-shot approval.
  • approve_writes (bool, default false)
    • Also require approval before sandboxed wl-copy writes to the host clipboard.

Security note: this is narrower than compositor passthrough. Clipboard reads are host-approved by default, but MIME type listing remains available so Pi can decide whether Ctrl-V image paste is possible.


[desktop_passthrough]#

Controls broad desktop/session primitive passthroughs. These should stay disabled unless explicitly needed for debugging GUI clients inside the sandbox.

toml
[desktop_passthrough]
wayland = false

Fields#

  • wayland (bool, default false)
    • Mounts the real Wayland compositor socket and injects WAYLAND_DISPLAY/XDG_RUNTIME_DIR.
    • This lets arbitrary Wayland-capable sandbox processes open host windows.
    • Can also be enabled per run with --wayland-compositor-passthrough.

[update]#

Controls agent and catalog release update behavior.

toml
[update]
pi_spec = "@earendil-works/pi-coding-agent"
minimum_release_age = 1440 # minutes

Fields#

  • pi_spec (string, default @earendil-works/pi-coding-agent)
    • Unversioned npm package name used for Pi install/update.
    • Older configs with the exact legacy value @mariozechner/pi-coding-agent should be updated; ags update-agents treats that value as the current default during migration.
  • minimum_release_age (u32 minutes, default 1440)
    • Minimum maturity period for release selection, measured from its published time.
    • Written to pnpm's ~/.config/pnpm/config.yaml (minimumReleaseAge) for Pi and Gemini packages. It also filters non-draft, non-prerelease catalog GitHub sources whose release mode is latest, including OpenCode and image tools. Exact-version sources inspect only their requested tag and do not apply the age filter or fall forward.

Validation tips#

  • Run ags doctor after config changes.
  • Keep required mounts minimal and explicit.
  • Prefer optional=true for machine-specific paths.
  • Prefer mode="ro" unless writes are necessary.
  • Keep browser section disabled unless you actively use it.

[[prepare_hook]]#

Optional host startup preparation. Global and project lists accumulate; contributions merge as defaults < global hooks < project hooks < explicit known-key CLI options. Entry-point content/declaration/argv approval is separate from repository-overlay trust. A discovered untrusted project overlay declaring hooks fails instead of silently dropping those declarations. Native executables and directly executable scripts support arguments.

See Startup hooks for the versioned JSON protocol, schemas, examples, reserved targets/keys, concurrency/deadlines, 1Password batching, trust limitations and resource ownership. Hook paths are literal absolute paths or relative to their declaring config file; unlike general mount/secret config paths they do not expand ~ or environment variables. --lockdown still executes approved host hooks, but rejects surviving hook secret references and host bind mounts; it permits protected literal env/generated files.