| 1 | # Configuration Paths |
| 2 | |
| 3 | Starting with **Reasonix v1.8.1**, Reasonix uses one user-facing home directory |
| 4 | for global configuration and user-owned state. CLI and desktop share this |
| 5 | location. |
| 6 | |
| 7 | ## Reasonix Home |
| 8 | |
| 9 | | Platform | Reasonix home | |
| 10 | | --- | --- | |
| 11 | | macOS | `~/.reasonix` | |
| 12 | | Linux | `~/.reasonix` | |
| 13 | | Windows | `%APPDATA%\reasonix` | |
| 14 | |
| 15 | Set `REASONIX_HOME` to override Reasonix home for tests, CI, or portable |
| 16 | installations. Normal users should not need it. |
| 17 | |
| 18 | When `REASONIX_HOME` is set, the runtime is fully self-contained: all |
| 19 | configuration, state, cache, and data live under that directory tree. Legacy |
| 20 | migration, OS-home convention directory scanning, and all other fallback paths |
| 21 | are skipped so no data leaks in from a system-wide production install. |
| 22 | |
| 23 | Advanced test and portable setups may set `REASONIX_STATE_HOME` to move runtime |
| 24 | state such as sessions, archives, and memory. It does not move global config or |
| 25 | provider credentials: those remain under `REASONIX_HOME`. If an older build wrote |
| 26 | provider keys to `REASONIX_STATE_HOME/.env`, Reasonix imports those keys |
| 27 | non-destructively when `<Reasonix home>/.env` is missing them. |
| 28 | |
| 29 | ## What Lives There |
| 30 | |
| 31 | | Data | Path | |
| 32 | | --- | --- | |
| 33 | | Global config | `<Reasonix home>/config.toml` | |
| 34 | | Global provider credentials | `<Reasonix home>/.env` | |
| 35 | | Legacy credentials import source | `<Reasonix home>/credentials` | |
| 36 | | Global slash commands | `<Reasonix home>/commands/` | |
| 37 | | Global skills | `<Reasonix home>/skills/` | |
| 38 | | Global hooks | `<Reasonix home>/settings.json` | |
| 39 | | Remote-SSH managed known_hosts | `<Reasonix home>/remote/known_hosts` | |
| 40 | | Sessions | `<state root>/sessions/` | |
| 41 | | Archives | `<state root>/archive/` | |
| 42 | | Memory | `<state root>/memory/` and `<state root>/projects/` | |
| 43 | |
| 44 | `<state root>` defaults to `<Reasonix home>`. It only differs when |
| 45 | `REASONIX_STATE_HOME` is set. |
| 46 | |
| 47 | The global user config is named `config.toml`. Project-local config files keep |
| 48 | the name `reasonix.toml`. If someone says "global reasonix.toml", they usually |
| 49 | mean `<Reasonix home>/config.toml`. |
| 50 | |
| 51 | ## Global `config.toml` |
| 52 | |
| 53 | `<Reasonix home>/config.toml` stores non-secret configuration shared by the CLI |
| 54 | and desktop app. It may contain the same provider, plugin, UI, desktop, tool, |
| 55 | skill, sandbox, bot, and agent settings that Reasonix renders into user config. |
| 56 | Provider entries store the name of the credential variable in `api_key_env`, not |
| 57 | the secret value. |
| 58 | |
| 59 | Saved provider and bot credential variables are removed from every |
| 60 | model-controlled child-process environment. The global credential `.env` is |
| 61 | also hidden from Reasonix's file readers, sandboxed shell commands, and MCP |
| 62 | servers; this does not change the visibility of a project's ordinary `.env`. |
| 63 | On Windows, shell commands remain outside an OS sandbox as documented in the |
| 64 | Guide, so approve shell access only for trusted tasks. |
| 65 | |
| 66 | Example: |
| 67 | |
| 68 | ```toml |
| 69 | config_version = 1 |
| 70 | default_model = "deepseek/deepseek-v4-flash" |
| 71 | language = "zh" |
| 72 | credentials_store = "auto" # legacy compatibility; provider keys are in .env |
| 73 | |
| 74 | [ui] |
| 75 | theme = "auto" |
| 76 | cursor_shape = "bar" # CLI/TUI text cursor: underline|block|bar |
| 77 | show_turn_usage = false # hide per-request token/cost receipts in the TUI; default true |
| 78 | |
| 79 | [desktop] |
| 80 | provider_access = ["deepseek"] |
| 81 | |
| 82 | [[providers]] |
| 83 | name = "deepseek" |
| 84 | kind = "openai" |
| 85 | base_url = "https://api.deepseek.com" |
| 86 | models = ["deepseek-v4-flash", "deepseek-v4-pro"] |
| 87 | default = "deepseek-v4-flash" |
| 88 | api_key_env = "DEEPSEEK_API_KEY" |
| 89 | |
| 90 | [[plugins]] |
| 91 | name = "example" |
| 92 | command = "example-mcp-server" |
| 93 | ``` |
| 94 | |
| 95 | Do not put API key values in `config.toml`. This file is regular configuration: |
| 96 | it is safe to inspect, edit, migrate, and include in diagnostics after standard |
| 97 | redaction. Secrets belong in the global `.env` below. |
| 98 | |
| 99 | `[ui].cursor_shape` affects only the CLI/TUI composer. The default `bar` stays |
| 100 | visible without covering double-width CJK characters; use `block` or |
| 101 | `underline` if you prefer those cursor shapes. |
| 102 | |
| 103 | `[ui].show_turn_usage = false` hides the token and cost receipt appended to the |
| 104 | TUI transcript after each model request. Accounting and live status updates |
| 105 | remain active. The default is `true`. |
| 106 | |
| 107 | ### Custom provider `api_key_env` names |
| 108 | |
| 109 | When a custom provider is added from the desktop settings or `reasonix setup`, |
| 110 | Reasonix stores a generated `api_key_env` in `config.toml` and writes the secret |
| 111 | value to the matching key in the global `.env`. The generated name is stable, so |
| 112 | the same provider keeps using the same credential slot after restart. |
| 113 | |
| 114 | Reasonix derives the default from the provider name. Names that normalize to |
| 115 | ASCII keep readable env names such as `LOCAL_GATEWAY_API_KEY`; names made |
| 116 | entirely of non-ASCII characters get a stable hash suffix such as |
| 117 | `CUSTOM_d39b9067_API_KEY` so two Chinese provider names do not share |
| 118 | `CUSTOM_API_KEY`. Names beginning with a digit get a `CUSTOM_` prefix so the |
| 119 | generated environment variable remains valid; for example, `9router` becomes |
| 120 | `CUSTOM_9ROUTER_API_KEY`. |
| 121 | |
| 122 | In the CLI custom-provider wizard, the provider name is generated from the base |
| 123 | URL first, then the same provider-name rule is applied. For example |
| 124 | `https://token.sensenova.cn/v1` creates provider name |
| 125 | `custom-token-sensenova-cn`, whose default key env is |
| 126 | `CUSTOM_TOKEN_SENSENOVA_CN_API_KEY`. Press Enter to accept that default, or type |
| 127 | an explicit env name such as `CUSTOM_API_KEY` if you intentionally want to share |
| 128 | one credential across providers. |
| 129 | |
| 130 | Existing configs are not rewritten on upgrade. If an old custom provider already |
| 131 | uses `CUSTOM_API_KEY`, it will keep working with that key. If several old custom |
| 132 | providers accidentally share `CUSTOM_API_KEY`, edit each provider's |
| 133 | `api_key_env` to a distinct name and save the corresponding API key again. |
| 134 | |
| 135 | ### Custom provider endpoint URLs |
| 136 | |
| 137 | Custom OpenAI-compatible providers normally store an API endpoint in `base_url`. |
| 138 | Reasonix sends chat requests to `base_url + "/chat/completions"` and probes model |
| 139 | discovery candidates such as `/models` and `/v1/models`. If a gateway gives you a |
| 140 | complete chat request URL, set `chat_url`; Reasonix will use it directly and will |
| 141 | not append `/chat/completions`. If model discovery needs a separate address, set |
| 142 | `models_url`. |
| 143 | |
| 144 | If a gateway requires vendor-specific top-level request body fields, set |
| 145 | `extra_body`, for example `extra_body = { enable_thinking = true }`. These values |
| 146 | are merged into the OpenAI-compatible chat JSON request body without allowing |
| 147 | core fields such as `model`, `messages`, `tools`, or `stream` to be overridden. |
| 148 | |
| 149 | ## Global `.env` |
| 150 | |
| 151 | `<Reasonix home>/.env` is the single runtime source for provider API keys saved |
| 152 | by Reasonix. The setup wizard, desktop settings, CLI missing-key prompts, and |
| 153 | provider-key delete actions all read or write this file through the same |
| 154 | credential helpers. |
| 155 | |
| 156 | Structure: |
| 157 | |
| 158 | ```dotenv |
| 159 | DEEPSEEK_API_KEY=sk-... |
| 160 | GEMINI_API_KEY=... |
| 161 | ANTHROPIC_API_KEY=... |
| 162 | # reasonix-cleared OLD_API_KEY |
| 163 | ``` |
| 164 | |
| 165 | Rules: |
| 166 | |
| 167 | - one `KEY=value` assignment per line; |
| 168 | - blank lines and `#` comments are ignored; |
| 169 | - `export KEY=value` and quoted values are accepted when reading; |
| 170 | - multiline values are rejected by Reasonix writes; |
| 171 | - keys must use shell-style names such as `DEEPSEEK_API_KEY`; |
| 172 | - `# reasonix-cleared KEY` comments are non-secret tombstones written after a key |
| 173 | is deleted so legacy stores do not silently re-import it; |
| 174 | - Reasonix writes this file with restricted permissions where the OS supports |
| 175 | them. |
| 176 | |
| 177 | For provider requests, Reasonix resolves only this global `.env`. Project `.env` |
| 178 | files, home `.env` files, inherited shell environment variables, the old |
| 179 | `credentials` file, and the OS keyring do not act as runtime provider-key |
| 180 | fallbacks. Project `.env`, home `.env`, and inherited shell environment values |
| 181 | are not imported into the global credentials file. The old `credentials` file |
| 182 | and old keyring entries are read only as non-destructive migration sources when |
| 183 | the new global `.env` is missing a key. Project `.env` files are still read as |
| 184 | workspace-scoped, non-provider expansion sources for `${VAR}` references in |
| 185 | MCP/plugin env, headers, URLs, commands, and args; those values are not written |
| 186 | into the process environment, and Reasonix control variables such as |
| 187 | `REASONIX_HOME`, `REASONIX_STATE_HOME`, and `XDG_CONFIG_HOME` are ignored there. |
| 188 | |
| 189 | Caches remain in the OS cache directory, for example |
| 190 | `~/Library/Caches/reasonix` on macOS, `$XDG_CACHE_HOME/reasonix` or |
| 191 | `~/.cache/reasonix` on Linux, and `%LOCALAPPDATA%\reasonix\cache` on Windows. |
| 192 | Set `REASONIX_CACHE_HOME` to override the cache root. When `REASONIX_HOME` is |
| 193 | set, the cache is placed under `$REASONIX_HOME/cache` (unless |
| 194 | `REASONIX_CACHE_HOME` is also set, which takes precedence). |
| 195 | |
| 196 | ## Config Priority |
| 197 | |
| 198 | Runtime configuration is resolved in this order: |
| 199 | |
| 200 | ```text |
| 201 | command-line flags |
| 202 | > project ./reasonix.toml |
| 203 | > global <Reasonix home>/config.toml |
| 204 | > compatible legacy global config |
| 205 | > built-in defaults |
| 206 | ``` |
| 207 | |
| 208 | Writes always target the new global path: |
| 209 | |
| 210 | ```text |
| 211 | macOS/Linux: ~/.reasonix/config.toml |
| 212 | Windows: %APPDATA%\reasonix\config.toml |
| 213 | ``` |
| 214 | |
| 215 | ## Legacy Migration |
| 216 | |
| 217 | Starting with **v1.8.1**, Reasonix automatically checks legacy locations on |
| 218 | startup before the first config load. Migration is synchronous, one-time, and |
| 219 | non-destructive: old files are copied or converted to Reasonix home and left |
| 220 | untouched. |
| 221 | |
| 222 | Legacy config sources include: |
| 223 | |
| 224 | ```text |
| 225 | ~/Library/Application Support/reasonix/config.toml |
| 226 | ~/.config/reasonix/config.toml |
| 227 | ~/.reasonix/reasonix.toml |
| 228 | ~/.reasonix/config.json |
| 229 | ``` |
| 230 | |
| 231 | Legacy credentials, memory files, and sessions are also imported into Reasonix |
| 232 | home when the new destination does not already exist. Legacy provider keys are |
| 233 | copied into `<Reasonix home>/.env` only when that file does not already contain |
| 234 | the same key. If the new global config already exists, it wins and legacy config |
| 235 | files are only kept as compatibility fallbacks. |
| 236 | |
| 237 | Starting in **v1.9.1**, Reasonix also backfills MCP servers from known legacy |
| 238 | paths, legacy `config.json`, desktop-registered projects, and restored tab |
| 239 | projects into the global `<Reasonix home>/config.toml`. Existing global |
| 240 | `[[plugins]]` entries win by name, so project or legacy entries never overwrite a |
| 241 | server the user already configured globally. Source files are left untouched, and |
| 242 | the backfill writes a one-time marker so a user-deleted global MCP server is not |
| 243 | recreated repeatedly from an old project config. |
| 244 | |
| 245 | ## Manual Migration Rescue |
| 246 | |
| 247 | If Reasonix has already created the new home directory but some legacy data was |
| 248 | not present yet, or if the desktop app was opened before the old paths were |
| 249 | available, run the migration rescue command from either frontend: |
| 250 | |
| 251 | ```text |
| 252 | /migrate |
| 253 | ``` |
| 254 | |
| 255 | In the CLI TUI, type `/migrate` into the chat input. In the desktop app, type the |
| 256 | same command into the composer. The command prints progress notices while it: |
| 257 | |
| 258 | 1. checks legacy config and credentials, |
| 259 | 2. scans known legacy memory locations, |
| 260 | 3. scans known legacy session directories, |
| 261 | 4. imports memory files and sessions that were not previously imported, and |
| 262 | 5. prints a final summary. |
| 263 | |
| 264 | If old v0.x sessions live outside the known legacy locations — for example a |
| 265 | Windows v0.52 install/data directory chosen during setup — pass that directory |
| 266 | explicitly: |
| 267 | |
| 268 | ```text |
| 269 | /migrate --from "D:\OldReasonix" |
| 270 | ``` |
| 271 | |
| 272 | The explicit form imports sessions only. The path may be the old install |
| 273 | directory, a `.reasonix`/data directory, or the `sessions` directory itself; |
| 274 | Reasonix checks the common layouts below that root and uses a source-specific |
| 275 | marker, so a previous plain `/migrate` run does not hide the later import. |
| 276 | |
| 277 | The rescue command is intentionally non-destructive. It does not overwrite an |
| 278 | existing `<Reasonix home>/config.toml`; if the new config already exists, copy |
| 279 | any missing legacy settings across by hand. It copies legacy memory files only |
| 280 | when the destination file is absent. It also respects session import markers, so |
| 281 | sessions that were already imported and later deleted by the user will not be |
| 282 | restored on a later `/migrate` run. |
| 283 | |
| 284 | Version limits: |
| 285 | |
| 286 | - Automatic migration starts in **v1.8.1**. |
| 287 | - `/migrate` is available only in Go-based Reasonix builds that include the |
| 288 | command. If Reasonix reports `unknown command`, upgrade first and rerun it. |
| 289 | - The command is not available in the legacy `0.x` TypeScript line. |
| 290 | - Plain `/migrate` rescans the legacy locations listed above. Use |
| 291 | `/migrate --from <path>` only for a known v0.x session source; it is not a |
| 292 | backup restore tool or a downgrade importer. |
| 293 |