Configuration
Every Empryo config field: default model, thinking, Genome graph, task router, agent features, compaction, key storage, instruction files, and env vars.
Config lives in two files. Project wins.
| Scope | Path |
|---|---|
| Global | ~/.empryo/config.json |
| Project | .empryo/config.json |
Full example
{
"defaultModel": "anthropic/claude-sonnet-4-5",
"thinking": { "mode": "adaptive" },
"genome": true,
"semanticSummaries": "ast",
"diffStyle": "default",
"chatStyle": "accent",
"toolTimeout": 2,
"compaction": {
"strategy": "v2",
"triggerThreshold": 0.7,
"keepRecent": 4
},
"taskRouter": {
"spark": "anthropic/claude-haiku-4-5",
"ember": "anthropic/claude-sonnet-4-5",
"compact": "google/gemini-2.5-flash"
},
"agentFeatures": {
"desloppify": true,
"tierRouting": true,
"dispatchCache": true,
"targetFileValidation": true
},
"retry": { "maxAttempts": 5, "baseDelayMs": 3000 }
}Fields
Model
| Field | Default | What it does |
|---|---|---|
defaultModel | "none" | Active model ID. "none" (default) forces picker on launch. |
thinking.mode | "off" | "off", "adaptive", "enabled" |
thinking.budgetTokens | - | Tokens when mode: "enabled" (1024, 2048, 5000, 10000, 20000) |
Display
| Field | Default | What it does |
|---|---|---|
diffStyle | "default" | "default", "sidebyside", "compact" |
chatStyle | "accent" | "accent", "bubble" |
vimHints | true | Show Vim keybinding hints |
nerdFont | auto | Nerd Font icons — auto-detected from installed fonts; set true/false to force (off shows ASCII) |
Intelligence
| Field | Default | What it does |
|---|---|---|
genome | true | Build the codebase graph on launch |
semanticSummaries | "synthetic" | "synthetic" (default), "ast", "llm", "off" |
toolTimeout | 2 | Tool call timeout in minutes. 0 disables. |
Compaction
See compaction for what these do.
"compaction": {
"strategy": "v2",
"triggerThreshold": 0.7,
"resetThreshold": 0.4,
"keepRecent": 4,
"maxToolResults": 30,
"llmExtraction": true
}Retry
For 429s and transient errors. Delays double each attempt.
"retry": { "maxAttempts": 5, "baseDelayMs": 3000 }Web access
| Field | Default | What it does |
|---|---|---|
webSearch | true | Allow the web_search tool at all. Off means no web search on any path. |
nativeSearch | true | Let the provider run the search server-side on lanes where we have measured it working. Requires webSearch. |
With nativeSearch on, a supported model searches in one step and returns its own citations instead of Empryo scraping on your machine — and the query goes only to your model provider rather than also to DuckDuckGo, Brave or Jina. Two trade-offs worth knowing:
- Because the provider executes the search, there is no per-query approval prompt to intercept.
Turn nativeSearch off to keep every search client-side and promptable.
- The provider's search tool adds a fixed ~2.2K input tokens to each request whether or not the
model searches. It sits in the cached prefix, so the effective cost is much lower than that.
It is on only where we have actually run it: Claude (direct and through the proxy), GPT through the proxy, and OpenRouter's native-search generations. Lanes we have implemented but never exercised against a real key stay off and use the search below instead — being wrong about a provider-executed tool costs the whole request, not just the search, so an unproven lane is not worth the gamble. /web-search names whichever backend is actually in play.
Everything else — gateways, local models, unproven lanes, no provider support — falls back to the search backends you've keyed, with free DuckDuckGo as the floor. Toggle both in Settings › Provider, or with /provider websearch and /provider nativesearch.
| Variable | Purpose |
|---|---|
EMPRYO_NATIVE_SEARCH_UNVERIFIED | Set to 1 to also use provider-side search on the unproven lanes (Gemini, Grok and Groq direct). Untested by us — if it works for you, please say so. |
Task router
Assign different models to different jobs. See the task router recipe for tuning tips.
"taskRouter": {
"spark": "anthropic/claude-haiku-4-5",
"ember": "anthropic/claude-sonnet-4-5",
"webSearch": "anthropic/claude-haiku-4-5",
"desloppify": "anthropic/claude-haiku-4-5",
"verify": "anthropic/claude-haiku-4-5",
"compact": "google/gemini-2.5-flash",
"semantic": "anthropic/claude-haiku-4-5",
"default": null
}| Slot | Runs when |
|---|---|
spark | Read-only research agents |
ember | Code-writing agents |
webSearch | Web search agent |
desloppify | Cleanup pass after code edits |
verify | Adversarial review after code edits |
compact | Context compaction |
semantic | Genome one-line summaries |
default | Fallback for background tasks |
Resolution: taskRouter[slot] → taskRouter.default → active model.
Agent features
"agentFeatures": {
"marionette": false,
"desloppify": true,
"tierRouting": true,
"dispatchCache": true,
"targetFileValidation": true
}| Feature | What it does |
|---|---|
marionette | Compile each sent prompt into a repo map (focus files, graph edges, memories) before the agent starts — model via taskRouter.marionette |
desloppify | Run cleanup agent after code agents |
tierRouting | Auto-route trivial tasks to cheap model |
dispatchCache | Share file reads across dispatches |
targetFileValidation | Require file paths on dispatch tasks |
Toggle with /agent-features (or /marionette for the prompt compiler directly).
Marionette lane
How the prompt compiler surveys the repository before it writes the map.
"marionetteMode": "fast"| Lane | How it surveys | Typical |
|---|---|---|
none | repository index only — no model call | ~0.2s, 0 tokens |
fast *(default)* | index survey, then one tool-less call judges and writes | ~20s |
assist | index survey, then a short tooled pass confirms | ~55s |
deep | no pre-retrieval — the model drives the whole survey | ~75s |
Measured on 11 real requests against a large TypeScript monorepo (haiku-4.5): fast found the right files as often as none while roughly doubling precision, and beat deep by 30 points of recall at a third of the latency. deep keeps the highest ceiling on requests whose product wording matches nothing in the code, at the cost of high run-to-run variance.
Switch with /marionette none|fast|assist|deep, in Settings → Router → Behaviors, or per run with --marionette-mode <lane>. marionetteBudget (steps / time) only applies to assist and deep — the retrieval lanes have no loop to bound.
Providers
Pick keys and add custom providers on the dedicated pages:
- All providers - env vars,
--set-keycommands, keyUrls. - Custom providers - any OpenAI-compatible API.
- Copilot - use your GitHub Copilot subscription.
Auth & key storage
Keys go to your OS keychain when available, with a file fallback otherwise.
| Platform | Backend |
|---|---|
| macOS | Login Keychain (security), service empryo |
| Linux | libsecret via secret-tool (GNOME Keyring, KWallet) |
Linux without secret-tool | ~/.empryo/secrets.json, mode 0600 |
| Windows | DPAPI (crypt32.dll) - %LOCALAPPDATA%\Empryo\secrets.dat, user-scoped |
| Windows without DPAPI | Plain JSON under same dir, mode-restricted |
| Windows (WSL) | Same as Linux above |
empryo --set-key <provider> <key> writes to whichever backend is active. Inspect with empryo --list-providers.
Lookup order
{ "keyPriority": "env" }| Value | Order |
|---|---|
"env" (default) | env var → keychain → file |
"app" | keychain → file → env var |
Use "app" when shell-exported keys keep overriding stored ones.
Pass a key per-launch
Env vars work for the TUI too - useful for one-off sessions or CI:
LLM_GATEWAY_API_KEY=sk-... empryo
ANTHROPIC_API_KEY=sk-ant-... empryoNothing is persisted. There is no --key flag - the TUI only reads stored keys and env vars.
Remove a key
/keys inside the TUI lists every provider with delete shortcuts. Or delete from the keychain directly (security delete-generic-password -a empryo -s anthropic-api-key on macOS).
Instruction files
Auto-load project rules from AI-tool markdown files:
{ "instructionFiles": ["empryo", "claude", "cursorrules"] }| Key | File | Default |
|---|---|---|
empryo | EMPRYO.md | on |
claude | CLAUDE.md | off |
cursorrules | .cursorrules | off |
github-copilot | .github/copilot-instructions.md | off |
cline | .clinerules | off |
windsurf | .windsurfrules | off |
aider | .aider.conf.yml | off |
codex | AGENTS.md | off |
amp | AMPLIFY.md | off |
Toggle in TUI with /instructions.
Privacy
Block files from the agent:
/privacy add .env
/privacy add secrets/**Built-ins already cover .env, .pem, credentials, id_rsa, .npmrc, .netrc, shadow, passwd.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
EMPRYO_NO_GENOME | unset | Skip the Genome scan at startup. |
EMPRYO_MAX_OUTPUT_TOKENS | 64000 | Per-step output cap for all agents (forge + subagents + web-search). Raise for reasoning models that hit finish_reason=length. |
EMPRYO_PRESETS | unset | Comma-separated preset specs to load on boot. Set automatically by --plugin <spec> flags. See presets. |
EMPRYO_NO_PROMPT | unset | Skip first-run addon wizard (set to 1). Useful in CI. |
EMPRYO_DEBUG_API | unset | Dump per-step API requests to ~/.empryo/api-export/. |
EMPRYO_DEV_UI | unset | Show dev-only slash commands (/ui-demo, etc). |
EMPRYO_ENABLE_GHOSTTY | unset | Force-enable the embedded floating terminal on Windows (off by default - see Windows notes). |
EMPRYO_HEARTH_SOCKET | <configDir>/hearth.sock | Override the Hearth IPC socket path. |
EMPRYO_HEARTH_APPROVAL_TIMEOUT_MS | 300000 | Approval timeout for remote tool calls. |
EMPRYO_HEARTH_DENY_READ_REMOTE | unset | Block read-only tools from remote surfaces (set to 1). |
EMPRYO_PROXY_VERSION | latest | Pin a CLIProxyAPI version when installing the proxy addon. |
EMPRYO_AUTO_INSTALL_ADDONS | unset | Comma-separated addons to install automatically (proxy,neovim). |
EMPRYO_MEMORY_LIMIT_MB | 1536 | Ceiling on Empryo's own heap. Past it, memory-hungry analysis (type-aware diagnostics) declines rather than pushing the collector into a spiral. |
EMPRYO_TREE_MEMORY_LIMIT_MB | 4096 | Ceiling on Empryo plus every process it spawned — language servers, mostly. A separate question from the heap ceiling: a big tsserver is not a reason to stop type-checking, but it is a reason to worry about the machine. |
EMPRYO_LSP_IDLE_MS | 180000 | How long a language server may sit unused before it is stopped. Restarting one costs 37–700ms depending on the server; holding four idle costs ~750MB. Lower it on a small machine, raise it if you bounce between languages. |
EMPRYO_LSP_MAX_CLIENTS | 6 | How many language servers may run at once; past this the coldest is stopped. Six keeps the worst case (~550MB each) inside the 4GB tree ceiling. |
The four values above are defaults measured on one machine. A malformed, zero or negative value falls back to the default — an empty variable never reads as "no limit".
Hooks
Covered on the hooks page. Short version: Empryo reads hooks.{Event} from all 5 config sources (Claude Code's three + Empryo's two), fires all matches.
Storage
/storage shows per-component disk usage (Genome, sessions, plans, memory, input history, binaries, fonts) with one-click cleanup.
Scope priority
Session → Project → Global. Changes via commands land in whatever scope the command targets. Use /model-scope to move the active model between project and global.