<!-- Markdown mirror. Canonical: https://empryo.com/docs/reference/configuration -->

# Configuration

> Every Empryo setting: default model, thinking, the Genome code index, task router, agent features, key storage, instruction files, and environment variables.

Empryo reads settings from two JSON files. Settings in the project file override the global file.

| Scope | Path |
|-------|------|
| Global | `~/.empryo/config.json` |
| Project | `.empryo/config.json` in your project |

You rarely need to edit these files by hand. Most settings have a slash command, a panel under `/settings`, or a switch in the desktop app's Settings. In the terminal app, `/settings` → **All settings** lists every setting the terminal reads, with its value and where that value comes from: the project, your global config or the default. Type to search, then press Enter to change it for this project or globally, or to clear it.

If a file has a key Empryo does not know, the app tells you right away: which key, which file, and the nearest real setting when the key looks like a typo. That covers the fields inside each settings block too, so `"compaction": { "keepRecnt": 4 }` is reported with `keepRecent` as the fix. A dotted key such as `"compaction.gapFill": "off"` is reported too, because a dot does not nest settings: write `"compaction": { "gapFill": "off" }`. Unknown keys are ignored and left in the file. Keys an older version of Empryo wrote and no longer uses, such as `fff` or `presentation`, are dropped without a notice.

## Ask Empryo to change a setting

You can also ask in the chat: "use adaptive thinking", "make the diffs compact", or "turn provider search off in this project". The agent uses its `settings` tool to make the change.

The change takes effect in the running app, just as if you had used the Settings panel. The desktop app and the terminal app redraw right away. In a headless run the change is saved for the next run.

A few settings are only read at startup: instruction files, live translations, live skills, the Neovim binary and config, language-server auto-install, and telemetry. For those, the agent tells you to restart (`/restart` in the terminal, or quit and reopen the desktop app). Appearance settings for the desktop app can only be changed from a running desktop window.

| You ask to | The agent shows you |
|---|---|
| See a setting | Its type, its current value, and which file it came from |
| Change a setting | The old and new value, and which file it wrote |
| Reset a setting | What now applies instead |

Say "globally" to write `~/.empryo/config.json`, or "for this project" to write `.empryo/config.json`. If you do not say, Empryo writes to the project file only when that file already sets the key. Otherwise it writes to the global file. It also removes any copy in the other file that would override your change.

The `settings` tool never handles credentials. Use `/login`, `/keys`, or `empryo --set-key` for those.

## Example

```json
{
  "defaultModel": "anthropic/claude-sonnet-4-5",
  "thinking": { "mode": "adaptive" },
  "genome": true,
  "semanticSummaries": "ast",
  "diffStyle": "default",
  "chatLayout": "speakers",
  "scrollSpeed": 1,
  "toolTimeout": 2,
  "compaction": {
    "strategy": "auto",
    "triggerThreshold": 0.95,
    "keepRecent": 4
  },
  "taskRouter": {
    "spark":   "anthropic/claude-haiku-4-5",
    "ember":   "anthropic/claude-sonnet-4-5",
    "compact": "google/gemini-2.5-flash"
  },
  "agentFeatures": {
    "desloppify": true
  },
  "retry": { "maxTransientRetries": 5, "baseDelayMs": 3000 }
}
```

## Fields

### Model

| Field | Default | What it does |
|-------|---------|--------------|
| `defaultModel` | `"none"` | The model to use, as `provider/model`. With `"none"`, Empryo asks you to pick one at launch. When [`taskRouter.default`](/docs/recipes/task-router) is set, saving `defaultModel` moves it to the same model. |
| `thinking.mode` | `"auto"` | Extended thinking: `"auto"`, `"adaptive"`, `"enabled"`, `"off"`. `"auto"` uses adaptive thinking on Claude models that support it. |
| `thinking.budgetTokens` | | Token budget when the mode is `"enabled"`. Minimum 1024. |

### Display

| Field | Default | What it does |
|-------|---------|--------------|
| `theme` | | Theme name and transparency. `/theme` sets it. See [themes](/docs/tools/themes). |
| `locale` | system | Interface language, such as `ja`, `zh-Hans`, or `ar`. `/language` sets it. `--locale` overrides it for one run. |
| `localizedCommands` | `false` | Also accept slash commands typed in the interface language, such as `/لغة` for `/language`. |
| `diffStyle` | `"default"` | `"default"`, `"sidebyside"`, `"compact"`, or `"off"` (desktop only: hides diffs in the chat). |
| `collapseDiffs` | `false` | Collapse diffs when a reply finishes. `Ctrl+O` expands them. |
| `chatLayout` | `"speakers"` | Terminal app only. How messages are framed: `"speakers"`, `"rail"`, or `"bubbles"`. |
| `scrollSpeed` | `1` | Terminal app only. Multiplies how far the chat moves per mouse-wheel notch and per `Alt+J` / `Alt+K` press, from `0.5` to `5`. |

| `showReasoning` | `true` | Show the model's reasoning. |
| `showNarration` | | Show the model's short notes between tool calls. `/narration` sets it. |
| `motion` | `true` | Animations. Turn off if you prefer no motion or work over a slow SSH connection. |
| `gitDecorations` | `true` | Git status colors and letters in the file tree. |
| `vimHints` | `true` | Show Vim key hints in the editor panel. |
| `nerdFont` | auto | Use Nerd Font icons. Detected from your installed fonts. Set `true` or `false` to force it. |
| `editorSplit` | `60` | Width of the editor panel, as a percentage. |
| `tabNaming` | `true` | Name each tab from its first prompt. |
| `notifyTurns` | | Notify you when a reply finishes while you are looking elsewhere. |

### Behavior

| Field | Default | What it does |
|-------|---------|--------------|
| `defaultForgeMode` | `"default"` | The mode new sessions start in. |
| `yolo` | | Skip every approval prompt. Your `/privacy` rules still apply. `/yolo` sets it. |
| `approvals.fetchPage` | `"ask"` | `"allow"` lets `fetch_page` read pages (GET) without asking. Requests that send data still ask. |
| `approvals.fetchDomains` | | Hosts `fetch_page` may read without asking, for example `["docs.python.org", "github.com"]`. A host also covers its subdomains. A redirect to another host is not followed: the agent has to fetch the new address, and that fetch is checked again. |
| `approvals.outsideCwd` | `"ask"` | `"allow"` stops the prompt for edits and commands that touch files outside the project. Read from the global file only. |
| `approvals.destructive` | `"ask"` | `"allow"` stops the prompt for destructive commands. Read from the global file only. |
| `coAuthorCommits` | `false` | Add an Empryo co-author line to commits the agent makes. |
| `toolTimeout` | `2` | Time limit for shell, project, and agent tools, in minutes. |
| `sessionCheckpoints` | `true` | Save progress during each turn so a crash does not lose it. Turn off to save disk space. |

An approval prompt also offers to allow that kind of request for the rest of the session: page fetches, or work outside the project. That choice lasts until the tab closes and covers nothing else. A project file can set `approvals` only after you trust the repo with `/trust`.

### Code intelligence

| Field | Default | What it does |
|-------|---------|--------------|
| `genome` | `true` | Build the Genome, Empryo's index of your code's files, symbols, and how they connect, when you open a project. |
| `semanticSummaries` | `"synthetic"` | One-line summaries of your symbols. `"off"`, `"ast"` (from doc comments), `"synthetic"` (doc comments plus names, no cost), `"llm"` (written by a model), `"full"` (all of these). |
| `semanticSummaryLimit` | `300` | How many symbols get model-written summaries. The most connected symbols go first. Controls the cost of `"llm"` and `"full"`. |
| `semanticAutoRegen` | `false` | Rewrite model summaries when files change. The other modes always update. |
| `genomeTokenBudget` | auto | How much of the context the Genome may use. Grows as the conversation gets longer. |
| `genomeMaxFiles` | `10000` | Most files the Genome indexes. In a bigger repo the most recently changed files go first. `0` removes the cap. Changing it rescans. To leave files out on purpose, list them in `.empryoignore`. |
| `genomeChurnWeight` | `60` | How much the Genome favors files that change often, compared with files the rest of the code depends on. `0` ignores change history. |
| `cochangeHints` | `true` | When you check `git status`, list files that usually change together with yours but are missing. Uses local git history only. |
| `codeIntelligence` | | Which code-analysis methods to use. See [intelligence](/docs/concepts/intelligence). |
| `disabledLspServers` | `[]` | Language servers to skip, by package name. |
| `lspAutoInstall` | `true` | Install language servers for the languages in your project, in the background. |
| `nvimPath` / `nvimConfig` | auto | The Neovim binary and config for the built-in editor. See [the editor](/docs/tools/editor). |
| `editorIntegration` | | Whether the agent may use the built-in editor (`agentAccess`) and which of its actions: diagnostics, symbols, hover, references, definition, code actions, rename, format, LSP status and the cursor context. |

### Compaction

When a conversation gets long, Empryo summarizes older parts to make room. See [compaction](/docs/context/compaction).

```json
"compaction": {
  "strategy": "auto",
  "triggerThreshold": 0.95,
  "resetThreshold": 0.4,
  "keepRecent": 4,
  "maxToolResults": 30,
  "llmExtraction": true
}
```

Related fields:

| Field | Default | What it does |
|-------|---------|--------------|
| `compaction.resetThreshold` | `0.4` | How full the context should be after a compaction. Automatic compaction arms again once the context is below it. |
| `contextManagement` | | More options for what is kept in context. See [compaction](/docs/context/compaction). |
| `contextWindowOverrides` | `{}` | The real context size of a model, in tokens. Use it when a provider reports the wrong size. |
| `maxRequestChars` | `{}` | Largest request a model accepts, in characters. For gateways that reject large requests. |

### Retries

For rate limits and temporary errors. The wait doubles after each attempt. See [model fallback](/docs/recipes/model-fallback).

```json
"retry": { "maxTransientRetries": 3, "maxStallRetries": 3, "baseDelayMs": 2000 }
```

| Field | Default | What it does |
|-------|---------|--------------|
| `retry.maxTransientRetries` | `3` | Retries for rate limits, overloads, and timeouts. 1 to 10. |
| `retry.maxStallRetries` | `3` | Retries when a response stops arriving. Only used when `watchdog` is on. 1 to 10. |
| `retry.baseDelayMs` | `2000` | Wait before the first retry, in milliseconds. 250 to 60000. |
| `watchdog` | `false` | Stop and retry when a response stalls. Off by default because slow models and long silent reasoning are normal. |
| `watchdogTimeouts` | | How long counts as a stall. `/timeouts` sets these. |
| `watchdogTimeouts.firstChunkMs` | `300000` | Wait for the first chunk of a response, in milliseconds. 30000 to 900000. |
| `watchdogTimeouts.chunkMs` | `240000` | Longest gap between chunks. 30000 to 900000. |
| `watchdogTimeouts.toolMaxMs` | `900000` | Longest wait while tools run. 120000 to 1800000. |
| `watchdogTimeouts.forceResolveMs` | `5000` | Grace after a stop before the turn is closed. 1000 to 30000. |

The older `retry.maxAttempts` field still works as a default for both retry counts.

### Web search

| Field | Default | What it does |
|-------|---------|--------------|
| `webSearch` | `true` | Allow the `web_search` tool. Off means no web search at all. |
| `nativeSearch` | `true` | Let the model provider run the search on its own servers, where Empryo has tested that it works. Needs `webSearch`. |

With `nativeSearch` on, a supported model searches in one step and returns its own sources. Your search then goes only to your model provider. Two things to know:

- The provider runs the search, so Empryo cannot ask you to approve each search. Turn `nativeSearch` off if you want every search to run on your machine, with a prompt.
- The provider's search tool adds about 2,200 input tokens to each request. They are cached, so the real cost is lower.

Provider-side search is on for Claude (direct and through the proxy), GPT through the proxy, and OpenRouter models that support it. Other models use the search services you have keys for, with DuckDuckGo as a free fallback. `/web-search` shows which one is in use. You can change both settings in `/provider-settings` or in the desktop app's provider settings.

| Variable | What it does |
|----------|--------------|
| `EMPRYO_NATIVE_SEARCH_UNVERIFIED=1` | Also use provider-side search on Gemini, Grok, and Groq direct, which are not yet tested. |

### Provider tools

Some tools are run by the model provider, not by Empryo. Whether a tool is available depends on the provider and model, so these settings allow a tool but cannot guarantee it. See [provider tools](/docs/context/provider-tools).

| Field | Default | What it does |
|-------|---------|--------------|
| `computerUse` | `true` | Let the agent take screenshots and use the mouse and keyboard. It still needs a model that accepts images and a machine that supports it, and your OS may ask for permission. See [computer use](/docs/tools/computer-use). |
| `computerUseApps` | | Which apps the agent may control, with allow and deny lists per platform. |
| `codeExecution` | `true` | Let the provider run code in its own sandbox. Claude and OpenAI only. |
| `anthropicTextEditor` | `false` | Give Claude its own file-editing tool alongside Empryo's. Claude only. |

To see what is available for a model:

```bash
empryo --capabilities anthropic/claude-opus-4-6
```

These settings are under **General** in `/provider-settings` and in the desktop app's provider options.

### Browser

| Field | Default | What it does |
|-------|---------|--------------|
| `browser` | | The desktop app's [browser](/docs/tools/browser) panel. `browser.agentOpensHidden` starts a browser the agent opens minimised. |
| `terminalBrowser` | `true` | Give the agent the same `browser` tool in the terminal app and headless runs, using a hidden browser window. `false` removes the tool. |
| `terminalBrowserAllowExternal` | `false` | Let that browser open public websites. When off, it can only open `localhost` and private network addresses. |

### Agents and limits

| Field | Default | What it does |
|-------|---------|--------------|
| `disabledTools` | `[]` | Tools you have turned off. Tools that are always on are ignored here. See [tools](/docs/reference/tools). |
| `advisor` | | Model and defaults for the [advisor](/docs/tools/side-agents#advisor) (`/advise`). `advisor.contextChars` sets how much of the conversation each consult sends, in characters. |
| `skills.autoManage` | `true` | Let the agent search, install and load [skills](/docs/tools/skills) on its own. |
| `skills.autoLoad` | | Skills loaded into every session, by name. |
| `skills.rememberSession` | | Load the skills a session had again when you resume it. |
| `memory.autoDistill` | | Headless runs only. Save what the run learned to [memory](/docs/tools/memory) automatically. |
| `images.autoResize` | `true` | Shrink image attachments that are larger than the provider accepts. `EMPRYO_NO_IMAGE_RESIZE=1` turns it off for one run. |
| `goalLoop` | | Settings for the [goal loop](/docs/agents/goal-loop): rounds, extra checks, escalation. |
| `modelFallback` | `{}` | Backup models to try when a model keeps failing. See [model fallback](/docs/recipes/model-fallback). |
| `maxTurnSteps` | none | Step budget for one agent turn. Unset or `0` means no limit. |
| `subagentMaxSteps` | none | Step limit for helper agents and reviewers. |
| `subagentStreamProviders` | `[]` | Global-only list of provider ids whose dispatched helpers consume streams internally and return finished results. Main chat stays unchanged. Set through `settings(action:"set", key:"subagentStreamProviders", value:'["openrouter"]', scope:"global")`. `EMPRYO_SUBAGENT_STREAM_PROVIDERS=openrouter,my-provider` overrides the list; an empty environment value disables it. |
| `subagentMaxMs` | none | Time limit for a helper agent, in milliseconds. It stops at the next step after the limit. |
| `mcpServers` | `[]` | [MCP servers](/docs/tools/mcp) to start or connect to. |
| `providers` | | [Custom providers](/docs/providers/custom). |

### Accounts and gateways

| Field | Default | What it does |
|-------|---------|--------------|
| `copilotHost` | github.com | Your enterprise GitHub host for [Copilot](/docs/providers/copilot). Global config only. `COPILOT_GITHUB_DOMAIN` overrides it. |
| `llmgatewayAuth` | `"auto"` | Which LLM Gateway credential to use when you have both: `"key"`, `"login"`, or `"auto"`. |
| `llmgatewayLoginOrg` | `"default"` | Which organization the browser sign-in created its key in. `"devpass"` bills your DevPass subscription. |
| `llmgatewayBudget` | | A spending limit and reset day for the usage display. |
| `voice` | | [Voice input](/docs/surfaces/voice-input): speech model (`gpt-transcribe` by default with an OpenAI key), hands-free voice (`handsFree`), live dictation (`live`, `liveModel`, `delay`), `language`, `prompt`, `keywords`, insert mode, recorder. |
| `telemetry` | on | Anonymous usage counts. Opt out with `false`, `DO_NOT_TRACK=1`, or `EMPRYO_TELEMETRY=0`. `/developer` shows exactly what is sent. |

### Live updates

| Field | Default | What it does |
|-------|---------|--------------|
| `liveTranslations` | `true` | Download newer translations at most once every 6 hours. |
| `liveSkills` | `true` | Update the [skill that ships with Empryo](/docs/tools/skills) from empryo.com. Only newer versions, only if you have not edited your copy, and only when the download's checksum matches. |

Empryo also stores some of its own state in the config file, such as `onboardingComplete`, `configVersion`, and flags ending in `IntroSeen`. These are not settings. Changing them only shows or hides a one-time notice.

## Task router

Use a different model for each kind of work. See [use multiple models](/docs/recipes/task-router) for advice.

```json
"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 | Used for |
|------|----------|
| `spark` | Helper agents that read and research |
| `ember` | Helper agents that edit code |
| `explore` | The single `explore` agent. Uses `spark` if unset. |
| `webSearch` | Web search |
| `desloppify` | The cleanup pass after edits |
| `verify` | The review after edits |
| `goalReview` | The reviewer in the goal loop |
| `review` | `/review`. Uses `goalReview` if unset. |
| `compact` | Compaction |
| `semantic` | Genome summaries |
| `marionette` | The Marionette's file mapping |
| `namer` | Tab names |
| `default` | Anything without its own slot |

If a slot is empty, Empryo uses `default`, then the model you are chatting with. `taskRouter.maxConcurrentAgents` is the single limit for dispatched and background agents together (default `16`, `0` for no limit). There is no separate CPU or memory cap. Change it in desktop Settings → Agent → Routing → Parallel agents, or terminal `/router` → Concurrency. It applies live to agents already waiting.

## Agent features

```json
"agentFeatures": {
  "marionette": false,
  "desloppify": true
}
```

| Feature | What it does |
|---------|--------------|
| `marionette` | Experimental. Before each prompt, map which files matter, using the `taskRouter.marionette` model. See [the Marionette](/docs/concepts/marionette). |
| `desloppify` | Run a cleanup pass after agents edit code. |
| `pythonKernel` | Off by default. Add a Python session that keeps its state between calls. See below. |
| `toolLoading` | How tools are sent to the model: `"auto"` (default), `"provider"`, `"ours"`, `"all"`. See below. |
| `contextGc` | Off by default. Drop tool results the agent no longer needs during a long turn. `true`, or `{ "keepSteps": n, "minChars": n }` to tune it. |
| `backgroundAutoResume` | On by default. Wake the chat when a background agent finishes. |
| `backgroundResumeLimit` | How many times background agents may wake the chat per message you send. Default `10`, `0` for no limit. |

Change these with `/agent-features`, or in the desktop app under Settings.

### Tool loading

```json
"agentFeatures": { "toolLoading": "auto" }
```

Every tool sent to the model adds to the size of each request. To keep requests small, Empryo holds back tools you use less often. The agent finds a held-back tool with `tool_search` and runs it with `run_tool`. The list of tools does not change during a conversation, which keeps the provider's prompt cache working. See [tools](/docs/reference/tools).

| Choice | What happens |
|--------|--------------|
| `auto` | The provider hides unused tools where it can (Claude 4.5 and later, GPT 5.4 and later), and Empryo holds back the rest. Works on every model. |
| `provider` | Only the provider hides tools. Other models get every tool. |
| `ours` | Empryo holds back tools on every model. The provider's own hiding is off. |
| `all` | Every tool in every request. Nothing is hidden, and requests are largest. |

Tools from MCP servers are always reached through `run_tool`. When a server connects or disconnects mid-conversation, the agent is told in a note. `/tools` shows which tools are sent and which are held back for the current model.

### Python kernel

```json
"agentFeatures": { "pythonKernel": true }
```

This adds a `python_kernel` tool: a Python session that keeps its variables between calls. The agent can load a data file once and ask many questions about it, instead of starting a new `python` process each time. It uses IPython if it is installed, and plain Python otherwise. There is one session per project, it starts in the project folder, and `reset: true` clears it. A call that runs past its time limit restarts the session.

It is off by default because it runs code with your permissions, like `shell` does. It needs `python3` on your PATH. To turn it on for one run, set `EMPRYO_PYTHON_KERNEL=1`.

### Marionette mode

The Marionette is an experimental step that maps which files matter for a prompt before the agent starts. `marionetteMode` sets how hard it looks:

```json
"marionetteMode": "fast"
```

| Mode | How it works |
|------|--------------|
| `none` | Uses the code index only. No model call. |
| `fast` *(default)* | Searches the index, then one model call picks the files. |
| `assist` | Searches the index, then a model checks with a few tool calls. |
| `deep` | The model does the whole search itself. Slowest, and results vary more between runs. |

Change it with `/marionette none|fast|assist|deep`, in Settings, or for one run with `--marionette-mode`. `marionetteBudget` limits steps and time for `assist` and `deep`.

## Providers

Add keys and custom providers on these pages:

- [All providers](/docs/providers/overview): environment variables and `--set-key` commands.
- [Custom providers](/docs/providers/custom): any OpenAI-compatible API.
- [Copilot](/docs/providers/copilot): use your GitHub Copilot subscription.

### Extra request-body parameters

Some provider features are turned on by a field in the request, not by a tool. For example, DashScope reads `enable_search`. `extraBody` adds your own JSON to every chat request for a provider or a model.

```json
{
  "extraBody": {
    "proxy": { "enable_search": true },
    "proxy/gpt-5.6-luna": { "verbosity": "low" }
  }
}
```

Keys are a provider id or a full model id. When both match, the model's entry wins. [Custom providers](/docs/providers/custom#extra-request-body-parameters) have their own `extraBody` field, which this map can override per model.

Your fields replace anything Empryo would have sent under the same name. If the provider rejects a field, the request fails. Embedding requests do not get these fields.

> **Note:**
> A project's `extraBody` only applies after you trust the repository, because it can change any part of a request. Run `/trust`, or put the fields in your global config.

## Auth & key storage

Empryo stores keys in your system keychain when one is available, and in a protected file otherwise.

| Platform | Where keys are stored |
|----------|-----------------------|
| macOS | Login Keychain, service `empryo` |
| Linux | The system secret store through `secret-tool` (GNOME Keyring, KWallet) |
| Linux without `secret-tool` | `~/.empryo/secrets.json`, readable only by you |
| Windows | Encrypted for your user account (DPAPI), in `%LOCALAPPDATA%\Empryo\secrets.dat` |
| Windows without DPAPI | A plain JSON file in the same folder, readable only by you |
| Windows (WSL) | Same as Linux |

`empryo --set-key <provider> <key>` saves a key. `empryo --list-providers` shows which providers have one.

### Several keys for one provider

Run `--set-key` again with a different key and Empryo keeps both. When one account runs out of quota during a turn, Empryo switches to the next key and continues. When every key is used up, you see the provider's error.

A short rate limit waits and retries with the same key. Keys from environment variables are never rotated. This works for built-in and [custom](/docs/providers/custom#several-accounts-on-one-provider) providers. `/keys` lists what is stored.

### Lookup order

```json
{ "keyPriority": "env" }
```

| Value | Order |
|-------|-------|
| `"env"` (default) | Environment variable, then keychain, then file |
| `"app"` | Keychain, then file, then environment variable |

Use `"app"` if keys exported in your shell keep overriding the ones you saved.

### Use a key for one launch

Environment variables work in the terminal app too. Nothing is saved:

```bash
LLM_GATEWAY_API_KEY=sk-... empryo
ANTHROPIC_API_KEY=sk-ant-... empryo
```

There is no `--key` flag.

### Remove a key

`/keys` lists every provider and lets you delete a key. You can also delete it from your keychain directly, for example on macOS: `security delete-generic-password -a empryo -s anthropic-api-key`.

## Instruction files

Empryo can load project rules from the instruction files other AI tools use:

```json
{ "instructionFiles": ["empryo", "claude", "cursorrules"] }
```

| Key | File |
|-----|------|
| `empryo` | `EMPRYO.md` |
| `claude` | `CLAUDE.md` |
| `claude-local` | `CLAUDE.local.md` |
| `codex` | `AGENTS.md` |
| `agent-md` | `AGENT.md` |
| `cursorrules` | `.cursorrules` |
| `github-copilot` | `.github/copilot-instructions.md` |
| `cline` | `.clinerules` |
| `windsurf` | `.windsurfrules` |
| `aider` | `.aider.conf.yml` |
| `amp` | `AMPLIFY.md` |
| `gemini` | `GEMINI.md` |
| `qwen` | `QWEN.md` |
| `warp` | `WARP.md` |
| `junie` | `.junie/guidelines.md` |
| `zed` | `.rules` |
| `continue` | `.continuerules` |
| `roo` | `.roorules` |
| `augment` | `.augment-guidelines` |
| `trae` | `.trae/rules/project_rules.md` |
| `goose` | `.goosehints` |

Each file is read from the project folder and from your home folder. If they disagree, the project file wins. Choose files with `/instructions` in the terminal app, or under Settings → Instruction files in the desktop app.

### Load a file only for some models

By default, every enabled file loads for every model. `instructionRouting` limits a file to certain models or agents:

```json
{
  "instructionFiles": ["empryo", "claude", "codex"],
  "instructionRouting": {
    "claude": ["claude"],
    "codex": ["openai", "agent:reviewer"]
  }
}
```

With this setup, a Claude tab reads `EMPRYO.md` and `CLAUDE.md`, and a GPT tab reads `EMPRYO.md` and `AGENTS.md`. Switch a tab's model and the files change on the next message.

| Pattern | Matches |
|---|---|
| `claude`, `openai`, `google`, `xai`, `deepseek` | The model's maker, through any provider or gateway. `anthropic`, `gpt`, `gemini`, and `grok` also work. |
| `provider:proxy` | Exactly this provider |
| `family:google` | The model's maker, written out |
| `anthropic/*`, `proxy/gpt-*` | The full model id, with `*` wildcards |
| `*sonnet*`, `gpt-5*` | The model name, with `*` wildcards |
| `agent:<name>` | A custom agent (`--agent`, `/agent`) |

`/instructions` shows a **for:** row under each enabled file. Press Enter to cycle through Everyone, Claude, OpenAI, and Gemini, or type `/instructions route <file> <all|claude|openai|google>`. The desktop app has the same choice next to each switch. A file that is on but not for the current model is marked *not for this model*. Project settings override global ones.

## Privacy

Stop the agent from reading certain files:

```
/privacy add .env
/privacy add secrets/**
```

Some files are always blocked, including `.env`, `.pem` files, `credentials`, `id_rsa`, `.npmrc`, `.netrc`, `shadow`, and `passwd`.

### Trusting a repository

A repository's own `.empryo/config.json` could try to start programs on your machine. So until you trust a repository, Empryo ignores its `mcpServers`, `providers`, `presets`, and `extraBody` settings, and its hook files. Safe settings such as theme, model, and instructions still apply.

| Command | What it does |
|---------|--------------|
| `/trust` | Trust this repository |
| `/trust revoke` | Remove trust |
| `/trust list` | List trusted repositories |
| `empryo --trust` | Trust from the command line, for CI |

Trust is stored on your machine, outside the repository, so a repository cannot trust itself.

## Environment variables

| Variable | Default | What it does |
|----------|---------|--------------|
| `EMPRYO_NO_GENOME` | unset | Skip the Genome scan at startup. |
| `EMPRYO_MAX_OUTPUT_TOKENS` | `64000` | Output-token cap for models whose limit is not declared by the provider's live listing or models.dev. Overrides `performance.maxOutputTokens`. A declared limit always wins. |
| `EMPRYO_PRESETS` | unset | Presets to load at startup, separated by commas. `--plugin` sets this. See [presets](/docs/reference/presets). |
| `EMPRYO_NO_PROMPT` | unset | Set to `1` to skip the first-run add-on prompt. Useful in CI. |
| `EMPRYO_TELEMETRY` | unset | Set to `0` to turn off anonymous usage counts. |
| `EMPRYO_PYTHON_KERNEL` | unset | Set to `1` to turn on the Python kernel for one run. |
| `EMPRYO_ENABLE_GHOSTTY` | unset | Turn on the floating terminal on Windows, where it is off by default. See [Windows notes](/docs/installation#windows-notes). |
| `EMPRYO_HEARTH_SOCKET` | `<configDir>/hearth.sock` | Deprecated, [Hearth](/docs/tools/hearth) is turned off. Where Hearth's local socket lived. |
| `EMPRYO_HEARTH_APPROVAL_TIMEOUT_MS` | `300000` | Deprecated. How long Hearth waited for you to approve a remote tool call. |
| `EMPRYO_HEARTH_DENY_READ_REMOTE` | unset | Deprecated. Blocked read-only tools from Hearth chats too. |
| `EMPRYO_PROXY_VERSION` | latest | Install a specific version of the proxy add-on. |
| `EMPRYO_AUTO_INSTALL_ADDONS` | unset | Add-ons to install automatically, such as `proxy,neovim`. |
| `EMPRYO_MEMORY_LIMIT_MB` | `1536` | Memory limit for Empryo itself. Above it, memory-heavy analysis such as type-aware diagnostics is skipped. |
| `EMPRYO_TREE_MEMORY_LIMIT_MB` | `4096` | Memory limit for Empryo plus the programs it started, mostly language servers. |
| `EMPRYO_LSP_IDLE_MS` | `180000` | How long an unused language server keeps running before it stops. Lower it on a machine with little memory. Raise it if you switch between languages often. |
| `EMPRYO_LSP_MAX_CLIENTS` | `6` | How many language servers can run at once. Past this, the least recently used one stops. |
| `EMPRYO_NO_MOTION` | unset | Set to `1` to turn off animations in the terminal UI. `NO_MOTION` works too. |
| `EMPRYO_NO_IMAGE_RESIZE` | unset | Set to `1` to send image attachments at full size. |
| `EMPRYO_STREAM_CADENCE` | on | After 50 pieces of a reply, a stream that goes fully silent for 120 s (or 10 times its longest gap so far) is treated as stalled and retried. Set to `off` to wait for the full idle limit instead. |

> **Note:**
> For the memory and language-server limits, an empty, zero, negative, or invalid value uses the default.

## Morphs

Morphs are panels and boards you build in the desktop app. A morph can also give the agent rules and lookups, which Empryo calls its cells. These settings are read from your global config only, so a repository cannot loosen them. See [Morphs](/docs/tools/morphs).

| Key | Values | What it does |
|---|---|---|
| `cells.reach` | `"morph"` (default), `"all"` | Which sessions can use morphs. `"morph"`: only tabs in morph mode. `"all"`: every session. |
| `cells.views` | `"any"` (default), `"signed"`, `"off"` | Whether a morph's own display code may run. `"signed"`: only morphs signed by Empryo or by a key in `trustedKeys`. `"off"`: never. |
| `cells.autoApprove` | `false` (default), `true` | Skip the approval step for morphs you wrote yourself. |
| `cells.requireSigned` | `"official"`, `"trusted"`, `"any"` | Only allow signed morphs. |
| `cells.trustedKeys` | Ed25519 public keys, base64 | Your organization's signing keys, for `"trusted"`. |
| `cells.directories` | URLs to `index.json` files | Your organization's own morph directories. |

A morph you hide from the agent on its card stays hidden, whatever `reach` says. A morph that reads files from your repository, connects to a live socket, or runs its own display code only works after you trust the repository.

## Hooks

See [hooks](/docs/tools/hooks). Empryo reads hooks from five places: Claude Code's three settings files and Empryo's two config files. Every matching hook runs.

## Storage

`/storage` shows how much disk space each part of Empryo uses (Genome, sessions, plans, memory, input history, binaries, fonts) and lets you clean it up.

## Which setting wins

Session, then project, then global. A command saves to whichever scope it targets. Use `/model-scope` to save the current model for the project or for everywhere.
