# Settings

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

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

Edit directly or use `/settings` for common options.

## Project Trust

On interactive startup, Selesai asks before trusting a project folder that contains project-local settings, resources, or project `.agents/skills` and has no saved decision for the folder or a parent folder in `~/.selesai/agent/trust.json`. Trusting a project allows Selesai to load `.selesai/settings.json` and `.selesai` resources, install missing project packages, and execute project extensions.

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 those project resources, 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 `~/.selesai/agent/settings.json`, or change it with `/settings`.

`selesai config` and package commands use the same project trust flow, except `selesai update` never prompts. 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 `~/.selesai/agent/trust.json` only; the current session is not reloaded, so restart Selesai for changes to take effect.

## All Settings

### Model & Thinking

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `defaultProvider` | string | - | Default provider (e.g., `"anthropic"`, `"openai"`) |
| `defaultModel` | string | - | Default model ID |
| `defaultThinkingLevel` | string | - | `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"` |
| `hideThinkingBlock` | boolean | `false` | Hide thinking blocks in output |
| `thinkingBudgets` | object | - | Custom token budgets per thinking level |

#### thinkingBudgets

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

### Sai advisory routing

The bundled `sai-deci` extension uses the Sai decisions model (TokenIn `cloudflare/clef` by
default) for bounded routing. Memory, ask, and tool-search routing are on by default;
recommendations and subagent routing remain opt-in. All routes share one Sai provider/model pair:

- `memory` — for each eligible request, Sai decides whether a memory lookup would help, choosing
  `none` or one read-only local `memory_search` target. No explicit memory cue is required. Sai
  never sees memory contents, and no memory is written. An accepted target runs at most one bounded
  local lookup (at most five results, bounded before injection), and the memory request has a
  750ms ceiling; set `saiAdvisory.routes.memory.enabled` to `false` to opt out. An image-only
  request is classified with bounded neutral text describing the attachments, and that text is
  never used as a memory search query, so an image-only request simply chooses `none` or finds no
  local results.
- `recommendations` — one discovered skill or prompt workflow that fits, or a proportionate
  verification level. Nothing is loaded, started, or executed: the recommendation is context for the
  agent, and required project/workflow gates are unchanged.
- `toolSearch` — ranks `tool_search` and codemode `searchTools()` results with one yes/no question
  per candidate tool, batched. It ranks only; it does not select, activate, or load a tool. With no
  Token-In credential, with the route off, or when a request fails, ranking falls back to
  deterministic local BM25.
- `ask` — the agent-callable `ask_sai` tool (on by default). The agent decides when to call it: it
  passes its own prose, up to eight file `paths`, one `command`, and up to eight typed
  choice/score/noul questions, and gets answers with confidences back — never the file contents or
  command output, so a verdict about code costs a few lines of context instead of the files. It can
  also attach local images through `imagePaths`. Paths must be inside the working directory,
  secret-named files (`.env`, `*.pem`, `id_rsa*`, `auth.json`, …) are refused, and the command runs
  through the bash tool's local shell. Whatever the agent passes is sent to Sai. Without Token-In
  credentials the tool stays registered and returns an actionable error without reading files,
  reading images, or running commands; `/tokenin add` supplies credentials without a loadout reset.

  `imagePaths` accepts at most four explicit local PNG/JPEG/WebP files whose aggregate base64 data
  fits a 2 MiB encoded cap. Each path is resolved and validated inside the canonical working
  directory, must be a regular nonempty file that does not match a secret name, and is read in
  bounded form only after the credential and the classifier's image input are confirmed. An invalid
  or unsupported image set refuses the whole call — nothing is clipped, dropped, or downgraded to a
  text-only request — before any optional command or classification runs. Image data never counts
  toward the route's text budget.

  The same route also offers `sai_find`, a bounded text/code finder: ripgrep gathers candidate files
  (those matching `pattern`, or every file under `path` filtered by `glob`); on large trees Sai first
  judges directories and descends only into relevant ones, then judges files, then the declarations
  (source units) inside relevant files. The agent gets a ranked file list with reading leads plus the
  accepted units verbatim with original line numbers (at most 12 Sai requests and 16 KiB of source
  per call). It respects `.gitignore`, stays inside the working directory, skips secret-named files,
  retries a transport failure once, and still returns ripgrep-ranked candidates with keyword-window
  source when Sai is unavailable. Results also show the discovery scope and sampled
  directory/file/source-unit verdicts (noul scores and thresholds) and skip reasons, with a separate
  4 KiB diagnostic budget. Counts cover every recorded outcome; at most three examples per category
  are retained. Ignored, hidden, and nonmatching files are outside discovery, not rejected by Sai.
  These diagnostics contain paths and verdicts, never rejected source; persisted details keep only
  counts. Weak or empty results should lead to broader discovery or direct grep/read, not a claim
  that the behavior is absent.

  Both tools are optional helpers, not mandatory steps before search, planning, or edits. For
  `ask_sai`, supply relevant evidence, ask one bounded judgment per question, batch independent
  questions, describe concrete situations in criteria, and include an `other`/`insufficient_evidence`
  choice when needed. Confidence is not proof; inspect missing or clipped evidence. Keep counting
  and exit-code checks in code. Prefer grep/read for known symbols, exact strings, and source explanations.
- `subagent` — sets up a single-child `subagent` call from the parent agent (off by default). Sai only
  fills what the parent left open, and can only narrow: (1) when `agent` is omitted or generic
  (`genericAgents`, default `["delegate"]`), it picks an agent by function from enabled native agents
  inside the capability ceiling; (2) it may drop tools from that agent's declared `tools` for this run
  (never `read` or supervision tools, and never adds one); (3) when `tiers` is set and the parent
  passed no `model`, it picks `simple`, `complex`, or `reasoning` and launches that tier's model. Sai
  sees only the task and agent descriptions. Any abstention launches exactly what was asked; an
  agentless task that Sai cannot route is rejected with a request to name an agent.

The settings area is `saiAdvisory`; the former `jevAdvisory` key is not read and has no alias.

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `saiAdvisory.provider` | string | `"tokenin"` | Provider serving the Sai decisions deployment |
| `saiAdvisory.model` | string | `"cloudflare/clef"` | Decisions model every route calls |
| `saiAdvisory.baseUrl` | string | inherited | Base URL override; defaults to any registered model of `provider` |
| `saiAdvisory.routes.memory.enabled` | boolean | `true` | Enable the memory-lookup route |
| `saiAdvisory.routes.recommendations.enabled` | boolean | `false` | Enable skill/workflow and verification recommendations |
| `saiAdvisory.routes.ask.enabled` | boolean | `true` | Offer the agent the `ask_sai` and `sai_find` tools; set `false` to turn both off |
| `saiAdvisory.routes.toolSearch.enabled` | boolean | `true` | Rank `tool_search` and codemode `searchTools()` results with Sai |
| `saiAdvisory.routes.toolSearch.model` | string | unset | Rank with this TokenIn decisions model instead of the shared Sai model |
| `saiAdvisory.routes.subagent.enabled` | boolean | `false` | Let Sai choose the agent, tools, and model tier of a subagent call |
| `saiAdvisory.routes.subagent.tiers` | object | unset | `{ "simple"?, "complex"?, "reasoning"? }` → `provider/id` model; tier routing needs at least two |
| `saiAdvisory.routes.subagent.genericAgents` | string[] | `["delegate"]` | Agents Sai may replace with a specialist |
| `<route>.timeoutMs` | number | `8000` | Route request timeout (ms); memory is capped at 750ms; `ask` defaults to `15000`, `toolSearch` to `6000`, `subagent` to `5000` |
| `<route>.minConfidence` | number | `0.6` | Below this Sai confidence the route abstains |
| `<route>.contextTurns` | number | `4` | Prior user turns sent as recommendation context; memory sends only the current bounded prompt |
| `<route>.contextChars` | number | `4000` | Character budget for recommendation context |
| `<route>.payloadBytes` | number | `8192` | Hard cap on the serialized decision request; `ask` and `toolSearch` default to `32768`, `subagent` to `16384` |

`ask` and `toolSearch` ignore `minConfidence`, `contextTurns`, and `contextChars`: `ask` returns every
confidence to the agent, and its context is whatever the agent put in the request. The serialized decision request is
bounded to 64 KiB of bytes; that payload budget is separate from the decisions model's 65,536-token
context window.

Only idle, top-level, interactive or RPC prompts that carry text or images are routed: queued
steering/follow-up input, slash commands, extension-injected turns, and input with neither text nor
images are skipped, and each turn is routed at most once. Only the current turn's final prompt text
and attachments are judged; earlier history images are never forwarded. The memory route sends no
history to Sai; on an accepted target it runs one local, read-only lookup (at most five results,
bounded before injection). A missing Token-In subscription, a timeout, a malformed or low-confidence
answer, an unknown candidate, unavailable/empty local memory, or an oversized payload is an ordinary
abstention that leaves the existing memory policy and verification requirements in force.

```json
{
  "saiAdvisory": {
    "provider": "tokenin",
    "model": "cloudflare/clef",
    "routes": {
      "memory": { "enabled": true },
      "recommendations": { "enabled": true }
    }
  }
}
```

### Tools and skills

The bundled defaults use `"defaultTools": ["+codemode"]`: keep the normal tool selection and
add codemode. Plain names replace the selection; `+name`/`-name` adjust it. The same applies to `--tools` for one invocation: `selesai --tools +tool_search` adjusts the resolved defaults, while plain names replace them. On `/reload`, a tool removed with `-name` stays removed. Frequently used
owned tools remain direct; specialised tools use upstream deferred exposure. Discover deferred
tools through codemode `searchTools()` or `tool_search` when enabled. Loaded tools remain active
across settlement and resume; there is no gateway reset or legacy capability tie-breaking policy.

The bundled `skills-index` extension replaces the eager skill listing with compact guidance.
Use `skill_show` without a name to list eligible skills, `query` to filter their metadata, or an
exact `name` to load instructions before applying a skill. It never activates tools or chooses
skills automatically. If `skill_show` is excluded, the ordinary skill index is retained.
The retired gateway environment variable and settings have no effect in the parent runtime.

MCP OAuth uses Selesai-branded dynamic registration or a pre-registered `oauth.clientId`.
`oauth.clientRegistration: "cimd"` is rejected: Selesai has no hosted client metadata document
and must not identify itself through upstream Pi's document. OAuth browser page artwork comes
from the upstream dependency and is unchanged.

### UI & Display

The logo and Tools/Skills panels always appear on interactive startup and dismiss on your first message. Legacy `quietStartup` settings are ignored.

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `theme` | string | `"dark"` | Theme name (`"dark"`, `"light"`, or custom) |
| `defaultProjectTrust` | string | `"ask"` | Fallback project trust behavior: `"ask"`, `"always"`, or `"never"`. Global setting only |
| `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
| `enableInstallTelemetry` | boolean | `true` | Send an anonymous install/update version ping after first install or changelog-detected updates. This does not control update checks |
| `enableAnalytics` | boolean | `false` | Opt-in analytics data sharing. Currently only asked for during the experimental first-time setup (`PI_EXPERIMENTAL=1`) |
| `trackingId` | string | - | Analytics tracking identifier, generated when `enableAnalytics` is turned on |
| `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` | `0 \| 1` | `1` | Horizontal padding for the interactive transcript: messages, tool output, `!` command output, and summary blocks. Any value other than `0` reads as `1`. Configurable in `/settings` as "Output padding", which saves it to the global settings file and applies it immediately. Applies to the built-in transcript components; it does not change the HTML export, which uses fixed padding |
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
| `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
| `tuiMode` | string | `"fullscreen"` | TUI layout: `"fullscreen"` (default) or `"regular"`. `fullscreen` uses Pi's native alternate-screen viewport with a fixed dock for the input editor, status, and widgets; set `"regular"` to opt out |
| `fullscreenScrollbar` | string | `"auto"` | Fullscreen transcript scrollbar: `"auto"`, `"always"`, or `"hidden"`; configurable in `/settings`. No effect in regular TUI mode |
| `fullscreenCopyOnSelect` | boolean | `true` | Automatically copy selected text in fullscreen mode; disable to copy selections with Ctrl+X. Configurable in `/settings`. No effect in regular TUI mode |

### Telemetry and update checks

`enableInstallTelemetry` only controls the anonymous install/update ping to `https://pi.dev/api/report-install`. Opting out of telemetry does not disable update checks; Pi can still fetch `https://pi.dev/api/latest-version` to look for the latest version.

Set `PI_SKIP_VERSION_CHECK=1` to disable the Pi version update check. Use `--offline` or `PI_OFFLINE=1` to disable all startup network operations described here, including update checks, package update checks, and install/update telemetry.

### Network

| 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 auto-compaction |
| `compaction.reserveTokens` | number | `16384` | Tokens reserved for LLM response |
| `compaction.keepRecentTokens` | number | `20000` | Recent tokens to keep (not summarized) |

```json
{
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  }
}
```

### Branch Summary

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `branchSummary.reserveTokens` | number | `16384` | Tokens reserved for branch summarization |
| `branchSummary.skipPrompt` | boolean | `false` | Skip "Summarize branch?" prompt on `/tree` navigation (defaults to no summary) |

### Retry

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `retry.enabled` | boolean | `true` | Enable automatic agent-level retry on transient errors |
| `retry.maxRetries` | number | `10` | Maximum agent-level retry attempts |
| `retry.baseDelayMs` | number | `2000` | Base delay for agent-level exponential backoff (2s, 4s, 8s) |
| `retry.provider.timeoutMs` | number | SDK default | Provider/SDK request timeout in milliseconds |
| `retry.provider.maxRetries` | number | `0` | Provider/SDK retry attempts |
| `retry.provider.maxRetryDelayMs` | number | `60000` | Max server-requested delay before failing (60s) |

When a provider requests a retry delay longer than `retry.provider.maxRetryDelayMs`, the request fails immediately with an informative error instead of waiting silently. Set it to `0` to disable the limit.

Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explicitly needed. Setting it above `0` can make SDK/provider retries handle out-of-usage-limit errors before Pi sees them, which may block the agent until the provider quota resets in some circumstances.

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

### 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 | `300000` | HTTP header/body idle timeout in milliseconds, also used by providers with explicit stream idle timeouts. Set to `0` to disable. |
| `websocketConnectTimeoutMs` | number | `15000` | WebSocket connect/open handshake timeout in milliseconds for providers that support WebSocket transports. Set to `0` to disable. |

### 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.images` | string | `"auto"` | Terminal image protocol: `"kitty"`, `"iterm2"`, `"auto"`, or `false` to disable inline images |
| `terminal.trueColor` | boolean/string | `"auto"` | Pin true-color support (`true`/`false`) or keep `"auto"` detection |
| `terminal.hyperlinks` | boolean/string | `"auto"` | Pin hyperlink support (`true`/`false`) or keep `"auto"` detection |
| `images.autoResize` | boolean | `true` | Resize images to 2000x2000 max |
| `images.blockImages` | boolean | `false` | Block all images from being sent to LLM |
| `images.imageCaptionModel` | string | unset | Vision model (`provider/model`) to describe images when the active model cannot accept images; the caption text is used in place of the image (e.g. `tokenin/gemma-4`, `tokenin/kimi-k3`) |
| `images.imageCaptionContextTokens` | number | `16384` | Max token budget (approx) for the recent-conversation context sent to the caption model. Messages are kept whole (cut at message boundaries only); the user's current prompt is always included |

### Shell

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `shellPath` | string | - | Custom shell path (e.g., for Cygwin on Windows) |
| `shellCommandPrefix` | string | - | Prefix for every bash command (e.g., `"shopt -s expand_aliases"`) |
| `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"]
}
```

`npmCommand` is used for all npm package-manager operations, including installs, uninstalls, and dependency installs inside git packages. User-scoped npm packages install under `~/.selesai/agent/npm/`; project-scoped npm packages install under `.selesai/npm/`. 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.

### Sessions

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `sessionDir` | string | - | Directory where session files are stored. Accepts absolute or relative paths, plus `~`. |

```json
{ "sessionDir": ".selesai/sessions" }
```

When multiple sources specify a session directory, precedence is `--session-dir`, `SELESAI_CODING_AGENT_SESSION_DIR`, then `sessionDir` in settings.json.

### Model Cycling

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `enabledModels` | string[] | - | Model patterns for Ctrl+P cycling (same format as `--models` CLI flag) |

```json
{
  "enabledModels": ["claude-*", "gpt-4o", "gemini-2*"]
}
```

### Markdown

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `markdown.codeBlockIndent` | string | `"  "` | Indentation for code blocks |
| `markdown.mermaid` | string | `"streaming"` | Render Mermaid fences as Unicode diagrams: `"off"`, `"final"`, or `"streaming"`. Also configurable in `/settings`. Diagrams that cannot render or fit retain their source fence. |

### Resources

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

Paths in `~/.selesai/agent/settings.json` resolve relative to `~/.selesai/agent`. Paths in `.selesai/settings.json` resolve relative to `.selesai`. 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 |

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.

#### 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": []
    }
  ]
}
```

See [packages.md](packages.md) for package management details.

### extensionHost

When selesai reads extensions from both `~/.selesai/agent/extensions/` and `~/.pi/agent/extensions/`, name collisions are resolved per extension. Default winner: selesai. Override per name:

```json
{
  "extensionHost": {
    "pi-subagents": "pi",
    "copy-turn.ts": "selesai"
  }
}
```

Keys are top-level entry names (dir name for packaged extensions, file name for loose `.ts`). Values are `"selesai"` or `"pi"`. See [Shared Host Extensions](shared-host-extensions.md) for the full flow.

## Bundled extension settings

The `pi-hermes-memory` extension reads its options from the `hermesMemory` object in global `~/.selesai/agent/settings.json`:

```json
{
  "hermesMemory": {
    "llmThinkingOverride": "off",
    "consolidationTimeoutMs": 300000
  }
}
```

These settings load at startup and take precedence over the legacy `hermes-memory-config.json` fallback. `llmModelOverride` is optional and uses `provider/model` format (for example, `tokenin/deepseek-v4.1-flash` if your account has access); leave it unset to use the active model. See the [memory extension configuration reference](../src/extensions/pi-hermes-memory/README.md#configuration) for all options.

## Example

```json
{
  "defaultProvider": "anthropic",
  "defaultModel": "claude-sonnet-4-20250514",
  "defaultThinkingLevel": "medium",
  "theme": "dark",
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  },
  "retry": {
    "enabled": true,
    "maxRetries": 10
  },
  "enabledModels": ["claude-*", "gpt-4o"],
  "warnings": {
    "anthropicExtraUsage": true
  },
  "packages": ["pi-skills"]
}
```

## Project Overrides

Project settings (`.selesai/settings.json`) override global settings. Nested objects are merged:

```json
// ~/.selesai/agent/settings.json (global)
{
  "theme": "dark",
  "compaction": { "enabled": true, "reserveTokens": 16384 }
}

// .selesai/settings.json (project)
{
  "compaction": { "reserveTokens": 8192 }
}

// Result
{
  "theme": "dark",
  "compaction": { "enabled": true, "reserveTokens": 8192 }
}
```

## Factory Reset

Run `/settings-factory-reset` inside a session to restore the global settings file (`~/.selesai/agent/settings.json`) to the bundled factory defaults. The command warns before replacing the file, saves a backup as `settings.json.bak` next to it, and leaves credentials (`auth.json`), sessions, extensions, skills, and themes untouched. Settings take effect immediately after the reset (equivalent to `/reload`).
