Appendix B · Configuration Keys Index
Every knob Agentao reads — environment variables first, then on-disk JSON. All of them are optional unless marked required.
B.1 Environment variables
LLM credentials
LLM_PROVIDER selects a provider prefix (default OPENAI). The remaining three keys are read as {PROVIDER}_API_KEY, {PROVIDER}_BASE_URL, {PROVIDER}_MODEL.
| Key | Required | Default | Notes |
|---|---|---|---|
LLM_PROVIDER | — | OPENAI | Picks the {PROVIDER}_* prefix. Any upper-case name works (e.g. DEEPSEEK, ANTHROPIC, GEMINI) |
{PROVIDER}_API_KEY | yes | — | Constructor api_key= overrides |
{PROVIDER}_BASE_URL | yes | — | Constructor base_url= overrides. An OpenAI-compatible endpoint by default; the API root (https://api.anthropic.com) when {PROVIDER}_API_FORMAT=anthropic-messages |
{PROVIDER}_MODEL | yes | — | Constructor model= overrides. Runtime-swappable via agent.set_model() |
{PROVIDER}_API_FORMAT | — | openai-completions | The wire protocol spoken to that block's endpoint (0.5.0): openai-completions, anthropic-messages (Anthropic's Messages API) or openai-responses (OpenAI's Responses API, 0.5.3). Never inferred from the URL, the provider name or the model name; an unknown value raises at startup. /provider reads the target block's value, so a switch between blocks on different protocols changes the wire too; sub-agents are built on the parent's current one. On anthropic-messages, LLM_TEMPERATURE is not sent and extended thinking is turned on through LLM_EXTRA_BODY. Equivalent to the constructor api_format=. Full notes: docs/reference/configuration.md §2 |
Fail-fast rule:
LLMClient.__init__raisesValueErrorat startup if any of{PROVIDER}_API_KEY,{PROVIDER}_BASE_URL, or{PROVIDER}_MODELis absent and was not supplied via the constructor. The/providerlisting and switching commands apply the same gate — all three must be set for a provider to appear in the list or be switchable.
Global runtime
| Key | Default | Meaning |
|---|---|---|
LLM_TEMPERATURE | unset | Sampling temperature (0.0–2.0). Unset = not sent; the provider's default applies (0.5.7; was 0.2). Malformed value raises at startup |
LLM_MAX_TOKENS | unset | Hard cap on LLM completion tokens per call. Malformed value raises at startup |
LLM_EXTRA_BODY | unset | JSON object forwarded verbatim to the LLM .create() as the SDK's extra_body — the escape hatch for reasoning_effort / top_p / seed / response_format / provider-specific fields. Equivalent to the constructor extra_body=. Example: LLM_EXTRA_BODY='{"reasoning_effort":"high"}'. Unlike the two above, a malformed or valid-but-non-object value is warned and skipped (not fatal); empty/whitespace is treated as unset (silent). Logged with credential keys redacted |
LLM_PROMPT_CACHE | off | Explicit prompt-cache breakpoints (0.4.26): anthropic, or off / empty / unset. When on, each agent-turn request carries at most 3 Anthropic-style cache_control markers — system message, last tool definition, end of stable history. Opt-in, never inferred from a base URL or model name: set it only for an endpoint you have verified forwards the key. An unknown value raises at startup. Equivalent to the constructor prompt_cache=. What to verify on the endpoint first: docs/reference/configuration.md §2 |
LLM_PROMPT_CACHE_TTL | 5m | Retention hint for those markers: 5m or 1h. Unread — validation included — while LLM_PROMPT_CACHE is off. Equivalent to the constructor prompt_cache_ttl= |
AGENTAO_CONTEXT_TOKENS | 200000 | Context budget; triggers compression when exceeded |
AGENTAO_WORKING_DIRECTORY | — | Override working directory at startup (alternative to constructor working_directory=) |
AGENTAO_SCRUB_CHILD_ENV | on | Whether shell and MCP child processes inherit agentao's own provider credentials. Default drops HARNESS_ENV_KEYS (OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, LLM_EXTRA_BODY, …), {LLM_PROVIDER}_API_KEY, and any variable whose value is a key agentao has used this process (after /provider, set_provider(), or an api_key= read from your own variable; values under 16 characters are not matched) from the child env. Set to 0/false/no/off to restore full inheritance — needed to run agentao run, or any provider-calling script, from inside the agent's own shell. Only agentao's keys are dropped; AWS_*, GITHUB_TOKEN, DATABASE_URL are untouched. See capabilities/process.py::build_child_env |
Third-party keys consumed by built-in tools
| Key | Consumed by | Purpose |
|---|---|---|
GITHUB_TOKEN | Skill catalog fetcher | Higher-rate GitHub API access |
BOCHA_API_KEY | web_search tool | Use Bocha Search API instead of DuckDuckGo. If absent, the tool falls back to DuckDuckGo automatically. |
MCP servers and custom tools typically read their own env keys — those are defined in your .agentao/mcp.json or your custom-tool code, not here.
B.2 Precedence order
For every setting: constructor argument > environment variable > on-disk JSON > hard-coded default.
On-disk JSON layering varies by surface:
sandbox.json— user-scope only. A<cwd>/.agentao/sandbox.jsonis ignored with a warning (a checked-in or agent-written{"enabled": false}would switch the sandbox off).mcp.json— both files are loaded; user wins on name collision and the project entry is add-only (it may declare new server names but cannot override a user-scope name; collisions warn and skip).permissions.json— user-scope only. A<cwd>/.agentao/permissions.jsonis intentionally not loaded (a checked-in{"tool": "*", "action": "allow"}would defeat the user policy on first match). Mode preset rules run last (or first infull-access/plan, where they cannot be overridden).memory.db— project and user stores are read independently; both are visible to the prompt renderer. Project does not override user.acp.json,settings.json,skills_config.json,AGENTAO.md— project-only; no merge.
B.3 On-disk JSON files
JSON config files live in an .agentao/ directory (project at <working_directory>/.agentao/, user at ~/.agentao/); the project-level AGENTAO.md lives at the project root. Per-surface precedence is described in B.2. Any file may be absent.
| File | Scope | Section | Purpose |
|---|---|---|---|
mcp.json | project (add-only) + user | 5.3 | MCP servers (stdio / Streamable HTTP / SSE) |
permissions.json | user only (project file is ignored) | 5.4 | Per-tool permission rules |
sandbox.json | user only (project file is ignored) | 6.2 | Shell sandbox profile selection |
acp.json | project only | 3.2 | ACP subagent registry (when Agentao runs as client) |
settings.json | project only | 6.6 | Persisted permission mode, builtin-agents flag, replay block |
skills_config.json | project only | 5.2 | Disabled-skills list (managed via /skills disable) |
AGENTAO.md (else AGENTS.md) | project only | 5.6 | Project-specific instructions, prepended to system prompt; AGENTS.md is read only when AGENTAO.md is absent |
memory.db | project + user | 5.5 | SQLite-backed persistent memory (not JSON; listed for completeness) |
B.3.1 mcp.json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
"env": { "LOG_LEVEL": "info" },
"trust": false,
"timeout": 30
},
"remote": {
"type": "sse",
"url": "https://api.example.com/sse",
"headers": { "Authorization": "Bearer $API_TOKEN" },
"timeout": 60
}
}
}Field reference:
| Field | Type | Notes |
|---|---|---|
type | string | Transport selector: "stdio" / "http" / "sse" (aliases "streamable-http" / "streamable_http" fold to "http"). Omitted → inferred: command = stdio, bare url = Streamable HTTP |
command | string | stdio server — mutually exclusive with url |
args | string[] | stdio args |
env | object | expanded ($VAR / ${VAR}) |
cwd | string | stdio subprocess cwd |
url | string | URL-transport server URL (Streamable HTTP or SSE) |
headers | object | URL-transport request headers ($VAR expanded) |
trust | bool | Skip confirmation prompt for tools from this server. When true, the server's ToolAnnotations (readOnlyHint, destructiveHint) are also consulted; destructiveHint=true re-introduces confirmation for that op. Hints are ignored entirely when trust is false. |
timeout | number (s) or {startup, request} | A number bounds connecting and the handshake (default 60). request bounds each tool call (no default) |
All three MCP transports are supported: stdio, Streamable HTTP, and SSE. A bare url defaults to Streamable HTTP; set "type": "sse" for a legacy SSE endpoint.
B.3.2 permissions.json
{
"rules": [
{ "tool": "run_shell_command", "args": { "command": "^git " }, "action": "allow" },
{ "tool": "run_shell_command", "args": { "command": "rm\\s+-rf" }, "action": "deny" },
{ "tool": "write_file", "action": "ask" },
{
"tool": "web_fetch",
"domain": { "allowlist": [".github.com"], "url_arg": "url" },
"action": "allow"
}
],
"shell": { "dialect": "powershell" }
}Two top-level keys, rules and shell. Anything else is a named error rather than an ignored key.
Rule fields:
| Field | Type | Required | Notes |
|---|---|---|---|
tool | string | yes | Tool name; matched as a regex via re.fullmatch (use "*" for wildcard) |
args | object | no | Map of <arg_name> → regex; all entries must re.search-match for the rule to fire |
domain | object | no | URL-tools only (web_fetch); keys url_arg (default "url"), allowlist, blocklist. Patterns starting with . do suffix matching (e.g. .github.com matches api.github.com); otherwise exact match |
action | string | yes | "allow" | "deny" | "ask" (case-insensitive) |
Shell block (new in 0.4.22, user scope, Windows only):
| Key | Type | Required | Notes |
|---|---|---|---|
dialect | string | no | "posix" | "cmd" | "powershell" — the syntax the interpreter reads. This is what the command floor scans with and what the prompt's shell guidance speaks. On its own it is enough: {"dialect": "powershell"} is the ordinary way to turn PowerShell on |
path | string | no | absolute path to a specific interpreter. Requires dialect — path alone is an error, because nothing can infer the syntax from a filename |
{"dialect": "powershell"} discovers pwsh.exe, else powershell.exe, and is an error if neither is installed — never a silent fall back to cmd. Nothing configured leaves Windows on %COMSPEC% /c exactly as before. On macOS and Linux, asking for powershell or cmd is an unsupported-platform error. Full behaviour, including the launch and the encoding: docs/reference/configuration.md §4.
The mode field is not stored in permissions.json — it lives in settings.json (B.3.5) and is changed at runtime via /permissions. Modes: read-only, workspace-write, full-access, plan (lowercase-hyphen; plan is internal).
Evaluation order:
read-only/workspace-write:[user rules] → [active mode preset]— first match wins. Inread-onlythis applies only to tools whoseis_read_onlyisTrue; any other tool is denied before a rule is consulted.full-access/plan:[active mode preset] → [user rules]— presets cannot be overridden.- No match → falls back to the tool's own
requires_confirmationattribute.
Project-scope <cwd>/.agentao/permissions.json is not loaded — see B.2.
B.3.3 sandbox.json
~/.agentao/sandbox.json:
{
"enabled": true,
"platform": "darwin",
"default_profile": "workspace-write",
"rules": [],
"profiles_dir": "~/.agentao/sandbox-profiles",
"workspace_root": null
}Built-in profiles: readonly, workspace-write-no-network, workspace-write. Fail-closed: a missing profile file raises SandboxMisconfiguredError; the shell tool refuses to run.
B.3.4 acp.json
Only consumed when Agentao itself is an ACP client: the CLI's /acp command (CLI · /acp) or a host's ACPManager (3.4). Project-level only (<project>/.agentao/acp.json). Servers sit under a top-level servers object, not mcpServers. Safe to omit for most integrations.
Per-server keys under servers.{name}:
| Key | Type | Default | Notes |
|---|---|---|---|
command | string | — | Required |
args | list[str] | — | Required |
env | dict | — | Required; $VAR / ${VAR} expanded |
cwd | string | — | Required; relative paths resolve against project root |
autoStart | bool | true | Read by ACPManager.start_all(). The CLI never auto-starts. Registry entries are written with false |
startupTimeoutMs | int | 10000 | Wait for the initialize answer. Never less than 30 s in effect. Registry entries are written with 120000 |
requestTimeoutMs | int | 60000 | Per-request timeout. Also bounds one CLI /acp send turn |
maxRecoverableRestarts | int | 3 | Cap for auto-restarts after recoverable subprocess deaths; reset on first successful turn |
capabilities | dict | {} | |
description | string | "" | |
nonInteractivePolicy | {"mode": "reject_all" | "accept_all"} | {"mode": "reject_all"} | Structured object (Week 3). Legacy bare-string form is rejected at config load time — see Appendix E. |
B.3.5 settings.json
Project-local runtime settings. Read from <working_directory>/.agentao/settings.json. Carries persisted permission mode, the built-in-agents opt-in, the background-wake switch, and the replay block.
{
"mode": "workspace-write",
"agents": {
"enable_builtin": false
},
"background_agents": {
"auto_wake": true
},
"replay": {
"enabled": false,
"max_instances": 20,
"capture_flags": {
"capture_llm_delta": true,
"capture_full_llm_io": false,
"capture_tool_result_full": false,
"capture_plugin_hook_output_full": false
}
}
}Top-level keys:
| Key | Type | Default | Notes |
|---|---|---|---|
mode | string | "workspace-write" (when key absent) | Last-known permission mode used for restoration paths and /permissions inspection. Allowed: "read-only", "workspace-write", "full-access". ("plan" is internal — set by the /plan flow, never written by users.) |
agents.enable_builtin | bool | false | Enables the built-in sub-agent set. Legacy top-level alias enable_builtin_agents (bool) is still honored. |
background_agents.auto_wake | bool | true (when key absent) | Interactive CLI only. When a background sub-agent's update is queued while the CLI waits at an empty prompt, run one turn automatically so the update is read without typing continue. Not while you are typing, with images staged, or in plan mode; pauses after 3 wakes in a row until you submit a line. false turns it off; any other value is reported and read as true. |
Replay keys:
| Key | Type | Default | Notes |
|---|---|---|---|
replay.enabled | bool | false | Enables recording for future sessions. /replay on and /replay off write this value. |
replay.max_instances | int | 20 | Retention cap under .agentao/replays/; does not affect .agentao/sessions/. true / false, a non-number or a value below 1 is ignored (20 is used, and agentao doctor reports an error); a numeric string or a fraction is converted, with a doctor warning. |
replay.capture_flags.capture_llm_delta | bool | true | Records messages newly added by each LLM call. |
replay.capture_flags.capture_full_llm_io | bool | false | Deep capture of full LLM inputs/outputs; treat as sensitive. |
replay.capture_flags.capture_tool_result_full | bool | false | Deep capture of full tool results beyond the normal replay truncation policy. |
replay.capture_flags.capture_plugin_hook_output_full | bool | false | Deep capture of plugin hook output. |
Malformed settings.json falls back to safe defaults instead of blocking startup.
B.4 Constructor parameters that shadow these
Every env var and JSON key above has a Python equivalent on Agentao(...):
| JSON / env | Constructor |
|---|---|
{PROVIDER}_API_KEY | api_key= |
{PROVIDER}_BASE_URL | base_url= |
{PROVIDER}_MODEL | model= |
{PROVIDER}_API_FORMAT | api_format= |
AGENTAO_WORKING_DIRECTORY | working_directory= |
AGENTAO_CONTEXT_TOKENS | max_context_tokens= |
mcp.json | extra_mcp_servers= (merged on top of file) |
permissions.json | permission_engine= |
sandbox.json | no direct arg — policy is read at tool-call time |
settings.json replay block | no direct arg — use /replay on/off or edit the file |
Constructor always wins. Useful for SaaS hosts that inject per-tenant settings without touching env.