# Settings

Atomic uses JSON settings files with project settings overriding global settings.

| Location | Scope |
|----------|-------|
| `~/.atomic/agent/settings.json` | Global (all projects) |
| `.atomic/settings.json` | Project (current directory) |

Edit directly or use `/settings` for common options. Choosing a model or thinking level with `/model`, `/thinking`, or their cycling shortcuts automatically saves it as the startup default. Thinking choices also update the active model's saved thinking level. `/scoped-models` saves cycle-list changes automatically. SDK calls, session restoration, and automatic fallbacks do not overwrite these defaults unless persistence is explicitly requested. Atomic also reads legacy `~/.pi/agent/settings.json` and `.pi/settings.json` as compatibility fallbacks, with `.atomic` paths taking precedence.

For editor completion and validation, add `"$schema": "https://raw.githubusercontent.com/bastani-inc/atomic/main/packages/coding-agent/schemas/settings.schema.json"` to `settings.json`. Atomic preserves `$schema` and settings it does not recognize, such as extension settings, when it saves.

Saving an Atomic setting applies only the changed fields to the corresponding `.atomic` file; it does not copy untouched fallback fields out of `.pi`. To intentionally override an inherited array such as `packages`, set it in `.atomic`, including an explicit empty array (`"packages": []`) when the inherited list should be disabled.

## On this page and its guide

This page is the exhaustive settings reference: every field, its default, and its constraints. If you are writing your first settings file or setting up a project-scoped override, start with the [Configure Atomic](/guides/configuration) guide.

## Project Trust

On interactive startup, Atomic asks before trusting a project folder that contains trust-gated project inputs and has no saved decision for the folder or a parent folder in `~/.atomic/agent/trust.json`. Trusting a project allows Atomic to load project-local `.atomic/settings.json` and `.atomic` resources, legacy `.pi/settings.json` and `.pi` resources, project-local context files, install missing project packages, and execute project extensions.

The startup prompt appears on its own, before the interface paints, and the interface appears once you choose. If you decline, the transcript warns that project resources are ignored; if you trust the project, it does not. Project resources and borrowed project-local code stay blocked until authorized. The trust dialog does not require a model request. Trusted global and explicitly authorized CLI extensions can report the wait.

Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a trust prompt. Without an applicable saved trust decision, they use `defaultProjectTrust` from global settings: `ask` (default) and `never` ignore trust-gated project inputs, while `always` trusts them. Pass `--approve`/`-a` or `--no-approve`/`-na` to override project trust for one run.

If no extension or saved decision applies, `defaultProjectTrust` controls the fallback behavior. Set it to `"ask"`, `"always"`, or `"never"` in `~/.atomic/agent/settings.json`, or change it with `/settings`.

`atomic config` and package commands use the same project trust flow. Pass `--approve` to trust project-local settings for one command or `--no-approve` to ignore them.

Use `/trust` in interactive mode to save a project trust decision for future sessions, including trust for the immediate parent folder. It writes `~/.atomic/agent/trust.json` only; the current session is not reloaded, so restart Atomic for changes to take effect.

Atomic may treat a bare directory without trust-gated inputs as implicitly trusted. Inert state directories such as `.atomic/todos/` and `.atomic/sessions/` neither require trust nor disable deferred resource startup.

Interactive startup makes the editor available while resources load. If you submit early, the prompt waits with a spinner until the tools, skills, templates, and provider updates are ready. You can still type or cancel. Newly loaded resources appear in the normal disclosure; there is no separate loading spinner before submission.

Explicit provider/model choices, resource flags, system-prompt inputs, metadata commands, and non-TTY modes normally finish loading before becoming ready. Trust-requiring resources always wait for authorization.

If trust-requiring config appears later, Atomic asks again on the next launch until you save a persistent decision. Implicit startup trust is persisted automatically only by the existing `/reload` flow, when reload discovers trust-requiring resources in an already-trusted session.

Settings and trust JSON files may start with a UTF-8 BOM, as commonly written by older Windows tools; Atomic strips that leading marker before parsing.

## All Settings

### Herdr

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `herdr.enabled` | boolean | `true` | Enable the built-in reporter in an eligible Herdr pane. Set to `false`, then reload or restart to opt out. Requires `mode: "tui"`, a UI, and the Herdr environment variables. Child sessions and other modes never claim. |

See [Herdr](/herdr) for state aggregation, reporter conflicts, privacy, and Herdr 0.8.2 limitations.

### Model & Thinking

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `defaultProvider` | string | - | Startup provider, saved automatically when you switch models interactively |
| `defaultModel` | string | - | Startup model ID, saved automatically when you switch models interactively |
| `routerModel` | string | `""` | Inference model for workflow-stage and subagent `model: "auto"` selection only. An exact `provider/model` selects a registered chat or classifier model. `auto` and empty use the current chat model. Does not change chat or `structured_output` tool inference. |
| `modelRouting` | object | `{}` | Provider and model filters for the models `model: "auto"` may select: `allowedProviders` and `excludedProviders` (provider ID arrays), `allowedModels` and `excludedModels` (model ID or glob pattern arrays). Does not change `routerModel`. See [modelRouting](#modelrouting). |
| `defaultThinkingLevel` | string | - | Startup thinking level, saved automatically on interactive model/thinking changes: `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"`, `"max"`; clamped to the active model's supported levels |
| `modelThinkingLevels` | object | - | Per-model startup thinking levels keyed by `"provider/modelId"`; updated automatically on interactive model/thinking changes, or configured from `/settings` → Default thinking level per model |
| `hideThinkingBlock` | boolean | `false` | Hide thinking blocks in output |
| `thinkingBudgets` | object | - | Custom token budgets per thinking level. Anthropic, Google, and Bedrock use these natively. OpenAI-compatible models use them when `compat.thinkingTokenBudgetField` (or `supportsThinkingTokenBudget`) is set. |
| `showCacheMissNotices` | boolean | `false` | Show transcript notices for significant prompt-cache misses, billed compaction or branch-summary usage, and provider recovery diagnostics such as dropped Anthropic thinking blocks, including when a persisted transcript is resumed |
| `fallbackModels` | string[] | - | Ordered fallback models, written as `"provider/model"` with optional model-supported reasoning suffixes such as `:high`, `:xhigh`, or `:max`. Used by main-chat turns and, since compaction fallback rungs, borrowed for compaction planner requests |

`defaultProvider` and `defaultModel` form one exact saved selection when both are present. Atomic waits for built-in, configured, and extension provider registration before classifying the provider.

If it remains unsupported, Atomic does not silently switch providers:

- Interactive mode stays live with a generic configuration warning.
- Print and JSON modes write the warning to stderr and exit nonzero before prompting. JSON stdout stays JSONL-clean.
- RPC rejects `prompt` until a successful explicit `set_model` selects an available model or an explicit model cycle returns a different available model. A null or unchanged cycle does not clear the condition.

Normal automatic selection of an available authenticated model remains enabled if the provider is supported but its saved model is unknown or lacks configured authentication. It also remains enabled when either field is omitted. Valid extension-provider defaults can resolve after deferred extension loading. Update an unsupported pair or choose a model with `/model`.

#### routerModel

```json
{ "routerModel": "" }
```

Use `/settings` → **Router model** to change the effective selection. If the project already defines `routerModel`, the picker edits that project override; otherwise it saves the global default in `~/.atomic/agent/settings.json`. The picker identifies which scope it will save. Choose **Automatic** to save `""` in that scope. `""` and `auto` both use the current chat model; saved classifier credentials do not change that choice. To pin a decision model, choose an exact ID from the current registry, such as `typesafe/jev-latest`, or a chat model by provider/model ID. A classifier is not a chat model and does not appear in `/model`. Run `/reload` or restart Atomic to apply the saved choice to an already-running isolated engine.

An explicit ID other than `auto` is resolved through the current model registry: a registered classifier first, otherwise a chat model. Built-in gateway classifiers include `vercel-ai-gateway/typesafe-ai/jev`, `opencode/jev-1.13`, and `opencode/jev-1.13-free`; authenticate their provider before choosing them. An invalid explicit ID, image-generation model, non-string value, or surrounding whitespace fails the decision instead of silently changing providers. An explicit empty project value overrides a global selection and restores the current chat model.

A failed explicit classifier routing attempt switches to the current chat model when one exists. That includes missing credentials, an unavailable classify operation, a provider size or context rejection, a refusal, and a malformed answer. Transient retries follow the provider operation and retry settings. Chat routing gets an initial attempt plus three corrective retries for invalid output, using the same context. Each routing inference must finish within a wall-clock deadline taken from [`httpIdleTimeoutMs`](#http), 10 minutes by default, covering its corrective retries and any chat fallback; otherwise routing fails like any other total inference failure. Cancel the request to stop sooner. Independent provider, credential-preparation, and enclosing tool-request limits still apply. The fallback can incur chat-provider charges. Cancellation does not trigger fallback.

A classifier `routerModel` such as Jev only chooses between the shortlisted models and never receives the task; a chat model (`routerModel` when it is one, otherwise the current chat model) reads the task to answer the routing questions. If the selected classifier rejects the request, routing switches to the current chat model.

Routing fallbacks are recovered automatically and are not printed to the terminal or added to the conversation. Set `ATOMIC_MODEL_ROUTING_DEBUG=1` to print them while debugging model selection.

This setting selects inference for [workflow-stage `model: "auto"`](/workflows/authoring#automatic-stage-model-selection) and [subagent `model: "auto"`](/subagents/reference#automatic-model-selection). It does not directly select the child execution model or change the selected chat model, `structured_output` tool, or general structured-output inference. The decision provider may be any registered classifier or chat model, never an image-generation model; execution `auto` selects only chat language models, including multimodal-input chat. The selected router provider receives the routing context, so choose a provider permitted to process that data. Authenticate a pinned classifier with that provider's login, such as `/login typesafe` or `TYPESAFE_API_KEY` for TypeSafe Jev. See [Structured decisions](/sdk/structured-decisions) and [TypeSafe Jev](/providers#typesafe-jev).

Remove secrets from routing tasks, inputs, and workflow descriptions/contracts before calling the tool. A routing-context credential error stops before inference or launch. Known configured credentials are screened even when they belong to a provider other than the router. Remove the credential from the supplied context or registered definition, reload a changed definition, then retry explicitly. The guard does not detect every possible secret.

#### modelRouting

```json
{
  "modelRouting": {
    "allowedProviders": ["github-copilot", "openai-codex", "anthropic"],
    "excludedProviders": ["openrouter"],
    "allowedModels": ["github-copilot/*", "anthropic/claude-sonnet-*", "openai-codex/gpt-6.1-sol"],
    "excludedModels": ["*-fast"]
  }
}
```

Limits which models workflow stages and subagents with `model: "auto"` can be routed to, including builtin workflow stages that do not name a model. It filters the candidates only; the model that makes the decision is still `routerModel`.

- `allowedProviders`: when nonempty, only models from these providers are candidates.
- `excludedProviders`: models from these providers are never candidates, even if they are also allowed.
- `allowedModels`: when nonempty, only models matching one of these patterns are candidates.
- `excludedModels`: models matching any of these patterns are never candidates, even if they are also allowed.

Use provider IDs as shown by `/model` or `workflow({ action: "models" })`, such as `github-copilot`, `openai-codex`, `anthropic`, or `openrouter`. For example, to route only to your subscriptions, exclude the API-billed providers you have configured. The Claude subscription and the Anthropic API both use the `anthropic` provider, so the provider lists cannot separate them.

Model patterns use the same format as [`enabledModels`](#models) and `--models`: a full `provider/model` ID, a bare model ID, or a glob such as `anthropic/claude-*` or `*sonnet*`. Matching is case-insensitive. A pattern without glob characters selects a single model ID, so use a glob to cover a family; a bare ID offered by several providers covers each of them, so use `provider/model` to pick one. A thinking suffix such as `anthropic/claude-opus-4-8:high` selects the model only; it does not limit the effort `auto` chooses. A candidate must pass every list. Patterns that match no available model are ignored, so an allowlist whose patterns match nothing leaves no candidate.

A project list replaces the global list of the same name; the other lists are kept. A subagent call or workflow stage that sets `modelConstraints.allowedProviders` or `excludedProviders`, for example because you asked for a provider, uses its own lists instead of the provider lists here for that call. `allowedModels` and `excludedModels` always apply, and the call's own `modelConstraints.allowedModels` can only narrow them. Provider lists in an agent definition or inherited from a parent workflow only narrow these settings; they never lift an exclusion. The filters apply to the routed model, its ranked fallbacks, any other fallback models the stage or subagent would try, and the current chat model that `auto` falls back to when routing fails, so none of them can run a filtered-out model.

If the filters leave no eligible model, the stage or subagent fails before launch with an error that names the settings involved, such as `modelRouting.allowedModels`; Atomic never falls back to the unfiltered catalog. A run resumed after you exclude a provider or model rejects a recorded selection that is no longer allowed instead of using it.

These settings apply only to `model: "auto"`. A stage, task, or agent that names a concrete model, and its explicit fallback models, run as written.

To audit a routing decision, the stage's `routerSelection` in `workflow({ action: "status", runId })` lists the chosen model and fallbacks, and `candidates` lists every model the router could choose from after these filters and the task's image and long-context needs. Subagent results carry the same `routerSelection`.

#### thinkingBudgets

```json
{
  "thinkingBudgets": {
    "minimal": 1024,
    "low": 4096,
    "medium": 10240,
    "high": 32768
  }
}
```

#### fallbackModels

`fallbackModels` gives main-chat turns an ordered model fallback chain. Atomic starts with the selected/default model and advances to the next configured model after exhausting same-model retries for a retryable provider/model failure. It continues the same turn. This includes rate limits and quota/usage-limit exhaustion, such as `The usage limit has been reached`.

If `retry.enabled` is `false`, Atomic skips same-model retries and moves directly to the next fallback for retryable failures. Non-retryable task failures and cancellations do not trigger fallback.

The fallback model and its thinking level remain active for later turns in the same main-chat session. Choose another model explicitly with `/model` or model cycle to change them.

Workflow stages that set their own `model` or `fallbackModels` never use this list; they advance only the chain they declare. See [`fallbackModels`](/workflows/api-reference#fallbackmodels).

A failure that another request to the same model cannot repair — a rejected credential, an unavailable model, a request that model cannot serve — takes that model out of the chain for the rest of the turn at **every** reasoning level, so a candidate that differs only by its `:low`/`:high` suffix is skipped rather than spent. Transient rate-limit and transport failures keep those reasoning variants, because retrying them can succeed.

Context overflow keeps its normal recovery order: compaction runs first, and a compactable overflow costs no fallback candidate. Only once compaction is disabled, fails, or reports the overflow unresolved does Atomic advance to the next configured candidate, which is how a larger-context model gets a chance at the turn.

Changing the reasoning level after fallback is not a model choice, so the fallback model stays active with the reasoning level you selected. Only an explicit `/model` selection or model cycle changes the session model.

The same list is also **borrowed by compaction**. When the compaction range planner cannot produce a usable plan on the current model — a rate limit, quota exhaustion, provider error, context overflow, or an empty plan — Atomic runs one planner request against the next configured candidate, using that candidate's own credentials. **A configured fallback model may therefore receive the compaction transcript.** Borrowing is planner-only: it never changes the session model, thinking level, or model history, it appends no model-change entry, and it emits no fallback status. See [Compaction](/compaction#planning-rungs-and-failure-behavior).

Fallback entries should be fully qualified `provider/model` ids. Add a reasoning suffix to a candidate to override the effort for that fallback only; valid suffixes are `:off`, `:minimal`, `:low`, `:medium`, `:high`, `:xhigh`, and `:max`. Atomic clamps or hides levels that the selected model's capability map does not support.

```json
{
  "defaultProvider": "openai-codex",
  "defaultModel": "gpt-5.5",
  "defaultThinkingLevel": "high",
  "fallbackModels": [
    "anthropic/claude-opus-4-8:xhigh",
    "github-copilot/gpt-5.5:high"
  ]
}
```

Fallback attempts are visible as model changes in the session transcript and as a fallback status in the UI. Switching providers can change latency, billing, data-handling terms, and subscription/credit usage. Configure only providers you are comfortable sending the current conversation and tool context to.

`enabledModels` is separate: it only controls the interactive Ctrl+P model cycle list and is not used as an implicit fallback chain. It does not limit `model: "auto"` routing; use [`modelRouting.allowedModels`](#modelrouting) for that.

### Fast models

Fast inference is not a setting. Where a provider supports it, Atomic publishes a second selectable model whose canonical ID is the base model ID plus `-fast`, and you choose it the same way you choose any other model — in `/model`, as a startup default, in `fallbackModels`, in `enabledModels`, in a workflow stage's `model`, or in a subagent definition. Thinking suffixes work unchanged: `openai-codex/gpt-5.6-sol-fast:medium`.

Normal and fast IDs stay distinct everywhere, so `fallbackModels` can list both and each attempt is recorded separately:

```json
{
  "fallbackModels": [
    "openai-codex/gpt-5.6-sol-fast:medium",
    "openai-codex/gpt-5.6-sol:medium"
  ]
}
```

See [Providers](/providers#fast-models) for which providers publish fast variants, what each one sends upstream, and how an exact `-fast` model ID you own yourself takes precedence over the derived one.

### UI & Display

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `theme` | string | `"dark"` | Theme name (`"dark"`, `"light"`, `"system"`, a Catppuccin built-in, or custom). `"system"` derives its palette from the terminal; see [Themes](/themes) |
| `fullscreenScrollbar` | string | `"auto"` | Fullscreen transcript scrollbar: `"auto"` shows it temporarily while scrolling, `"always"` reserves the rightmost transcript column and keeps it visible, and `"hidden"` hides it. The thumb can be dragged when shown. |
| `fullscreenExitOutput` | string | `"transcript"` | Fullscreen exit output: `"transcript"` prints the final transcript and session resume hint, while `"resume-hint"` restores the terminal's previous screen and prints only the resume hint. Settable from `/settings` |
| `fullscreenCopyOnSelect` | boolean | `true` | Copy fullscreen text selections automatically on mouse release. When `false`, selection only highlights text. Ctrl+X does not copy; `/copy` copies the last assistant message. Settable from `/settings` |
| `fullscreenWheelScrollLines` | `"auto"` or number | `"auto"` | Lines per mouse-wheel tick in fullscreen views. `"auto"` uses terminal-aware scrolling; numeric values are clamped to 1–100. Settable from `/settings` |
| `quietStartup` | boolean or `"header"` | `false` | `true` hides the startup header. `"header"` keeps the startup header but hides the model scope line |
| `defaultProjectTrust` | string | `"ask"` | Fallback project trust behavior: `"ask"`, `"always"`, or `"never"`. Global setting only |
| `collapseChangelog` | boolean | `false` | Show a one-line update notice after updates instead of the What's New highlights; `/changelog` shows the full changelog |
| `enableInstallTelemetry` | boolean | `true` | Send a version-adoption ping on the first interactive launch with fresh settings, and on the first interactive launch after an update whose version has changelog entries. This does not control update checks |
| `firstRunOnboardingStartedVersion` | string | - | Managed onboarding state; leave unchanged |
| `onboardedVersion` | string | - | Managed onboarding completion state; leave unchanged |
| `enableAnalytics` | boolean | `false` | Opt in to analytics during first-run setup |
| `trackingId` | string | - | Locally generated analytics identifier when analytics is enabled |
| `deviceId` | string | - | Managed global installation identity, created only when a provider sign-in needs it. Project values are ignored |
| `doubleEscapeAction` | string | `"tree"` | Action for double-escape: `"tree"`, `"fork"`, or `"none"` |
| `treeFilterMode` | string | `"default"` | Default filter for `/tree`: `"default"`, `"no-tools"`, `"user-only"`, `"labeled-only"`, `"all"` |
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
| `outputPad` | number | `1` | Horizontal transcript padding for messages, tool output, `!` command output, and summary blocks. `0` or `1` |
| `externalEditor` | string | - | Command for the Ctrl+G external editor; takes precedence over `$VISUAL`/`$EDITOR`. Defaults to Notepad on Windows and `nano` elsewhere |
| `autocompleteMaxVisible` | number | `5` | Max visible items in the default editor and custom editors installed through `ctx.ui.setEditorComponent()` (3-20) |
| `showHardwareCursor` | boolean | `false` | Use the terminal cursor instead of Atomic's drawn cursor. Atomic still positions it for IME support |

Interactive sessions use fullscreen, with the transcript above the docked editor and status area. Wheel and trackpad input scrolls the focused workflow graph or stage chat first, then the transcript when the overlay does not consume it. Transcript scrolling, scrollbar dragging, and text selection remain available outside overlays. Overlay selections clear when returning to main chat and are not copied during that transition.

Transient notices stack while visible.

The alternate screen normally restores the terminal's prior contents on exit, so an interactive transcript does not remain in terminal scrollback. The `fullscreenExitOutput` setting changes what exiting prints: `"transcript"` (the default) paints the final transcript plus a session resume hint on the main screen, while `"resume-hint"` restores the previous screen and prints only the resume hint. Use `/export` before exit for an HTML copy, or resume the saved session later to review it in Atomic.

Ctrl+G uses `externalEditor`, then `$VISUAL`, then `$EDITOR`, then Notepad on Windows or `nano` elsewhere. This applies in main chat, embedded chat, and extension editor dialogs. Saving an empty edit clears the text; editor failure leaves the original unchanged. Atomic restores its interface after the editor exits.

### Telemetry and update checks

Version-adoption telemetry reports the running version on eligible interactive launches. It is separate from opt-in analytics.

`enableInstallTelemetry` controls this ping and Atomic's provider attribution headers; it does not control update checks. Atomic still fetches the npm registry latest package metadata at `https://registry.npmjs.org/@bastani/atomic/latest` unless update checks are disabled or offline mode is on.

Atomic sends one GET to `https://atomic-version-adoption.bastani-atomic.workers.dev/v1/version-adoption` with the running version as the `version` query parameter and the existing `atomic/<version> (<platform>; <runtime>; <arch>)` User-Agent. There is no request body, UUID, cookie, auth header, or user content.

The ping fires only in interactive mode, and only on:

- the first interactive launch with fresh settings (no recorded changelog version)
- the first interactive launch after an update whose version has changelog entries

It does not fire on every launch, on npm install, on a reinstall that kept settings, or in `-p` / RPC modes.

Atomic stores only UTC date, version, and an aggregate count, retained as aggregates. Cloudflare, the hosting provider, necessarily processes transient connection metadata (IP, TLS) to serve the request. That is not a promise of platform-wide zero logging.

Opt out by setting `enableInstallTelemetry` to `false` in `settings.json`, or by setting `ATOMIC_TELEMETRY=0` (`PI_TELEMETRY=0` remains a legacy alias). `ATOMIC_TELEMETRY=1`/`true`/`yes` forces the ping on even when the setting is false. `ATOMIC_TELEMETRY` wins when both it and `PI_TELEMETRY` are set.

Set `ATOMIC_SKIP_VERSION_CHECK=1` to disable the Atomic version update check. Use `--offline` or `ATOMIC_OFFLINE=1` to disable all startup network operations described here, including update checks, package update checks, install/update telemetry, and model catalog refreshes. Legacy `PI_*` aliases are also supported for app-specific environment variables.

On a genuine first run, Atomic previews available themes and asks whether to opt into analytics. The choice and locally generated identifier are stored as `enableAnalytics` and `trackingId`; analytics remains off unless explicitly enabled.

### Network proxy

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `httpProxy` | string | - | HTTP proxy URL applied as `HTTP_PROXY` and `HTTPS_PROXY`. Global setting only. |

```json
{ "httpProxy": "http://127.0.0.1:7890" }
```

### Warnings

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `warnings.anthropicExtraUsage` | boolean | `true` | Show a warning when Anthropic subscription auth may use paid extra usage |

```json
{
  "warnings": {
    "anthropicExtraUsage": false
  }
}
```

### Compaction

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `compaction.enabled` | boolean | `true` | Enable automatic verbatim line compaction |
| `compaction.reserveTokens` | number | `16384` | Free context tokens below which automatic compaction starts; does not limit summary output |
| `compaction.compression_ratio` | number | `0.5` | Fraction of compactable transcript **lines to keep** (`0 < value < 1`) |
| `compaction.preserve_recent` | number | `2` | Exact number of newest context-visible messages kept outside the compactable region; `0` keeps none |
| `compaction.query` | string | last user message | Optional relevance focus for selecting older lines to retain |
| `compaction.modelOverrides` | object | `{}` | Exact `"provider/modelId"` keys with optional `reserveTokens` and `preserve_recent` overrides |

```json
{
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "compression_ratio": 0.5,
    "preserve_recent": 2,
    "query": "optional focus"
  }
}
```

The model emits numbered line ranges only; Atomic reconstructs retained text mechanically. `preserve_recent` is enforced client-side and is not a provider parameter. Atomic does not widen this exact message count to a user-turn boundary or force a final logical turn to remain outside compaction.

Per-model budgets use exact, case-sensitive provider/model IDs (including any slashes in the model ID), not patterns or reasoning suffixes:

```json
{
  "compaction": {
    "reserveTokens": 16384,
    "preserve_recent": 2,
    "modelOverrides": {
      "anthropic/claude-sonnet-4-5": { "reserveTokens": 32768, "preserve_recent": 4 },
      "openai/gpt-5": { "preserve_recent": 0 }
    }
  }
}
```

Each field resolves independently: the active model's override, then the ordinary compaction setting, then the built-in default. Global and trusted-project settings merge overrides per model and per field. Model switches take effect on the next compaction check or manual call; borrowing a fallback planner does not change the selected budgets. Explicit manual `preserve_recent` parameters still take precedence.

Both fields must be non-negative safe integers, including ordinary settings. Invalid ordinary values are reported even if a model override exists; malformed matching entries and invalid override values are reported when that model is used. `enabled`, `compression_ratio`, and `query` remain ordinary settings, not per-model overrides. Unlike upstream pi's token-based recent-history budget, Atomic uses the exact-message `preserve_recent` setting, not `keepRecentTokens`, and retains its verbatim line compactor.

### Branch Summary

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `branchSummary.reserveTokens` | number | `16384` | Tokens reserved when selecting branch history; the provider sizes summary output |
| `branchSummary.skipPrompt` | boolean | `false` | Skip "Summarize branch?" prompt on `/tree` navigation (defaults to no summary) |

### Session Summary

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `sessionSummary.enabled` | boolean | `true` | Generate a one-line summary of each session for the `/resume` picker once the agent goes idle |

### Retry

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `retry.enabled` | boolean | `true` | Enable automatic agent-level retry on transient errors |
| `retry.maxRetries` | number | `3` | Maximum agent-level retry attempts |
| `retry.baseDelayMs` | number | `2000` | Base delay for agent-level exponential backoff (2s, 4s, 8s) |
| `retry.maxAgentDelayMs` | number | `60000` | Maximum agent-level backoff delay (60s); `0` retries immediately |
| `retry.provider.timeoutMs` | number | SDK default | Provider/SDK request timeout in milliseconds |
| `retry.provider.maxRetries` | number | `0` | Provider/SDK retry attempts. Leave unset/`0` to let Atomic's agent-level retry handle transient failures |
| `retry.provider.maxRetryDelayMs` | number | `60000` | Max server-requested delay before failing (60s); also caps how long an agent-level retry waits for a server retry hint |

Agent-level retries use exponential backoff capped by `retry.maxAgentDelayMs`, including the shared main-chat and workflow retry policy and summary calls. When a failed response carries a server retry hint (`Retry-After-Ms` or `Retry-After` header, or a Cloudflare 5xx `retry_after` body field), Atomic waits as long as the server asks instead, up to `retry.provider.maxRetryDelayMs`. OpenAI, OpenAI-compatible and ChatGPT (Codex) providers report these hints. `retry.maxRetries` still limits the number of retries, so with the defaults a hinted outage can take up to about 3 × 60s before the turn fails or switches to a configured `fallbackModels` entry. Cloudflare 520-524 responses and connection resets count as transient errors; non-retryable 4xx and quota errors still stop immediately. This is independent of provider retry limits. Legacy `retry.maxDelayMs` still migrates to `retry.provider.maxRetryDelayMs`, not the agent cap.

When a provider requests a retry delay longer than `retry.provider.maxRetryDelayMs` (e.g., Google's "quota will reset after 5h"), the request fails immediately with an informative error instead of waiting silently. Set to `0` to disable the cap.

`retry.provider.maxRetries` follows upstream Pi's behavior and defaults to `0` SDK/provider retries. Atomic still performs agent-level retries via `retry.maxRetries`; set `retry.provider.maxRetries` explicitly only when you want the underlying provider SDK to retry before Atomic observes the failure.

```json
{
  "retry": {
    "enabled": true,
    "maxRetries": 3,
    "baseDelayMs": 2000,
    "maxAgentDelayMs": 60000,
    "provider": {
      "timeoutMs": 3600000,
      "maxRetries": 0,
      "maxRetryDelayMs": 60000
    }
  }
}
```

### HTTP

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `httpIdleTimeoutMs` | number or string | `600000` | HTTP idle timeout as milliseconds, a duration such as `"30s"`, `"5m"`, or `"1h"`, or `"disabled"`. `0` also disables it. |

Atomic applies this timeout to the global HTTP dispatcher used by `fetch` and provider SDK HTTP clients. The default is 600,000 ms (10 minutes), which keeps slow long-context requests working while reclaiming stale idle connections. Atomic does not impose a separate fixed connect-phase timeout; connection failures surface through the provider and agent retry/error paths.

The same value is the default wall-clock limit for one [structured decision](/sdk/structured-decisions#cancellation-and-failures): a `structured_output` call, a `generateStructuredOutput()` call, or one automatic model-selection inference. The limit covers every repair attempt, retry, and fallback together, so a model that streams for a long time cannot hold a workflow stage past it. A disabled idle timeout leaves those calls effectively unbounded. Schema-backed workflow stages can set their own limit with [`schemaTimeoutMs`](/workflows/api-reference#schematimeoutms).

The `/settings` picker offers these presets:

| Label | Value |
|-------|-------|
| `30 sec` | `30000` |
| `1 min` | `60000` |
| `5 min` | `300000` |
| `10 min` | `600000` |
| `30 min` | `1800000` |
| `Disabled` | `"disabled"` (or `0`) |

```json
{
  "httpIdleTimeoutMs": 600000
}
```

### Message Delivery

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `steeringMode` | string | `"one-at-a-time"` | How steering messages are sent: `"all"` or `"one-at-a-time"` |
| `followUpMode` | string | `"one-at-a-time"` | How follow-up messages are sent: `"all"` or `"one-at-a-time"` |
| `transport` | string | `"auto"` | Preferred transport for providers that support multiple transports: `"sse"`, `"websocket"`, `"websocket-cached"`, or `"auto"` |
| `httpIdleTimeoutMs` | number or string | `600000` | HTTP idle timeout in milliseconds, a duration string, or `"disabled"`; also used by providers with explicit stream idle timeouts. |
| `websocketConnectTimeoutMs` | number or string | `15000` | WebSocket connect/open handshake timeout; accepts milliseconds, a duration string, or `"disabled"`/`0` to disable. |
| `streamDeadlineMs` | number or string | `300000` | Maximum idle gap between two provider stream events, enforced below the HTTP layer; accepts milliseconds, duration strings such as `30s`, `5m`, or `1h`, or `"disabled"`/`0` to disable. A stream that stalls without an error — for example a response body that fails to decompress — is cut at this deadline and retried or failed over instead of hanging the request. |

Older settings with a boolean `websockets` value are migrated to `transport`: `true` becomes `"websocket"` and `false` becomes `"sse"` when `transport` is not already set.

### Terminal & Images

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `terminal.showImages` | boolean | `true` | Show images in terminal (if supported) |
| `terminal.imageWidthCells` | number | `60` | Preferred inline image width in terminal cells |
| `terminal.clearOnShrink` | boolean | `false` | Clear empty rows when content shrinks (can cause flicker) |
| `terminal.showTerminalProgress` | boolean | `false` | Show OSC 9;4 progress indicators in the terminal tab bar |
| `images.autoResize` | boolean | `true` | Resize oversized images to a 2000x2000 maximum. Applies to `@file` attachments, `read`, and images returned by tools |
| `images.blockImages` | boolean | `false` | Block all images from being sent to LLM |
| `terminal.hyperlinks` | boolean or `"auto"` | `"auto"` | JSON-only hyperlink capability override. `true`/`false` overrides detection; `"auto"`, omitted, and invalid values preserve detection. Not shown in `/settings` |
| `terminal.images` | `"kitty"`, `"iterm2"`, `"auto"`, or `false` | `"auto"` | JSON-only inline-image protocol override. `false` disables terminal images; `"auto"`, omitted, and invalid values preserve detection. Not shown in `/settings` |
| `terminal.trueColor` | boolean or `"auto"` | `"auto"` | JSON-only truecolor capability override. `true`/`false` overrides detection; `"auto"`, omitted, and invalid values preserve detection. Not shown in `/settings` |

The installed pi-tui 0.85.0 renderer owns the matching environment overrides: `PI_HYPERLINKS=1|0|auto`, `PI_IMAGE_PROTOCOL=kitty|iterm2|none|auto`, and `PI_TRUE_COLOR=1|0|auto`. Explicit JSON booleans/protocols take precedence over those environment values. Use `"auto"` or omit a JSON value to leave environment and terminal detection in control.
When `images.autoResize` is enabled, Atomic normalizes images before sending them to the model. Tool-result images are normalized after `tool_result` extension handlers run, so images an extension inserts receive the same limit; if processing fails, Atomic keeps the original image. Set it to `false` to preserve source dimensions.

### Shell

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `shellPath` | string | - | Custom Bash path (e.g., for Cygwin on Windows); does not select the PowerShell used by native Windows `!`/`!!` or the interactive subshell |
| `shellCommandPrefix` | string | - | Prefix for shell commands, including `!`/`!!`; use PowerShell syntax for native Windows interactive commands and Bash syntax elsewhere (e.g., `"shopt -s expand_aliases"`) |
| `bashInterceptor.enabled` | boolean | `false` | When true, block shell commands that have dedicated tools and offer remaining `bash` tool calls to `user_bash` extension handlers before local execution. Also available in `/settings` as **Bash Interceptor**. |
| `search.contextBefore` | number | `1` | Number of context lines before each `search` match. |
| `search.contextAfter` | number | `3` | Number of context lines after each `search` match. |
| `npmCommand` | string[] | - | Command argv used for npm package lookup/install operations (e.g., `["mise", "exec", "node@20", "--", "npm"]`) |

```json
{
  "npmCommand": ["mise", "exec", "node@20", "--", "npm"]
}
```

`bashInterceptor.enabled` is intentionally `false` unless configured. Enable it from `/settings` or set it to `true` in JSON when you want Atomic to steer shell anti-patterns to `read`/`search`/`find`/`edit`/`write` and let extensions intercept model `bash` tool calls through the same `user_bash` event used by interactive `!` commands.

`npmCommand` is used for all npm package-manager operations, including installs, uninstalls, and dependency installs inside git packages. Use argv-style entries exactly as the process should be launched. When `npmCommand` is configured, git package dependency installs use plain `install` to avoid npm-specific flags in wrappers or alternate package managers.

Package-manager wrapper commands must support Atomic's lookup operations.

On Windows, JSON paths must use forward slashes or escaped backslashes:

```json
{
  "shellPath": "C:/Program Files/Git/bin/bash.exe"
}
```

```json
{
  "shellPath": "C:\\Program Files\\Git\\bin\\bash.exe"
}
```

### Tools

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `defaultTools` | string[] | - | Initial built-in tools. Plain names replace the defaults; `+name` and `-name` add or remove tools |
| `codemode.mode` | `"on"` or `"only"` | `"on"` | While codemode is active, `"on"` keeps direct tool declarations visible with script-call information; `"only"` hides ordinary direct callable declarations so the model uses scripts. Model-only tools remain directly available |
| `codemode.inlineBudget` | number | `3000` | Estimated token budget for inline script-tool declarations. Omitted tools remain discoverable with `searchTools()`. `0` lists namespaces without inline declarations |

`defaultTools` selects the built-in tools a session starts with. Extension and SDK custom tools retain their own activation behavior. Available built-ins include `read`, `bash`, `powershell`, `edit`, `write`, `find`, `search`, `ask_user_question`, `todo`, and `ls`:

```json
{
  "defaultTools": ["bash", "edit", "write"]
}
```

On Windows, select `powershell` instead of `bash`, or include both:

```json
{
  "defaultTools": ["read", "powershell", "edit", "write"]
}
```

An empty array starts with no coding tools while preserving extension/custom tools. `--tools` with plain names replaces this behavior with an allowlist including Intercom; modifier-only lists change the resolved selection instead. `--no-tools` disables every tool even with an allowlist or modifiers. `--no-builtin-tools` suppresses coding defaults when no allowlist is given. `--exclude-tools` filters the result, including Intercom.

A list containing only modifiers starts from Atomic's standard defaults. Modifiers are applied in order; adding an existing name or removing an absent one has no effect:

```json
{ "defaultTools": ["-bash", "+ls"] }
```

Plain names establish a replacement list before its modifiers apply. A project list of only modifiers layers over the global selection. A project list with plain names, or an empty list, replaces the global selection. For example, global `["read", "bash"]` plus project `["-bash", "+ls"]` resolves to `["read", "ls"]`.

`/reload` enables tools newly added to `defaultTools`. It does not disable removed tools or re-enable unchanged tools you turned off during the session. `--tools` with plain names, `--no-tools`, and `--no-builtin-tools` override the setting on reload too; excluded tools remain excluded. Modifier-only `--tools` lists apply on top of the reloaded setting, so a tool removed with `-name` stays removed.

`codemode` and `tool_search` are built-in extension tools registered inactive. Add `"+codemode"` or `"+tool_search"` to `defaultTools` to activate them alongside ordinary defaults. See [codemode](/tools#codemode) and [tool search](/tools#tool_search) for usage and safety boundaries.

### Sessions

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `sessions.storage` | object | Local SQLite | Session-only storage selection: `{ "path": "..." }`, `{ "dir": "..." }`, `{ "memory": true }`, or `{ "adapter": "...", "options": {}, "secrets": {}, "prefix": "..." }`. |
| `storage` | object | Local SQLite | Shared selection for sessions and workflow runs. Accepts the same forms except `dir`. |

```json
{ "sessions": { "storage": { "path": "sessions.sqlite" } } }
```

Without configuration, sessions and workflow runs share `~/.atomic/workflows/journal.sqlite`. Session tables use `session_` names; workflow tables use `wf_` names. If `ATOMIC_CODING_AGENT_DIR` changes the agent directory, this default is `workflows/journal.sqlite` under its parent. JSONL is opt-in through `dir`, `--session-dir`, or `ATOMIC_CODING_AGENT_SESSION_DIR`. The `sessionDir` setting has been removed; use `sessions.storage.dir` instead.

Session precedence is SDK `sessionStore`, `--no-session`, `--session-dir` or `--session-store` (mutually exclusive CLI selections), `--storage` or `--storage-file`, `ATOMIC_SESSIONS_STORAGE` or non-empty `ATOMIC_CODING_AGENT_SESSION_DIR`, `ATOMIC_STORAGE`, `sessions.storage`, shared `storage`, then the default SQLite file. Empty environment values are ignored. Project selections replace global selections as whole objects, including options, secrets and prefix; fields are never merged. A present empty `sessions.storage` selects the default session database rather than inheriting `storage`. Relative settings paths resolve against Atomic home, normally `~/.atomic`, and so do relative paths in the JSON selections of `--storage`, `ATOMIC_STORAGE`, and `ATOMIC_SESSIONS_STORAGE`. `--session-dir`, `--session-store`, and `ATOMIC_CODING_AGENT_SESSION_DIR` resolve against the working directory.

To select storage for one process without editing settings, pass the same JSON selection in `ATOMIC_STORAGE`, `ATOMIC_SESSIONS_STORAGE`, `ATOMIC_WORKFLOWS_JOURNAL`, `--storage`, or `--storage-file`. See [Selecting storage per process](/storage#selecting-storage-per-process).

See [Choosing a store](/sessions#choosing-a-store) for CLI selection, prefix rules, and conflicts.

Only the selected setting is validated; invalid lower-precedence settings do not block an explicit override. Every set `ATOMIC_STORAGE`, `ATOMIC_SESSIONS_STORAGE`, and `ATOMIC_WORKFLOWS_JOURNAL` is validated even when outranked. Memory must be selected explicitly and is lost on exit. Invalid selected configuration raises `StorageConfigError`, whose `source`, `field`, and `reason` identify the problem. If a selected store cannot open, Atomic raises a typed storage error rather than falling back to memory. See [Sessions](/sessions#session-storage) and [Storage errors](/storage#storage-errors).

### Models

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `enabledModels` | string[] | - | Model patterns for CTRL+P cycling (same format as `--models` CLI flag). In interactive TTY startup, these patterns are resolved again after deferred extension/resource loading so extension-provided providers can match without blocking first paint. |

```json
{
  "enabledModels": ["claude-*", "gpt-4o", "gemini-2*"],
  "fallbackModels": ["anthropic/claude-opus-4-8:xhigh", "github-copilot/gpt-5.5:high"]
}
```

`fallbackModels` is independent of `enabledModels`: it is consulted only after a retryable main-chat provider/model failure or a terminal compaction planner outcome.

### Markdown

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `markdown.codeBlockIndent` | string | `"  "` | Indentation for code blocks |
| `markdown.mermaid` | string | `"streaming"` | Mermaid rendering mode: `"off"`, `"final"`, or `"streaming"` |
| `markdown.latex` | boolean | `true` | Render LaTeX expressions as terminal-friendly Unicode math |

Mermaid code blocks render as themed Unicode diagrams in interactive transcripts when they fit the available width. `"off"` keeps the Markdown fence, `"final"` renders only finalized responses, and `"streaming"` also renders partial assistant responses. Invalid or too-wide diagrams remain as code, and rendering is display-only: stored messages and model context keep the original Markdown. LaTeX rendering is also display-only and converts supported expressions to terminal-friendly Unicode math; set `markdown.latex` to `false` to keep the source form.

LaTeX rendering supports whitespace and matrix layouts.

### Resources

These settings define where to load extensions, skills, prompts, themes, and workflows from.

Paths in `~/.atomic/agent/settings.json` resolve relative to `~/.atomic/agent`. Paths in `.atomic/settings.json` resolve relative to `.atomic`. Absolute paths and `~` are supported.

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `packages` | array | `[]` | npm/git packages to load resources from |
| `extensions` | string[] | `[]` | Local extension file paths or directories |
| `skills` | string[] | `[]` | Local skill file paths or directories |
| `prompts` | string[] | `[]` | Local prompt template paths or directories |
| `themes` | string[] | `[]` | Local theme file paths or directories |
| `workflows` | string[] or object | `[]` | Local workflow paths, or `{ "paths": [...] }`; see [Workflow storage](#workflow-storage) |
| `enableSkillCommands` | boolean | `true` | Register skills as `/skill:name` commands |

Arrays support glob patterns and exclusions. Use `!pattern` to exclude. Use `+path` to force-include an exact path and `-path` to force-exclude an exact path.

#### Workflow storage

Workflow runs use a SQLite journal, by default the local file `~/.atomic/workflows/journal.sqlite`. Set `workflows.journal.path` in `settings.json` to choose another file:

```json
{
  "workflows": {
    "paths": ["./workflows"],
    "journal": { "path": "workflows/project.sqlite" }
  }
}
```

#### Local worker pools

Local worker pools are disabled unless `workflows.localWorkers` is set. With the option omitted, Atomic creates no worker tables, processes, or polling loops. A worker definition must be importable from its module path and export name. Only first-level `ctx.workflow(...)` child subtrees run in the pool; a root closure stays in the main process, and nested children stay on their assigned worker.

```json
{
  "workflows": {
    "localWorkers": {
      "count": 4,
      "definitions": [
        { "path": "./workflows/research.ts", "exportName": "research" }
      ]
    },
    "admission": {
      "limits": { "session": 4, "process": 8 },
      "userLimits": { "session": 8, "process": 16 },
      "userDatabase": "/Users/alex/.atomic/workflows/journal.sqlite",
      "host": { "maxLoadPerCpu": 2, "minFreeMemoryBytes": 2147483648 }
    }
  }
}
```

`count` is a positive integer. Paths in the settings object resolve against the invocation working directory. Worker settings and entry-module digests are saved with the root; resume refuses changed settings or definitions. The entry-module digest does not include imported dependencies.

`startupTimeoutMs` is how long, in milliseconds, each worker process may take to become ready. It defaults to `30000`. The pool runs children once any worker is ready and fails only when no worker starts. This value is not saved with the root, so changing it does not block a resume. Each worker's standard error is written to `worker-logs/<root run ID>/<worker ID>.log` in the workflow journal's directory, and worker failure messages name that file. See [Worker startup and failures](/workflows/operations#worker-startup-and-failures).

`leaseMs` is how long, in milliseconds, a worker that is still running but has stopped responding keeps its child before the child is replayed on another worker. It defaults to `30000` and must be at least `2000`. A worker that exits is replaced immediately, and a worker that is still responding keeps its child even when the root itself is briefly too busy to process its heartbeats. Like `startupTimeoutMs`, this value is not saved with the root.

`limits` caps agent sessions and managed tool processes for one root. Session permits cover creation through disposal, including fallback and delegated sessions. Process permits last until confirmed cleanup; yielding an observation wait does not free one. Processes outside Atomic's managed tools are not counted. `host` load and memory thresholds gate launches but do not impose hard OS limits.

`userLimits` counts across runs only when all participating runs use the same canonical local SQLite journal. Set `userDatabase` to that exact path, and pass the admission options to participating non-pooled SDK runs. This coordinates processes for one local user; it is not a tenant isolation boundary.

Workers require native process and boot identity and are currently supported only on Linux and macOS. Windows and hosts without those identities refuse activation, even if no process cap is configured. Remote workers are not supported. SDK callers cannot combine the pool with process-bound adapters, UI, persistence, or similar overrides. An unregistered or non-importable child fails; Atomic does not execute it locally as a fallback. Recovery may repeat external effects that occurred after a checkpoint, so use stable idempotency keys for operations that must not be repeated.

Relative settings paths resolve against the Atomic home directory, normally `~/.atomic`, not the project directory. Precedence is SDK `RunOpts.journal` (or `createAgentSession({ journal })` for a session's `workflow` tool), `--storage` or `--storage-file`, `ATOMIC_WORKFLOWS_JOURNAL` or non-empty `ATOMIC_WORKFLOW_JOURNAL_PATH`, `ATOMIC_STORAGE`, `workflows.journal`, shared top-level `storage`, then the default journal file. An empty environment variable is ignored. SDK sessions read `workflows.journal` from the settings they were given, so `SettingsManager.inMemory(...)` selects a journal per session. A present empty journal block selects the journal default rather than inheriting shared storage. See [Selecting storage per process](/storage#selecting-storage-per-process).

To keep workflow records only in memory, set `"journal": { "memory": true }`. Do not combine `memory: true` with a non-empty `path`. Memory must be selected explicitly and cannot recover runs after the process exits; an environment path still takes precedence over this setting.

Project `workflows.journal` and `storage` each replace their global selection as a whole, including options, secrets, and prefix. For example, a project can select `{ "memory": true }` over a global path. Invalid selected settings raise `StorageConfigError` instead of trying a lower-precedence selection. Combining `memory: true` with a non-empty `path` is an error.

To use your own database driver, install an adapter module, for example as an [Atomic package](/storage#adapters-from-atomic-packages), and select it by package name or module path:

```json
{
  "storage": {
    "adapter": "@example/atomic-sqlite",
    "options": { "url": "libsql://database.example" },
    "secrets": { "authToken": { "env": "DATABASE_TOKEN" } },
    "prefix": "project_"
  }
}
```

The shared `storage` setting supplies defaults for both sessions and the journal. Use `sessions.storage` or `workflows.journal` for a domain-only override. A shared empty selection uses `~/.atomic/storage.sqlite`. Atomic bundles no remote driver. Adapter modules execute code, so review them before trusting project settings. Secret references accept `{ "env": "VARIABLE" }` or `{ "file": "token.txt" }`; relative secret files resolve against Atomic home, and their contents are passed as written except for one trailing line ending (`\n` or `\r\n`), which is removed. See [Storage adapters](/storage#selecting-an-adapter).

Changing the journal selects a different run history. Preserve the original file to inspect or resume its runs. The default local file needs no separate server; a remote database requires an adapter, and every host that shares runs must select the same database and prefix. See [Sharing storage across hosts](/storage#sharing-storage-across-hosts). If the selected journal cannot be opened or written, the action fails with a typed storage error rather than selecting memory. Restore access to the store and inspect the retained run before retrying. See [Durable workflows](/workflows/operations#durable-workflows-and-cross-session-resume).

#### packages

String form loads all resources from a package:

```json
{
  "packages": ["pi-skills", "@org/my-extension"]
}
```

Object form filters which resources to load:

```json
{
  "packages": [
    {
      "source": "pi-skills",
      "skills": ["brave-search", "transcribe"],
      "extensions": [],
      "workflows": []
    }
  ]
}
```

Set `autoload` to `false` on an object-form package entry to start that package with no discovered resources and apply only its explicit `extensions`, `skills`, `prompts`, `themes`, or `workflows` patterns. This is useful when a package contains resources you do not want to load by default.

See [Atomic packages](/packages) for package management details.

## Example

Moved to [Configure Atomic](/guides/configuration#example).

## Project Overrides

Moved to [Configure Atomic](/guides/configuration#project-overrides).
