# Config
URL: /en-US/docs/config

Data directories, config.json v1, .spirit/, and environment variables.



Shared user data follows the build quality, not the operating system's application-data directory.

## Data directory [#data-directory]

Override with `SPIRIT_DATA_DIR`. The server can also use `SPIRIT_SERVER_DATA_DIR` (wins over the former).

| Build  | macOS / Linux   | Windows                     |
| ------ | --------------- | --------------------------- |
| Stable | `~/.spirit`     | `%USERPROFILE%\.spirit`     |
| Dev    | `~/.spirit-dev` | `%USERPROFILE%\.spirit-dev` |

Breaking change: old platform data directories are not read or migrated automatically. Explicit data-directory overrides remain supported. Electron caches, browser storage, and window state remain in the private platform application directory.

Typical files:

```
{spiritDataDir}/
  config.json
  mcp.json
  hooks.json
  rule.md
  skills/
  chats/
  plans/
  extensions/
  automations/
  dreams/
  server.token
  server/instances/
```

CLI binaries use SPIRIT\_HOME. On Unix, the Stable install and shared data may have the same parent directory; bin/ and cli/ remain installation files. The installer setting does not select the shared-data directory.

## config.json v1 [#configjson-v1]

`schemaVersion` must be `1`. Any other value is rejected — delete the old file and [reconnect a provider](./providers.mdx). There is no migration from older shapes.

Core fields:

* `providers` — connected providers: endpoint, transport, credentials, models
* `activeModel`
* `imageGenerationModel` / `videoGenerationModel` / `secondaryLanguageModel`
* `agents` — agent toggles such as `agents.providerTools.enabled`
* `permission` — permission allowlist rules

`activeModel` and the other model slots are model refs: `{ "providerId": "…", "name": "…" }`, where `providerId` is a `providers[].id` and `name` is one of its `models[].name`.

### Provider entries [#provider-entries]

Each `providers[]` entry is a fully declarative connection — what the connect wizard writes is what the runtime reads. The runtime never re-derives `apiBase` from the provider's identity; site, plan, and cloud choices are baked into the final URL at connect time.

Connection-level fields:

* `id` (required) — unique entry id. Model refs and the internal keyring account point at it
* `label` — optional display name
* `apiBase` (required) — the endpoint, the single source of truth
* `transportKind` — wire protocol: `openai-compatible` (default) / `open-responses` / `anthropic` / `bedrock`
* `sdk` — full npm package name of the bundled SDK adapter (for example `@ai-sdk/openai-compatible`). Absent = the transport default; an unknown package name is rejected at load
* `headers` — literal extra request headers merged into every outbound request
* `body` — literal fields merged into every request body. An escape hatch for odd wire quirks — prefer a structured declaration where one exists
* `providerTools` — tools the provider exposes (web search, code interpreter). See [Provider Tools](./agent/tools.mdx#provider-tools)
* `fileUpload` — the upload channel for local files that should not go inline (`path` / `url`, `purpose`, `idPath`, `refTemplate`, `maxBytes`). Absent = media go inline
* `imageApi` / `videoApi` — API shape names for image / video generation; absent = no such generation
* `options` — transport parameters; the legal key set depends on `transportKind` × `sdk` (`awsRegion` for bedrock, `project` / `location` for `@ai-sdk/google-vertex`, `auth` / `storedState` / `applyPatch` switches on open-responses). Unknown keys are rejected
* `models` (required array, may be empty)

Model-level fields — `capabilities`, `contextLength`, `outputLimit`, `reasoningEffort`, `supportedReasoningEfforts`, `reasoningMode`, `supportedReasoningModes`, `supportsThinkingType`, `supportsThinkingSwitch`, `thinkingSwitch`, `serviceTiers`, `serviceTier` — may also be declared flat on the provider entry as defaults inherited by every model; a model's own declaration wins. Inside `models[]`, everything except `name` is optional, and absent means undeclared, not a default.

* `capabilities` tokens: `languageModel`, `image`, `audio`, `video`, `imageGeneration`, `videoGeneration`
* `outputLimit` is the output token cap, separate from `contextLength`
* `supportedReasoningEfforts` / `supportedReasoningModes` / `serviceTiers` are the sole picker and validation sources — an out-of-list selection is a load-time error, never silently clamped
* `thinkingEnabled` is your thinking on/off state (not a capability); it is model-level only and requires `supportsThinkingSwitch` declared

### Key channels [#key-channels]

Keys do not have to live in this file — the connect wizard writes them to the [keyring](./security.mdx) by default. Config may instead declare a channel, resolved in this order:

1. `apiKey` — plaintext. Not recommended; an escape hatch only
2. `apiKeyEnv` — the name of an environment variable to read the key from
3. `apiKeyKeyring` — `{ "service": "…", "account": "…" }`, an entry in an external keyring
4. Internal keyring — the implicit fallback written by the wizard (account `provider::{id}`)

Composite credentials (Bedrock IAM, Vertex service accounts) use a `credentials` slot map instead of the flat keys:

```json
{
  "credentials": {
    "accessKeyId": { "env": "AWS_ACCESS_KEY_ID" },
    "secretAccessKey": { "keyring": { "service": "…", "account": "…" } }
  }
}
```

Slot names are protocol fields — `apiKey`, `accessKeyId` / `secretAccessKey` (Bedrock IAM / SigV4), `clientEmail` / `privateKey` (Vertex) — and unknown slots are rejected. Each slot resolves `value` → `env` → `keyring` → internal keyring (`provider::{id}::{slot}`; the `apiKey` slot is plain `provider::{id}`). Flat keys and `credentials.apiKey` cannot coexist in one entry.

### agents.providerTools [#agentsprovidertools]

`agents.providerTools.enabled` gates all provider-declared tools at once (renamed from `agents.webSearch.enabled`; the semantics did not change: opt-out, on by default). Set to `false`, no provider tool entries or body switches reach requests.

### Catalog refresh and reconnect [#catalog-refresh-and-reconnect]

Routine catalog refreshes rewrite the model declaration fields the catalog owns (`capabilities`, `supportedReasoningEfforts`, `supportedReasoningModes`, `serviceTiers`, …) — model facts come from the catalog as the single source of truth, so manual edits to those fields are overwritten on the next refresh. Provider-level materializations (`apiBase`, `sdk`, `providerTools`, `fileUpload`, `options`, `imageApi` / `videoApi`) change only when you reconnect the provider. Reconnect resets the wizard-owned keys (edits you made to them are overwritten) and preserves everything else: `label`, credential channels, `headers` / `body`, flat model defaults, and models you added by hand.

### permission [#permission]

`permission` pins down what individual shell commands and file paths may do, on top of the session [approval level](./agent/approvals.mdx). Keys are tool names (`shell`, `read_file`); values map wildcard patterns to `allow`, `ask`, or `deny`.

```json
{
  "permission": {
    "shell": {
      "git *": "allow",
      "rm -rf *": "deny"
    }
  }
}
```

`deny` is absolute — no approval level, hook, or session memory overrides it. Pattern syntax, path semantics, and the full action list are in [Approvals](./agent/approvals.mdx). Verify rules without running anything: `spirit permission check --shell "git status"`.

The old `tool-permissions.json` (written by the "Always Trust" button) is deprecated: the code no longer reads or writes it, and there is no automatic migration. Leftover files are inert — delete them manually.

## Workspace `.spirit/` [#workspace-spirit]

| Path                 | Role                                       |
| -------------------- | ------------------------------------------ |
| `.spirit/rule.md`    | Workspace [rule](./customize/rules.mdx)    |
| `.spirit/skills/`    | Workspace [skills](./customize/skills.mdx) |
| `.spirit/mcp.json`   | Workspace [MCP](./customize/mcp.mdx)       |
| `.spirit/hooks.json` | Workspace [hooks](./customize/hooks.mdx)   |

Also used: `{workspace}/AGENTS.md`, `{workspace}/.agents/skills/`, `{workspace}/plans/`.

## Environment variables [#environment-variables]

| Variable                                                          | Role                               |
| ----------------------------------------------------------------- | ---------------------------------- |
| `SPIRIT_DATA_DIR`                                                 | Data directory                     |
| `SPIRIT_SERVER_DATA_DIR`                                          | Server data directory (wins)       |
| `SPIRIT_ACP_DATA_DIR` / `SPIRIT_ACP_WORKSPACE`                    | [ACP](./acp.mdx)                   |
| `SPIRIT_HOME` / `SPIRIT_VERSION` / `SPIRIT_DOWNLOAD_HOST`         | CLI installer                      |
| `SPIRIT_API_KEY` / `SPIRIT_API_BASE`                              | [CLI](./cli.mdx) process overrides |
| `SPIRIT_WEB_HOST` / `SPIRIT_WEB_PORT` / `SPIRIT_DESKTOP_WEB_HOST` | Desktop Web Host                   |
| `SPIRIT_TERMINAL_SHELL`                                           | Desktop PTY shell                  |
