Skip to content
qqthe agent runtime
DocsConfiguration reference

Configuration reference

Every setting in config.ron: files and precedence, models, providers, policy, MCP, profiles.

QQ reads RON documents. Every file starts with ( and version: 1, and ends with ). Unknown keys are errors, so a typo cannot silently do nothing. Files are limited to 1 MiB.

(
version: 1,
model: "anthropic/claude-sonnet-5",
policy: (
allow_shell_prefixes: ["cargo test", "cargo fmt"],
),
)

qq init writes a commented starter file with the model you choose (or --model PROVIDER/MODEL); qq init --project writes .qq/config.ron in the current directory instead. Neither replaces an existing file without --force. qq config check validates the merged result; qq config show prints it with secrets redacted; qq config explain model says which file set a value; qq config sources lists every file consulted in order.

Later layers win. Maps (providers, mcp, profiles, packs) merge by key; an entry set to Remove deletes what an earlier layer declared. Sections delegation and audit replace as a whole.

OrderLayerPath
1compiled defaultsbuilt-in providers and policy
2global packs<global>/packs/<id>/pack.ron
3organization manifestcached from qq org enroll
4your global config<global>/config.ron, then <global>/config.d/*.ron sorted
5project layers, repository root first, current directory lastper directory: .qq/packs/<id>/pack.ron (each manifest trusted on its own), qq.ron, .qq/config.ron, .qq/config.d/*.ron
6explicit fileQQ_CONFIG=/path/to/file.ron
7inline documentQQ_CONFIG_CONTENT='(version: 1, …)'
8overrides--model / QQ_MODEL, --organization / QQ_ORGANIZATION, --max-output-tokens, QQ_JEV_CHECKPOINTS, QQ_JEV_ROUTING, QQ_JEV_APPROVAL, QQ_APPROVAL_DELEGATE
9managed/etc/qq/managed.ron + managed.d/ (Linux), /Library/Application Support/qq/ (macOS), %ProgramData%\qq\ (Windows); must be root-owned
10MDMmacOS forced preference dev.qq / ManagedConfig; Windows policy HKLM\Software\Policies\dev.qq\ManagedConfig (REG_SZ); none on Linux

<global> is ~/.config/qq on Linux, ~/Library/Application Support/dev.qq.qq on macOS, %APPDATA%\qq\qq\config on Windows; qq config paths prints it, along with the global config.ron, tui.ron, and the data, managed, and organization paths, each marked (exists) or (missing). The global config.ron may be a symlink to a regular file; project files may not.

Project layers that declare anything sensitive — model, providers, mcp, packs, profiles, delegation, audit, Jev settings, reasoning_effort, or any policy grant — are loaded only after qq trust has accepted that exact file content. See Permissions and trust.

Fragments in config.d/ are a good place for machine-local settings a repository should not commit; this repository’s .gitignore excludes .qq/config.d/*-local.ron.

KeyTypeDefaultMeaning
version1requireddocument schema
model"PROVIDER/MODEL"none; required to runthe route sessions start with
reviewer_model"PROVIDER/MODEL"nonemodel used for supervised approval and the final-answer audit
worker_model"PROVIDER/MODEL"nonedeprecated; use delegation.roster
organizationstringnonewhich enrolled organization manifest applies (qq org)
max_output_tokensinteger16384cap on generated tokens per model turn; a model’s own limit applies if lower. One exception: when a turn is cut at this cap with nothing visible (all hidden reasoning) or right after a complete tool call, that one retry is sent with the cap doubled, up to the model’s limit and never past a managed policy.max_output_tokens, at most once per run. Use policy.max_output_tokens for a hard ceiling; run budgets still bound spend
reasoning_effortnone minimal low medium high xhigh max defaultprovider defaulteffort hint for reasoning models that accept one. default lets the provider choose. Any other value outside the model’s known accepted set (catalog or discovery) fails at plan time naming the accepted ones; with no known set, a rejected value fails at the provider (providers)
jev_reviewoff final enforceoffoptional TypeSafe Jev checkpoints; see ../runbooks/jev.md
jev_routingboolfalseoptional Jev model routing
jev_approvalboolfalseJev decides held approvals before reviewer_model and you; see ../runbooks/jev.md
approval_delegateon offabsentwho settles held approvals: on lets the delegate decide ask holds too, off sends every hold to you; absent keeps each mode’s default (delegate under auto, you under ask). See permissions
approval_timeout_seconds1–86400absentserver-side bound on how long a held call waits for you before it is denied. Absent is no deadline: the prompt waits for you, the run’s own deadline, or cancellation. Not trust-gated: it can only shorten a wait
providersmapbuilt-insprovider declarations; below
mcpmapemptyMCP servers; MCP servers
profilesmapemptynamed per-session presets; below
packsmapdiscoveredagent packs by id; below
delegationsectionemptysub-agent roster and bounds; below
auditsectionofffinal-answer audit; below
policysectionsee belowwhat runs without asking, and what may never run; below

PROVIDER/MODEL. The provider must exist (built-in or declared) and the model must be either in QQ’s catalog for that provider or declared under the provider’s models. qq ask --model x/y hi fails fast with the available routes when the pair is unknown.

Built-in catalog routes are listed in Providers.

Built-in providers exist without any declaration; declare one only to change its credential reference or add models. Custom endpoints need a declaration.

providers: {
// Change where a built-in reads its key.
"openai": OpenAi(api_key: Env("MY_OPENAI_KEY")),
// Codex subscription under a named credential profile.
"openai-codex": OpenAiCodex(profile: "work"),
// Any OpenAI- or Anthropic-compatible gateway.
"gateway": Custom(
connection: (
base_url: "https://llm.example.com/v1",
api: OpenAiChatCompletions, // OpenAiResponses | OpenAiChatCompletions | AnthropicMessages | GoogleGenerateContent
auth: Bearer(Stored("gateway/default")), // NoAuth | ApiKey(ref) | Bearer(ref) | Header("X-Name", ref)
headers: { "X-Team": "platform" }, // static, non-secret headers
),
models: {
"big": (name: "Big model", context_window: 200000, max_output_tokens: 32000, reasoning: true),
},
),
// LiteLLM: same shape as Custom, LiteLLM-aware.
"litellm": LiteLlm(connection: (base_url: "…", api: OpenAiChatCompletions, auth: ApiKey(Env("LITELLM_API_KEY")))),
// Amazon Bedrock (Converse API) and Bedrock Mantle (OpenAI/Anthropic wire).
"bedrock": AmazonBedrock(region: "us-east-1", auth: Aws(DefaultChain)),
"bedrock-mantle": AmazonBedrockMantle(region: "us-east-1", api: AnthropicMessages, auth: Aws(Profile("dev"))),
// Drop a provider an earlier layer declared.
"unused": Remove,
}

Provider kinds: OpenAi, OpenAiCodex, Anthropic, Google, XAi, LiteLlm, AmazonBedrock, AmazonBedrockMantle, Custom.

Everywhere a credential is expected:

FormMeaning
Env("NAME")read the environment variable at run time
Stored("name")read the OS keyring entry created by qq auth login or qq auth set name
Value("literal")a literal secret; rejected unless policy.allow_literal_secrets: true — do not commit these

Stored(...) names resolve on this machine only. A repository’s committed config should reference Env(...), or leave the credential to the built-in default (qq auth login PROVIDER stores PROVIDER/default).

Per model under a provider (all optional):

KeyMeaning
namedisplay name
apioverride the wire API for this model
reasoningtrue if the model accepts reasoning_effort
reasoning_effortswhich efforts it accepts
input[Text] or [Text, Image]
context_window, max_output_tokenslimits QQ uses for compaction and budgeting
pricing(input_usd_nanos_per_token, output_usd_nanos_per_token, cache_read_…, cache_write_…, provenance: "…") so --max-cost-usd and the cost footer work

"model-id": Remove hides a catalog model.

What the agent may do without asking, and what it may never do.

Any layer (your config, a trusted project):

policy: (
// Grants: run without a prompt under `auto`.
allow_tools: ["edit_file", "write_file"],
allow_shell_prefixes: ["cargo test", "cargo fmt --all", "git status"],
allow_hosts: ["docs.rs", "*.github.com"],
shell_env: ["CARGO_HOME"], // extra env vars shell may pass through
builtin_preference: hint, // off | hint | strict
exposed_tools: ["read_file", "search", "edit_file", "shell"],
)

Administrators only, in managed.ron or MDM (anywhere else is an error):

policy: (
allowed_providers: ["anthropic", "openai"],
denied_providers: ["xai"],
max_output_tokens: 32000,
require_https: true,
allow_custom_providers: true,
allow_literal_secrets: false,
deny_tools: ["write_file"],
deny_shell_prefixes: ["git push"],
deny_hosts: ["*.internal.example.com"],
)
KeyWho may set itMeaning
allow_toolsany layer except an organization manifesttool names approved for the workspace. Grants layer: "name" adds, Remove("name") drops one a lower layer added
allow_shell_prefixesany layer except an organization manifestshell commands approved by word-boundary prefix: "cargo test" covers cargo test -p x, never cargo test | sh
allow_hostsany layer except an organization manifesthosts fetch may reach under auto; exact or *.suffix
shell_envany layer except an organization manifestvariable names passed to shell children beyond PATH HOME LANG TERM TMPDIR
builtin_preferenceany; only tightenshow hard the model is steered from shell habits to built-in tools
exposed_toolsany; intersectsthe tool catalog; empty list exposes nothing
allowed_providers / denied_providersmanaged layers onlywhich providers a model route may use; denies accumulate
max_output_tokensmanaged layers onlyceiling for the top-level key; only lowers
require_httpsmanaged layers onlyreject http:// custom endpoints (loopback exempt); default true
allow_custom_providersmanaged layers onlyallow Custom/LiteLlm declarations; default true
allow_literal_secretsmanaged layers onlyallow Value(...); default false
deny_tools, deny_shell_prefixes, deny_hostsmanaged layers onlyremove grants no matter who declared them

“Managed layers” are managed.ron, managed.d/, and MDM (rows 9 and 10 above). Setting a managed layers only key anywhere else fails with managed-only policy settings are only allowed in managed configuration; to cap output tokens for yourself, set the top-level max_output_tokens instead. An organization manifest may not plant approval grants: qq org enroll and qq org refresh reject one that sets allow_tools, allow_shell_prefixes, allow_hosts, or shell_env.

The approval prompt’s w key appends to allow_tools / allow_shell_prefixes / allow_hosts in the project’s .qq/config.ron. How grants interact with approval modes is in Permissions and trust.

A profile is a named bundle of per-session defaults, selected with /profile in the TUI or qq run --profile NAME. default is the top-level configuration and cannot be declared. Names: 1–64 lowercase letters, digits, hyphens.

profiles: {
"cheap": Profile(model: "openai/gpt-5.4-mini", reasoning_effort: low),
"careful": Profile(approval_mode: ask, max_output_tokens: 8000),
"old": Remove,
}

Keys: model, organization, max_output_tokens, approval_mode (read_only ask auto full), approval_delegate (on off), jev_review, jev_routing, jev_approval, reasoning_effort. Pack profiles (below) add prompts, skills, and tool filters.

A pack is a directory with pack.ron that bundles profiles, a persona prompt, skills, commands, and MCP declarations. Packs are discovered from <global>/packs/<id>/ and .qq/packs/<id>/, or declared explicitly. A project pack (discovered under .qq/packs/ or named by a project file) loads only once you have trusted that exact pack.ron; editing it asks again. A project file’s path must stay inside the repository (no path that leads out of it, and no symbolic link):

packs: {
"reviewer": Pack(path: "tools/qq-packs/reviewer"), // relative to this file
"legacy": Remove,
}

pack.ron:

(
schema: 1,
id: "reviewer",
version: "2026.09", // the pack's own version; any 1–64 bytes
name: "Code reviewer",
requires: (protocol: 14),
profiles: {
"reviewer": (
approval_mode: read_only,
prompt: "prompts/persona.md",
skills: ["skills"],
commands: ["commands"],
tools: (deny: ["shell", "write_file", "edit_file", "spawn_agent", "mcp__*"]),
mcp: [], // subset of this pack's mcp; absent = all
),
},
mcp: {}, // same shape as config `mcp`
)

Limits: 32 entries across packs/ directories per load (including directories without a pack.ron and stray files), 16 profiles per pack, 64 KiB manifest. A pack profile shadows nothing: a profile of the same name in your config wins.

Which models a run may spawn sub-agents on and how deep.

delegation: (
roster: [
(route: "openai/gpt-5.4-mini", role: fast, note: "lookups and summaries"),
(route: "anthropic/claude-sonnet-5", role: balanced),
(route: "anthropic/claude-opus-4-8", role: strong, note: "hard reasoning"),
],
default_role: balanced, // fast | balanced | strong
max_depth: 2, // ≤ 3
write_children: false, // may children edit files?
)

Sub-agents are read-only by default. To let the spawning agent choose write access, set delegation.write_children: true and configure reviewer_model. The spawn_agent tool then offers authority: "read" | "write"; omitting it still chooses read-only. Write children can edit files and run commands under supervised approval, with each such action reviewed before execution. Only a top-level run may spawn a write child, and only one write child runs at a time. The parent’s approval policy still gates the write spawn.

A run that may spawn sub-agents also gets wait_agents (wait for its background sub-agents) and cancel_agent (stop one). They come and go with spawn_agent: allowing, denying, or exposing spawn_agent in policy or a pack applies to all three, and the two are not tool names of their own there.

Up to 8 roster entries. Each route must resolve like model. An entry may pin the reasoning effort its children run at with effort: low (any effort value); without it, fast children run at low and balanced at medium, never above the parent’s own effort, fitted to what the route’s catalog entry advertises (a model without reasoning is sent none), while strong children inherit the parent’s. The deprecated worker_model counts as a balanced entry. Design: ../design/architecture.md and ../plans/supervised-delegation.md.

A second agent run that reviews the first’s final answer.

audit: (
mode: heuristic, // off (default) | heuristic | always
max_revisions: 1, // ≤ 2
role: strong, // roster role that performs the audit
)

heuristic audits when the run edited files, ran a non-read command, made twelve or more tool calls, or spawned a child.

Terminal preferences live in a separate document, loaded from <global>/tui.ron then .qq/tui.ron root-to-leaf.

(
version: 1,
theme: "ink", // qq | ink | ember | gruvbox | tokyonight | catppuccin | dracula | nord | solarized | onedark | rose-pine | kanagawa | everforest | monokai | <your-theme>
bindings: (
toggle_navigator: ["Ctrl-T"],
create_root_session: ["Alt-N"],
create_child_session: ["Alt-C"],
cancel_run: ["Ctrl-X"],
interrupt_run: ["Alt-S"],
),
)

An omitted binding inherits the layer below; an empty list disables the action. Collisions are rejected before the TUI starts. theme defaults to ink when the terminal advertises truecolor and to terminal otherwise. Themes are .ron files in <global>/themes/ or .qq/themes/; shape in ../design/theme.md.

VariableEffect
QQ_MODELoverride model for this process
QQ_ORGANIZATIONoverride organization
QQ_CONFIGan extra config file applied after project layers
QQ_CONFIG_CONTENTan inline RON document applied after QQ_CONFIG
QQ_JEV_CHECKPOINTSoff final enforce
QQ_JEV_ROUTINGon off
QQ_JEV_APPROVALon off; overrides jev_approval for this process
QQ_APPROVAL_DELEGATEon off; overrides approval_delegate for this process
OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY or GOOGLE_API_KEY, XAI_API_KEYbuilt-in provider credentials when nothing is stored (GEMINI_API_KEY wins over GOOGLE_API_KEY)
AWS_PROFILE, AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY, AWS_WEB_IDENTITY_TOKEN_FILE + AWS_ROLE_ARN, AWS_CONTAINER_CREDENTIALS_*Bedrock default credential chain
TYPESAFE_API_KEYJev, when not stored
COLORTERMtruecolor / 24bit selects the ink default theme
EDITOR/editor in the TUI

Not configuration keys, but files QQ discovers:

PathWhat
.qq/commands/<name>.mda slash command the composer offers as /name; the file is the prompt
.qq/skills/<name>/SKILL.mda skill the model may load; /name loads it explicitly
AGENTS.mdproject instructions the agent reads; see the FAQ
(
version: 1,
model: "anthropic/claude-sonnet-5",
reviewer_model: "openai/gpt-5.6",
max_output_tokens: 16384,
reasoning_effort: medium,
policy: (
allow_tools: ["edit_file", "write_file"],
allow_shell_prefixes: ["cargo build", "cargo test", "cargo fmt --all", "git status", "git diff"],
allow_hosts: ["docs.rs"],
),
profiles: {
"quick": Profile(model: "anthropic/claude-haiku-4-5", reasoning_effort: low),
},
delegation: (
roster: [
(route: "anthropic/claude-haiku-4-5", role: fast),
(route: "anthropic/claude-sonnet-5", role: balanced),
],
max_depth: 2,
),
)