Configuration reference
Configure mounts, secrets, browser integration, clipboard access, host UI, and update behavior.
View source MarkdownThis 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:
ags --agent pi --config /path/to/config.tomlIf 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:
- base config (
~/.config/ags/config.toml, or--config <path>if provided) - 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.
[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 exactMAJOR.MINOR.PATCHpins 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-imageand first-time image creation. After changing it for an existing image, runags update-image; normal launches do not update images. - Repo-local overlays replace the base value. This is image-wide, not a project's
packageManagersetting: use different image tags for configurations requiring different pnpm versions.
- Selects the image-owned pnpm used for development and managed-agent installation:
containerfile(path, required)- Where AGS writes a reference copy of the image recipes: the final-assembly
Containerfile, with component recipes underimage/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.
- Where AGS writes a reference copy of the image recipes: the final-assembly
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 installis the only writer and normal sandbox runs mount that store read-only. - Agent updater pnpm downloads live under
<cache_dir>/agent-downloadsand 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--configfor each distinct cache root.
- Host cache dir for ssh-agent env/socket and tool caches. AGS stores mise-managed Node installations below
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 byags tools)- Selects agent CLIs installed by
ags update-agents:pi,claude,codex,gemini, andopencode. - 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 runags update-agentsto reconcile persistent runtime volumes.
- Selects agent CLIs installed by
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/miseCOPR 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 selectingsocat, and--tmuxrequires 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 runags update-image.
- Advanced representation of the optional tools installed by automatic builds and
tool_download_lock(path, optional, managed byags 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
br0.5.2,bv0.22.0, anddcg0.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_64oraarch64, or contains an invalid checksum. - Both automatic image builds and
ags update-imageverify 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 byags tools)- Points to the generated
agent-providers.<sha256>.lock.jsoncontaining 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-agentsresolves 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_lockkey is accepted when it contains the legacy OpenCode release source. AGS combines that source with embedded providers for the other agents; the nextags toolssave replaces it withagent_provider_lock.
- Points to the generated
[[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.
[[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 whenis alwaysalways- mount is always required (
optional=false,create=false)
[[mount]]#
Extra host bind mounts.
[[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, defaultfalse)- If host path missing, create it automatically.
optional(bool, optional, defaultfalse)- If host path missing and
create=false, skip instead of failing.
- If host path missing and
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)
Recommended optional mounts for dcg#
If you want sandboxed dcg to use host-managed global config and persist its own user-level state, add mounts like:
[[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 = trueNotes:
- project-local
.dcg.tomlis picked up automatically from the workspace mount ~/.config/dcgcovers global config, allowlists, and allow-once state~/.local/share/dcgcovers 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:
# ~/.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.
[[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, defaultro)when(always|browser, optional, defaultalways)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.
[[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" }Recommended modern fields#
env(required): target env var name inside containerfrom_env(optional): source env var from host process environmentsecret_store(optional): key/value attributes forsecret-tool lookupcommand(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
0and one non-empty UTF-8 value on stdout. One trailing\nor\r\nis 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, andXDG_RUNTIME_DIR. They do not receive previously resolved secrets. - Helper stdout and stderr are never included in normal diagnostics.
ags doctorreports executable availability and lookup success or a structural failure without displaying the value or helper output. --lockdowndisables 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:
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.
[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, defaultfalse)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.
- Required when enabled. Base directory for isolated
window_class(string, default"ags-browser")- Passed to Chromium as
--class; match this class/app ID in Hyprland workspace and grouping rules. Usehyprctl clientsto verify the value reported by your browser/backend.
- Passed to Chromium as
debug_port(u16, legacy)- Accepted for compatibility but ignored on launch. Each browser receives an OS-assigned port, discovered via its
DevToolsActivePortfile. Inside each sandbox, the endpoint stays athttp://127.0.0.1:9222; socat forwards that fixed port to the session's dynamic host port.
- Accepted for compatibility but ignored on launch. Each browser receives an OS-assigned port, discovered via its
startup_timeout_ms(u64, default5000)- 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>).
- Injected for Pi runs in browser mode (
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.
[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, defaultfalse)- Starts the AGS host UI sidecar for each run.
binary(string, defaultglimpse-host-ui)- Path or command for the host UI service.
renderer(string, defaultstub)- Renderer backend name passed to the host UI service.
- Use
processfor normal interactive Glimpse windows. stubis mainly useful for testing.
renderer_bin(path, optional)- Required when the chosen renderer needs an external binary, such as
renderer = "process".
- Required when the chosen renderer needs an external binary, such as
idle_timeout_ms(u64, default0)- Idle timeout passed to the host UI service.
0disables idle shutdown so the sidecar stays alive for the AGS session.
log_level(string, defaultinfo)- 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. WithoutXDG_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.
[clipboard]
enabled = true
mode = "readwrite" # off | read | readwrite
max_bytes = 33554432
approval_required = true
approval_seconds = 300
approve_writes = falseFields#
enabled(bool, defaulttrue)- 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, defaultreadwrite)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, default33554432)- Maximum clipboard payload size for reads and writes.
approval_required(bool, defaulttrue)- Prompts on the host before sandboxed code can read clipboard contents.
- Set to
falseto restore session-wide read access while[clipboard]is enabled.
approval_seconds(u64, default300)- Adds an Allow for N seconds choice to the approval dialog.
- Set to
0to only offer one-shot approval.
approve_writes(bool, defaultfalse)- Also require approval before sandboxed
wl-copywrites to the host clipboard.
- Also require approval before sandboxed
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.
[desktop_passthrough]
wayland = falseFields#
wayland(bool, defaultfalse)- 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.
- Mounts the real Wayland compositor socket and injects
[update]#
Controls agent and catalog release update behavior.
[update]
pi_spec = "@earendil-works/pi-coding-agent"
minimum_release_age = 1440 # minutesFields#
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-agentshould be updated;ags update-agentstreats that value as the current default during migration.
minimum_release_age(u32 minutes, default1440)- 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 islatest, 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 doctorafter config changes. - Keep required mounts minimal and explicit.
- Prefer
optional=truefor 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.
Improve this page where the source lives.