# Settings

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

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

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

## 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
  }
}
```

### UI & Display

| Setting                  | Type    | Default     | Description                                                                                     |
| ------------------------ | ------- | ----------- | ----------------------------------------------------------------------------------------------- |
| `theme`                  | string  | `"dark"`    | Theme name (`"dark"`, `"light"`, or custom)                                                     |
| `quietStartup`           | boolean | `false`     | Hide startup header                                                                             |
| `collapseChangelog`      | boolean | `false`     | Show condensed changelog after updates                                                          |
| `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)                                                       |
| `autocompleteMaxVisible` | number  | `5`         | Max visible items in autocomplete dropdown (3-20)                                               |
| `showHardwareCursor`     | boolean | `false`     | Show terminal cursor                                                                            |

### 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 retry on transient errors      |
| `retry.maxRetries`  | number  | `3`     | Maximum retry attempts                          |
| `retry.baseDelayMs` | number  | `2000`  | Base delay for exponential backoff (2s, 4s, 8s) |
| `retry.maxDelayMs`  | number  | `60000` | Max server-requested delay before failing (60s) |

When a provider requests a retry delay longer than `maxDelayMs` (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.

```json
{
  "retry": {
    "enabled": true,
    "maxRetries": 3,
    "baseDelayMs": 2000,
    "maxDelayMs": 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 | `"sse"`           | Preferred transport for providers that support multiple transports: `"sse"`, `"websocket"`, or `"auto"` |

### Terminal & Images

| Setting                  | Type    | Default | Description                                               |
| ------------------------ | ------- | ------- | --------------------------------------------------------- |
| `terminal.showImages`    | boolean | `true`  | Show images in terminal (if supported)                    |
| `terminal.clearOnShrink` | boolean | `false` | Clear empty rows when content shrinks (can cause flicker) |
| `images.autoResize`      | boolean | `true`  | Resize images to 2000x2000 max                            |
| `images.blockImages`     | boolean | `false` | Block all images from being sent to LLM                   |

### 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"`) |

### 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 |

### Resources

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

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

#### 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.

## Example

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

## Project Overrides

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

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

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

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