Skip to content

config.toml reference

This is the exhaustive schema for ~/.aethon/config.toml. The Configuration guide walks through the common fields with copy-paste examples; this page is the keys-and-defaults table for when you need to look up an option.

The file lives at ~/.aethon/config.toml (resolved through Tauri's cross-platform home-directory API). Every section is optional, and so is every key inside it. Unset values use the defaults documented below.

Aethon never crashes on a malformed config.toml. A few rules govern how it tolerates bad input:

  • Parse errors fall back to the full set of defaults; the error is logged, not surfaced as a crash.
  • Unknown enum values (a misspelled theme, enabled, mode, …) fall back to a safe default per field rather than erroring.
  • Out-of-range numbers clamp to the nearest valid value. This is non-fatal but not always silent: ui.font_size, for example, logs a warning when it clamps.
  • Unknown sections and keys are preserved on round-trip; Aethon only writes back the keys it manages.
  • File size: Aethon reads at most the first 64 KiB of the file. Any bytes past that are ignored, so truncating mid-file may produce a parse error that falls back to defaults.

[ui]

toml
[ui]
theme = "ember"
font_size = 14
restore_tabs = true
notify_on_completion = true
notify_min_duration_seconds = 8
thinking_visibility = "show"
tool_calls_visibility = "show"
KeyTypeDefaultNotes
themestring"ember"One of the registered theme ids. Built-ins: ember, paper, aether, brink, daylight, mist, nocturne. signature is a back-compat alias for aether. Custom theme ids registered by extensions are valid here too. Unknown ids fall back to ember.
font_sizeinteger14Terminal and editor font size in pixels. Clamped to 10-24; values outside that range are clamped (with a warning logged) to protect layout integrity.
restore_tabsbooleantrueRe-open all tabs from the previous session on launch.
notify_on_completionbooleantrueNotify when an agent turn ends and you are not watching that tab: an in-app toast if the Aethon window is focused but another tab is active, or a native OS notification if the window is unfocused. Nothing fires if the finishing tab is already active.
notify_min_duration_secondsinteger8Minimum turn length (seconds) to trigger the completion notification. Sub-second turns skip notification. Clamped to 0-3600.
thinking_visibility"show" | "collapse" | "hide""show"Global default visibility for the model's thinking blocks in the transcript. Per-tab overridable at runtime via the composer visibility pills.
tool_calls_visibility"show" | "group-turn" | "group-run" | "group-block" | "hide""show"Global default visibility and grouping for tool-call cards. The legacy value collapse migrates to group-turn. Per-tab overridable at runtime via the composer visibility pills.

[agent]

toml
[agent]
model = "anthropic/claude-sonnet-4-6"
# provider_timeout_seconds = 120     # optional; omit to keep pi's default
bash_timeout_floor_seconds = 300
subagent_timeout_seconds = 300
idle_retire_minutes = 15
KeyTypeDefaultNotes
modelstringprovider defaultThe default model for new agent tabs. Format depends on the provider: anthropic/claude-sonnet-4-6, openai/gpt-4o, etc. The /model slash command updates the active tab's model and persists the choice for new tabs.
provider_timeout_secondsintegerunsetAethon-owned override for the provider/SDK request timeout, in seconds. Omit (or set 0) to leave pi's own retry.provider.timeoutMs behavior unchanged. Clamped to 1-86400. Wired through AETHON_PROVIDER_TIMEOUT_SECONDS.
bash_timeout_floor_secondsinteger300Floor applied to model-supplied bash tool timeouts, in seconds. A missing or invalid (0) value uses the historical 5-minute default. Clamped to 1-86400. Wired through AETHON_BASH_TIMEOUT_FLOOR_SECONDS.
subagent_timeout_secondsinteger300Default inline subagent wall-clock ceiling, in seconds. Individual subagent frontmatter may override this per invocation (see Agents). A missing or invalid (0) value uses the 5-minute default. Clamped to 1-86400. Wired through AETHON_SUBAGENT_TIMEOUT_SECONDS.
idle_retire_minutesinteger15Minutes a per-tab agent worker may sit idle (no prompt in flight, no traffic) before the background sweep retires it. The worker respawns lazily from the persisted session on the next message. 0 disables retirement. Clamped to 0-1440.

TIP

provider_timeout_seconds is the one [agent] knob with no default. Leave it out unless a provider is timing out on legitimately long turns. The other three timeout/idle knobs ship with working defaults.

[shell]

toml
[shell]
default_share_mode = "private"
auto_restart_agent = true
default_command = ""
default_args = []
inherit_env = true
prompt_before_close = true
KeyTypeDefaultNotes
default_share_mode"private" | "read" | "read-write" | "read-write-trusted""private"Initial share mode for new shell tabs. Anything else falls back to "private" so a typo cannot accidentally widen exposure.
auto_restart_agentbooleantrueWhen the bun bridge child crashes unexpectedly, automatically respawn it. Set false to surface the crash notice without auto-restart (useful when debugging the bridge).
default_commandstring"" (= $SHELL)Override the program spawned for new shell tabs. Empty string or omission falls back to $SHELL (and the platform default on macOS).
default_argsstring[][]Extra argv for the spawned shell. Each element becomes a separate argv slot, appended after the platform default (e.g. -il on Unix). Use to pass profile flags or a -c <command> every new tab should run.
inherit_envbooleantrueWhether new shell tabs inherit Aethon's environment (PATH, locale, etc.). Set false for hermetic shells (the PTY still gets TERM=xterm-256color).
prompt_before_closebooleantrueWhen closing a shell whose foreground job is not the shell itself (vim, npm test, ssh), prompt before killing. Enforced frontend-side: both Cmd+W and the X close button honour it.

[shortcuts]

toml
[shortcuts]
new_tab_kind = "agent"
KeyTypeDefaultNotes
new_tab_kind"agent" | "shell""agent"What Cmd+T opens when focus is outside the bottom terminal panel. "agent" keeps the focus-aware default; "shell" makes Cmd+T always open a shell sub-tab. Anything else falls back to "agent".

[voice]

toml
[voice]
toggle_hotkey = "mod+shift+m"
# hold_hotkey = "AltRight" # macOS default; unset elsewhere.
KeyTypeDefaultNotes
toggle_hotkeystring"mod+shift+m"Global hotkey to toggle voice input on and off. mod maps to Cmd on macOS and Ctrl on Linux/Windows.
hold_hotkeystring or unset"AltRight" on macOS, unset elsewhereOptional hold-to-record physical key. Platform-dependent default (AltRight / Option on macOS only).

WARNING

All [voice] behavior requires the voice build feature. On a build without it, the voice commands return the error voice support not built into this binary and these keys are inert. See Voice-to-text input.

[extensions]

toml
[extensions]
state_warn_kb = 64
state_hard_kb = 512
KeyTypeDefaultNotes
state_warn_kbinteger64Soft warning threshold (KB) for an extension's setState payload. Above this, the bridge logs a WARN naming the extension and the path. Clamped to 1-8192. Wired through AETHON_STATE_WARN_KB.
state_hard_kbinteger512Hard rejection threshold (KB) for an extension's setState payload. Above this the write is rejected and the extension's mutation Promise resolves to { ok: false, error }. Clamped to 1-8192 and raised to at least state_warn_kb. Wired through AETHON_STATE_HARD_KB.

[updates]

toml
[updates]
channel = "stable"
disable_auto_check = false
KeyTypeDefaultNotes
channel"stable" | "nightly""stable"Which release channel the auto-updater checks. stable tracks releases/latest; nightly follows the nightly tag for in-development builds. Unknown values fall back to "stable".
disable_auto_checkbooleanfalseDisable automatic background update checks entirely. The manual "Check for Updates" menu item still works.

[devshell]

Controls Nix devshell detection for shell tabs and the agent's pi bash tool.

toml
[devshell]
enabled = "auto"
mode = "auto"
cache_ttl_hours = 720
refresh_on_lockfile_change = true
KeyTypeDefaultNotes
enabled"auto" | "always" | "never""auto"Whether to detect and apply a Nix devshell on shell and agent spawn. auto detects via marker files; always forces detection with loud errors on failure; never disables wrapping entirely. Unknown values fall back to "auto".
mode"auto" | "direnv" | "nix" | "nix-shell""auto"Pin a resolver kind. auto honours natural precedence (direnv before flake before shell.nix). Named variants force a single kind and fall back to no-wrap if the marker file or binary is missing.
cache_ttl_hoursinteger720How long a successful on-disk snapshot stays valid (hours) before the next launch ignores it. Lockfile-hash mismatches always invalidate first. 0 disables time-based eviction.
refresh_on_lockfile_changebooleantrueRe-resolve automatically when watched lockfile or marker files change mtime. Disable to require a manual "Refresh now" in Settings.

Per-project override

A project can override the global [devshell] section with <project-root>/.aethon/devshell.toml:

toml
# <project-root>/.aethon/devshell.toml
[devshell]
enabled = "never"   # never wrap this repo
mode = "nix"        # if enabled, force the flake resolver

Merge semantics:

  • Only enabled and mode are per-project-overridable. Project-level values take precedence when set; missing keys fall through to the global [devshell] defaults. The two keys can be overridden independently.
  • cache_ttl_hours and refresh_on_lockfile_change are global only; a project file cannot change them.
  • The override is loaded best-effort at command-invocation time (in effective_config(), consumed by devshell_status, devshell_env_for_path, and devshell_refresh). Malformed TOML is silently ignored, so a bad .aethon/devshell.toml never blocks a shell from opening.

TIP

[devshell] is the only section with a per-project variant. Every other section is global to ~/.aethon/config.toml.

[server]

toml
[server]
enabled = true
KeyTypeDefaultNotes
enabledbooleantrueWhether to advertise this host over mDNS (_aethon._tcp.local.) at boot. Set false to stop the LAN announcement while keeping peer discovery (the browser) running read-only. A manual server_start action always advertises regardless of this flag.

WARNING

The discovery server has no authentication and no TLS. It is explicit scaffolding for an upcoming pairing feature; do not treat the HTTP endpoints as a trusted IPC channel. enabled = false only silences the mDNS advertiser; the HTTP server and the read-only discovery browser keep running.

[guardrails]

toml
[guardrails]
# soft_prompt_anchor = "Prefer small, reviewable diffs. Run the test suite before claiming done."
hard_enforce_project_root = false
KeyTypeDefaultNotes
soft_prompt_anchorstringunsetOptional free-text "soft anchor" appended to the per-turn working context the agent injects into the model's system prompt. Use it to remind the model of project rules. Whitespace-only is treated as unset. This never enforces anything: it is advisory prompt text only. Wired through AETHON_SOFT_GUARDRAIL_PROMPT (emitted only when present).
hard_enforce_project_rootbooleanfalseHard enforcement: blocks write/edit/bash tool calls touching paths outside the active tab's project root. A deterministic backstop for a wandering model. The per-tab composer toggle can override this default per session. Wired through AETHON_HARD_ENFORCE_PROJECT_ROOT (0 or 1).

TIP

soft_prompt_anchor is advice; hard_enforce_project_root is a hard deny. Pair them: a short anchor steers the model, and the enforcement flag is the backstop if it wanders anyway.

Clamps and validation

Out-of-range numbers clamp to the nearest valid value (non-fatal, though some keys like ui.font_size log a warning when they clamp); unknown enum values fall back to safe defaults. Aethon corrects the value rather than erroring.

KeyRangeZero handling
ui.font_size10-24clamps into range
ui.notify_min_duration_seconds0-36000 allowed (notify on any turn)
agent.provider_timeout_seconds1-864000 / unset means "leave pi's default"
agent.bash_timeout_floor_seconds1-864000 falls back to default 300
agent.subagent_timeout_seconds1-864000 falls back to default 300
agent.idle_retire_minutes0-14400 disables retirement
extensions.state_warn_kb1-8192clamps into range
extensions.state_hard_kb1-8192raised to at least state_warn_kb
devshell.cache_ttl_hours0 and up0 disables time-based eviction

Enum fall-backs: theme to ember, default_share_mode to private, new_tab_kind to agent, updates.channel to stable, devshell.enabled / devshell.mode to auto.

Environment variable wiring

Some config keys are pushed into the agent bridge process as AETHON_* environment variables at spawn time (in agent_process/spawn.rs::apply_user_env()). Editing one of these keys takes effect on the next agent spawn, not the next render.

Config keyEnv varEffect
agent.provider_timeout_secondsAETHON_PROVIDER_TIMEOUT_SECONDSProvider/SDK request timeout (omitted when unset/0).
agent.bash_timeout_floor_secondsAETHON_BASH_TIMEOUT_FLOOR_SECONDSFloor for bash tool timeouts.
agent.subagent_timeout_secondsAETHON_SUBAGENT_TIMEOUT_SECONDSDefault inline subagent ceiling.
extensions.state_warn_kbAETHON_STATE_WARN_KBSoft setState payload warning threshold.
extensions.state_hard_kbAETHON_STATE_HARD_KBHard setState payload rejection threshold.
guardrails.soft_prompt_anchorAETHON_SOFT_GUARDRAIL_PROMPTAdvisory system-prompt anchor (emitted only when present).
guardrails.hard_enforce_project_rootAETHON_HARD_ENFORCE_PROJECT_ROOT1 to enforce the project-root write/edit/bash deny.

TIP

Provider credentials (ANTHROPIC_API_KEY, OPENAI_API_KEY, …) are not Aethon config. They come from the shell environment Aethon was launched with and are read by pi. See Models and providers and the Runtime API page for the full non-config AETHON_* runtime contract.

How Aethon reads and writes the file

  • Reads happen at app launch and again whenever the Settings panel is opened. Manual edits take effect on next launch (or next Settings open).
  • Writes happen when you change a value in Settings and the panel saves. Aethon uses toml_edit, so it preserves comments, key ordering, and any custom keys or unknown sections you added by hand. Only the whitelisted keys the Settings UI manages are written back.
  • Reset to defaults in Settings clears the keys Aethon manages but leaves the file intact, including your custom keys.
  • File size: Aethon reads at most the first 64 KiB and parses what it read. A file whose first 64 KiB is valid TOML still loads; truncating mid-file may cause a parse error that falls back to defaults.

Where to next

  • Configuration: task-focused tour with full copy-paste blocks.
  • Agents: models, providers, subagents, and the timeout precedence that [agent] feeds.
  • Themes: registering custom themes that [ui] theme can target.
  • Settings & search: the GUI for config.toml.