Pify
Reference

Configuration reference

Current Pi settings files, merge rules, trust boundary, settings families, and runtime overrides.

This page was reviewed against Pi v1.0.0, commit a13d35a742c6ef8462812a28fbe1d8c8b7431c32.

Pi reads JSON settings at startup and when resources reload. This reference describes @earendil-works/pi-coding-agent 1.0.0 on Node.js 22.19 or newer.

Settings files and precedence

File locations

PathRole
~/.pi/agent/settings.jsonGlobal settings for every project
<cwd>/.pi/settings.jsonSettings for the current project, when the project is trusted
~/.pi/agent/trust.jsonSaved project-trust decisions; this is not a settings layer
<cwd>/.pi/SYSTEM.md, <cwd>/.pi/APPEND_SYSTEM.mdTrusted project prompt sources, not settings files
AGENTS.md, CLAUDE.mdContext files found from the working-directory ancestry, not settings files

Edit the JSON files directly, or use /settings for the common interactive choices. pi config manages which package resources are enabled; it is not a general settings editor. See Customize the system prompt for the separate prompt-file composition rules.

Merge and CLI precedence

Project settings recursively override global settings. Nested objects merge by key; arrays and scalar values replace the global value. CLI arguments then override only the behavior they name for that process. Examples include --model, --thinking, --models, the --tools family, --use-theme, --tui-mode, --session-dir, and the project-trust flags.

For model selection, --provider requires --model; use --model provider/model-id when a single argument is more convenient. Supplying --provider alone is a CLI error.

Precedence is setting-specific

Do not treat every CLI flag as a field in settings.json. For example, session storage resolves as --session-dir → PI_CODING_AGENT_SESSION_DIR → sessionDir → the default. Explicit resource flags add runtime paths, while --no-extensions, --no-skills, --no-prompt-templates, and --no-themes disable discovery for their resource family.

Current settings shape

The public root exports SettingsManager and selected setting types, not a full schema validator. The current JSON families are:

FamilyKeys
ModeldefaultProvider, defaultModel, defaultThinkingLevel, modelThinkingLevels, thinkingBudgets, enabledModels, cacheWarming, showCacheMissNotices
InteractionsteeringMode, followUpMode, defaultTools, doubleEscapeAction, treeFilterMode
Displaytheme, tuiMode, fullscreenExitOutput, fullscreenScrollbar, fullscreenCopyOnSelect, terminal, images, markdown
Lifecyclecompaction, branchSummary, retry, sessionDir
Networktransport, httpProxy, httpIdleTimeoutMs, websocketConnectTimeoutMs
Resourcespackages, extensions, skills, prompts, themes, enableSkillCommands

Use public getters when a host needs the effective value. This runnable inspection intentionally ignores project settings. Direct SDK use does not consult the CLI trust store; the host must resolve trust and pass projectTrusted itself.

inspect-settings.ts
import { getAgentDir, SettingsManager } from "@earendil-works/pi-coding-agent";

const settings = SettingsManager.create(process.cwd(), getAgentDir(), {
  projectTrusted: false,
});

console.log({
  model: [settings.getDefaultProvider(), settings.getDefaultModel()],
  thinking: settings.getDefaultThinkingLevel(),
  tools: settings.getDefaultTools(),
  compaction: settings.getCompactionSettings(),
  retry: settings.getRetrySettings(),
  diagnostics: settings.drainErrors().map(({ scope, error }) => ({
    scope,
    message: error.message,
  })),
});

Models, thinking, and tools

Model and thinking

defaultProvider and defaultModel identify the default model. --model takes precedence for a run; a resumed session can restore its recorded model when no explicit CLI model is supplied. defaultThinkingLevel accepts off, minimal, low, medium, high, xhigh, or max; it can be saved with Ctrl+S in /thinking or edited manually. This semantic global startup default is distinct from provider request fields.

The model resolver supplies a fallback when neither an explicit selection nor resumed state supplies a model:

ProviderResolution scopeResolver default
xainew sessiongrok-4.7

This is the default for new or otherwise default-resolved xAI sessions in 1.0.0. It does not replace a model selected with --model, chosen interactively, configured as defaultModel, or restored from a resumed session.

modelThinkingLevels stores per-model startup thinking levels keyed by provider/modelId; configure it from /settings → Default thinking level per model or edit the JSON manually. A matching per-model value selects that model's startup level, while defaultThinkingLevel remains the global fallback. thinkingBudgets separately supplies token budgets for supported providers or compatible models.

Do not confuse those semantic settings with a direct Google API option. GoogleApiThinkingLevel, exported from @earendil-works/pi-ai, is the API-facing union "THINKING_LEVEL_UNSPECIFIED" | "MINIMAL" | "LOW" | "MEDIUM" | "HIGH" used by GoogleOptions.thinking.level and GoogleVertexOptions.thinking.level. ResolvedGoogleThinkingLevel is the normalized adapter union "minimal" | "low" | "medium" | "high" used after Pi resolves model capability mappings. Neither type expands the allowed values of defaultThinkingLevel; they describe provider-code boundaries.

google-provider-levels.ts
import type {
  GoogleApiThinkingLevel,
  ResolvedGoogleThinkingLevel,
} from "@earendil-works/pi-ai";

const directRequestLevel: GoogleApiThinkingLevel = "HIGH";
const resolvedAdapterLevel: ResolvedGoogleThinkingLevel = "high";
void [directRequestLevel, resolvedAdapterLevel];

hideThinkingBlock hides thinking in the transcript. showCacheMissNotices shows transcript notices for significant prompt-cache misses, compaction or branch-summary usage, and provider recovery diagnostics such as dropped Anthropic thinking blocks. A model still decides which thinking levels and budgets it supports.

enabledModels supplies patterns for Ctrl+P model cycling; --models overrides that scope for one run. Provider endpoints and credentials do not belong in a providers settings object. Put supported endpoints in ~/.pi/agent/models.json or a Provider configuration, and keep credentials in the supported authentication store or environment. See Add a model provider.

cacheWarming is global-only because refreshes incur provider usage. Its default, "streaming", keeps eligible caches warm while an Agent run is active; "idle" may continue after settlement, and "off" disables warming. Eligibility comes from the selected model's promptCache lifetime metadata for the active retention tier. Pi evaluates expected savings before each refresh, but warming still costs money and cannot guarantee a provider cache hit. /session exposes the next decision, while showCacheMissNotices controls transcript notices for significant misses, successful warming, compaction usage, and provider recovery.

Radius model discovery uses three layers: the bundled offline catalog is available immediately, cached gateway metadata overlays it when present, and a live gateway refresh overlays both when network access succeeds. A custom Radius gateway configured in models.json uses its own catalog instead of inheriting the public radius.pi.dev catalog.

PriorityRadius catalog layer
1bundled offline catalog
2cached gateway catalog
3live gateway catalog
thinking-settings.json
{
  "defaultProvider": "anthropic",
  "defaultModel": "claude-sonnet-4-6",
  "defaultThinkingLevel": "medium",
  "modelThinkingLevels": {
    "anthropic/claude-sonnet-4-6": "high"
  },
  "thinkingBudgets": {
    "minimal": 1024,
    "low": 4096,
    "medium": 10240,
    "high": 32768
  },
  "hideThinkingBlock": false,
  "showCacheMissNotices": true,
  "cacheWarming": "streaming"
}

Tool selection

defaultTools selects Tools at startup. When omitted, exactly read, bash, edit, and write are active defaults. The other ordinary built-ins are powershell, grep, find, and ls; powershell is the optional native Windows shell Tool and is not added automatically. codemode and tool_search are inactive Tools registered by built-in extensions and may also be named here. An empty array removes the built-in defaults but leaves extension and SDK custom Tools available. Plain names replace the inherited selection; a list containing only +name and -name entries modifies it in order. For example, ["-bash", "+powershell", "+grep"] replaces Bash with PowerShell and adds grep without restating every inherited Tool. Project settings apply this same rule on top of user settings. --tools is a strict allowlist across built-in, extension, and custom Tools; it and the other CLI Tool switches override defaultTools for the invocation and do not accept the additive/removal notation. On /reload, defaultTools activates newly added names; it does not disable removed names or re-enable an unchanged Tool that you turned off manually.

tool-settings.json
{
  "defaultTools": ["read", "bash", "edit", "write"]
}

Select PowerShell explicitly on Windows, either instead of Bash or alongside it:

tool-settings-windows.json
{
  "defaultTools": ["read", "powershell", "edit", "write"]
}

Selecting a Tool does not change the host shell that launched Pi. It chooses which LLM-callable Tool names are active: bash sends commands to Pi's Bash-compatible backend, while powershell sends commands to the native PowerShell backend. The CLI/SDK tools allowlist follows the same distinction.

The built-in read, bash, powershell, edit, and write definitions use strict-prefer JSON Schema constrained sampling by default. A provider that cannot enforce the schema falls back to ordinary Tool calling. An Extension replacing a built-in definition can opt out explicitly with constrainedSampling: false.

Project trust

Fallback and saved decisions

Project trust controls loading .pi/settings.json, project .pi resources, project packages, and executable extensions. defaultProjectTrust is global-only: ask is the default, while always or never supplies the non-interactive fallback. Interactive startup asks when trust-requiring project resources exist and no saved decision applies. /trust writes the decision to ~/.pi/agent/trust.json; restart Pi to apply it to the current project runtime.

The CLI resolves that store before it creates the trusted runtime. SettingsManager.create() used directly by an SDK host defaults projectTrusted to true and never reads trust.json; security-sensitive hosts should pass an explicit decision.

One-run overrides

--approve (-a) trusts project-local files for one run. --no-approve (-na) ignores them for one run. Print, JSON, and RPC modes cannot display a trust prompt, so they use an applicable saved decision, the global fallback, or one of these flags.

Project trust is a project-resource boundary, not per-tool approval. Current settings have no yolo, permissions, or requiresPermission switch. Enforce tool approval or denial in the embedding host or an Extension tool_call policy.

Compaction and retries

Compaction and branch summaries

SettingDefaultEffect
compaction.enabledtrueEnables automatic compaction
compaction.reserveTokens16384Reserves context space for the next model response
compaction.keepRecentTokens20000Keeps this many recent tokens outside the summary
compaction.modelOverridesnoneOverrides either token budget for an exact provider/modelId
branchSummary.reserveTokens16384Reserves tokens for branch summarization
branchSummary.skipPromptfalseWhen true, skips the branch-summary question and defaults to no summary

The former fractional compaction.threshold and turn-count preserveRecentTurns settings do not exist. Current compaction is driven by token reserve and recent-token budgets.

Inside compaction.modelOverrides, reserveTokens and keepRecentTokens fall back independently to the ordinary compaction value, then the built-in default. Keys are exact and case-sensitive, including slashes inside a model ID. Only omitted fields fall back; values must be non-negative safe integers, and an invalid matching override is an error.

Retry and message delivery

retry.enabled, maxRetries (3), and baseDelayMs (2000) control agent-level retries. retry.provider.timeoutMs, maxRetries, and maxRetryDelayMs (60000) control the provider layer. Provider retries default to zero in the Coding Agent integration; increasing both layers can multiply requests and delay the visible failure.

steeringMode and followUpMode accept one-at-a-time (default) or all. transport accepts auto, sse, websocket, or websocket-cached. httpIdleTimeoutMs defaults to 300000; 0 disables the HTTP idle timeout. websocketConnectTimeoutMs controls the opening handshake and also accepts 0 to disable it.

Sessions, terminal, and shell

Session storage

sessionDir changes persistent session storage. Relative paths resolve from the process working directory, and ~ expands to the home directory. Without an override, Pi stores one append-only JSONL file per session below ~/.pi/agent/sessions/<encoded-cwd>/.

There are no built-in sessions.retention or sessions.redactSecrets settings. The application operating Pi owns file permissions, backups, retention, and deletion; protect session JSONL because it can contain prompts, model output, and tool results. See Persist sessions.

/bug [description] is a runtime command, not a settings.json family. It redacts secret values from collected metadata, then offers optional transcript inclusion, a model-written summary, Radius upload, or local ZIP export. Offline mode blocks upload but preserves local ZIP export. Crash metadata is kept in ~/.pi/agent/crashes.json for the next report; protect that file and any exported ZIP as diagnostic data.

Terminal, images, shell, and npm

terminal.showImages (true) controls inline display, imageWidthCells (60) sets preferred width, clearOnShrink (false) clears vacated rows, and showTerminalProgress (false) emits supported terminal progress indicators. images.blockImages (false) blocks all images from reaching providers. Hiding terminal images does not block upload.

images.autoResize is the global on/off gate. model.inputLimits.images.resize is an optional per-field override. Pi merges its supplied fields over runtime fallbacks, so an absent profile uses every fallback and a partial profile keeps the fallback for each omitted field:

Control or eventScopeEffect
images.autoResizeglobal gateenable or disable resizing
model.inputLimits.images.resizeoptional per-field overridenew images before history
model switchstored imagedo not rewrite
FieldRuntime fallbackUnit or boundary
maxWidth2000pixels
maxHeight2000pixels
maxBytes4.5MiB base64 payload
jpegQuality80integer

The effective limits can differ per model. The active profile is used for file attachments, images returned by read, and Tool-result images. Each new image is normalized once as it enters history; selecting another model later does not rewrite the stored content. Provider-side transformations and hard limits remain outside this Pi profile, so validate them separately for each route.

Pi auto-detects terminal capabilities, with these exact environment and setting values:

CapabilityEnvironment valueJSON setting
OSC 8 hyperlinksPI_HYPERLINKS=1|0|autoterminal.hyperlinks: true|false|"auto"
Inline imagesPI_IMAGE_PROTOCOL=kitty|iterm2|none|autoterminal.images: "kitty"|"iterm2"|false|"auto"
TruecolorPI_TRUE_COLOR=1|0|autoterminal.trueColor: true|false|"auto"

For PI_HYPERLINKS, 1 force-enables OSC 8 hyperlinks, 0 force-disables them, and auto falls back to automatic detection. An explicit boolean terminal.hyperlinks setting overrides both PI_HYPERLINKS and automatic detection; "auto" supplies no setting override.

For PI_IMAGE_PROTOCOL, kitty selects the Kitty protocol and iterm2 selects the iTerm2 protocol; none force-disables inline images, while auto falls back to automatic detection. An explicit protocol or false in the terminal.images setting overrides both PI_IMAGE_PROTOCOL and automatic detection; "auto" supplies no setting override.

For PI_TRUE_COLOR, 1 force-enables truecolor, 0 force-disables it, and auto falls back to automatic detection. An explicit boolean terminal.trueColor setting overrides both PI_TRUE_COLOR and automatic detection; "auto" supplies no setting override.

Forcing a capability unsupported anywhere along the terminal, proxy, or multiplexer path may emit unsupported escape sequences and corrupt rendering. Detection recognizes the Zed integrated terminal as supporting truecolor and hyperlinks but no inline image protocol, so auto uses the image text fallback there.

shellPath selects the executable for the bash Tool, shellCommandPrefix prefixes every bash command, and npmCommand is an argv array for package operations. These Bash settings do not activate, configure, or replace the powershell Tool; PowerShell selection belongs in defaultTools, --tools, or the SDK tools option. Windows JSON paths need forward slashes or escaped backslashes.

terminal-and-shell-settings.json
{
  "terminal": {
    "showImages": true,
    "imageWidthCells": 60,
    "clearOnShrink": false,
    "showTerminalProgress": false,
    "hyperlinks": "auto",
    "images": "auto",
    "trueColor": "auto"
  },
  "images": {
    "autoResize": true,
    "blockImages": false
  },
  "shellPath": "C:/Program Files/Git/bin/bash.exe",
  "shellCommandPrefix": "shopt -s expand_aliases",
  "npmCommand": ["mise", "exec", "node@22", "--", "npm"],
  "sessionDir": ".pi/sessions"
}

Interface and output

--mode accepts text, json, or rpc. Pi 1.0.0 treats both a missing value and an unknown value as CLI errors rather than falling back to interactive mode:

InvocationResultProcess outcome
--mode <missing>errorexit status=1
--mode invaliderrorexit status=1

This validation happens before the session starts, which makes a misspelled mode fail visibly in scripts and CI.

UI and display

theme, externalEditor, quietStartup, and collapseChangelog control startup and presentation. quietStartup: "header" keeps the header with version and key hints while hiding the model scope line and loaded-resource listing; true hides both header and details. externalEditor overrides VISUAL, then EDITOR; use code --wait when Pi must wait for VS Code. doubleEscapeAction is tree, fork, or none, and treeFilterMode chooses the default /tree filter.

The system theme is the default and derives its palette from terminal colors. A custom theme accepts exactly six color forms: 3-digit RGB hex such as #0af, 6-digit RGB hex such as #00aaff, OKLCH, OKHSL, an ANSI 256 index from 0 through 255, a variable reference, or the empty string "" for the terminal default. The two RGB spellings are one hexadecimal form; invalid or circular variable references make the theme invalid.

editorPaddingX is clamped from 0 to 3, outputPad is 0 or 1, and autocompleteMaxVisible is clamped from 3 to 20. showHardwareCursor helps IME input. tuiMode accepts regular or fullscreen and defaults to fullscreen; choose tuiMode: "regular" in settings or --tui-mode regular for one run to opt out. The related flat keys are fullscreenExitOutput (transcript or resume-hint) and fullscreenScrollbar (auto, always, or hidden). The old nested tui.* and fullscreen.* shapes are not current. Escape-key timing is an environment control documented in Environment variables.

fullscreenCopyOnSelect defaults to true, which copies a fullscreen drag selection automatically. When it is disabled, the selection remains active and highlighted; Ctrl+X attempts to copy the eligible active selection and returns from the copy action whether the clipboard write succeeds or fails. It falls back to the last assistant message only when no eligible active selection exists. This setting affects fullscreen text selection, while /tree keeps its own selected-message copy behavior.

fullscreenWheelScrollLines accepts "auto" or a number from 1 through 100. Automatic mode moves one line per event in local macOS terminals, which already accelerate wheel/trackpad input; elsewhere and over SSH it accelerates fast wheel input up to six lines per event. Alt+wheel moves five times the resolved distance.

The clickable Jump to latest message control appears only while the fullscreen transcript is scrolled above the latest message; it occupies the bottom row and shows the tui.altScreen.bottom shortcut. For fullscreenScrollbar: "auto", the scrollbar becomes visible while scrolling or when the pointer enters its rightmost-column track. Clicking that track jumps through the transcript; always reserves and displays the column continuously, while hidden removes it.

Markdown and warnings

markdown.codeBlockIndent defaults to two spaces. markdown.mermaid accepts off, final, or streaming (default). warnings.anthropicExtraUsage defaults to true and controls the subscription extra-usage warning.

Network, telemetry, and updates

httpProxy applies HTTP_PROXY and HTTPS_PROXY to Pi-managed HTTP clients and is read from global settings only. Do not embed proxy credentials in a project file. Stream timeout and transport settings are listed under retry and message delivery.

enableInstallTelemetry defaults to true for the anonymous install/update version ping. enableAnalytics is opt-in and defaults to false; Pi creates trackingId on opt-in. These settings do not disable update checks. collapseChangelog changes how the changelog is shown, while lastChangelogVersion is Pi-managed state and should not be edited by hand. Use PI_SKIP_VERSION_CHECK or offline mode for network policy; see Environment variables for the exact controls.

Resources, packages, and globs

Resource lists and package filters

extensions, skills, prompts, and themes contain local paths or directories. In global settings, relative paths resolve from ~/.pi/agent; in project settings they resolve from .pi. These arrays support globs, !pattern exclusions, +path force-includes, and -path force-excludes. enableSkillCommands controls registration as /skill:name and defaults to true.

The exact built-in extension identifiers are builtin:mcp, builtin:llama.cpp, builtin:codemode, and builtin:tool-search. They load by default; use -builtin:mcp (or the corresponding exact name) to disable one, and use +builtin:<name> or -builtin:<name> in project settings to override the user-level resource selection. --no-extensions disables them with other extensions, while -e builtin:<name> loads one explicitly.

MCP server entries live in mcp.json, separate from settings.json. For an HTTP server whose authorization-server discovery is wrong or absent, the Coding Agent configuration override is oauth.authServerMetadataUrl. The configured metadata document is trusted and must use HTTPS except on loopback hosts.

Use packages for npm or Git package sources; do not put package names in extensions. A string package entry autoloads all resources. An object can set autoload: false and filter extensions, skills, prompts, or themes. Project resources and missing project-package installation remain subject to project trust.

resource-settings.json
{
  "packages": [
    "@org/pi-resources",
    {
      "source": "git:github.com/org/team-pi-resources",
      "autoload": false,
      "skills": ["review", "release"],
      "extensions": []
    }
  ],
  "extensions": ["./extensions/*.ts", "!./extensions/legacy.ts"],
  "skills": ["+./skills/release/SKILL.md", "!./skills/experimental/**"],
  "prompts": ["./prompts/*.md"],
  "themes": ["./themes/*.json"],
  "enableSkillCommands": true
}

Complete example and project override

This global file covers the common families without provider credentials:

complete-settings.json
{
  "defaultProvider": "anthropic",
  "defaultModel": "claude-sonnet-4-6",
  "defaultThinkingLevel": "medium",
  "thinkingBudgets": {
    "minimal": 1024,
    "low": 4096,
    "medium": 10240,
    "high": 32768
  },
  "hideThinkingBlock": false,
  "showCacheMissNotices": true,
  "cacheWarming": "streaming",
  "enabledModels": ["anthropic/*", "openai/gpt-5.2*"],
  "defaultTools": ["read", "bash", "edit", "write"],
  "theme": "dark",
  "quietStartup": true,
  "tuiMode": "regular",
  "fullscreenCopyOnSelect": true,
  "markdown": {
    "codeBlockIndent": "  ",
    "mermaid": "final"
  },
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000,
    "modelOverrides": {
      "some-provider/large-context-model": {
        "reserveTokens": 400000
      }
    }
  },
  "branchSummary": {
    "reserveTokens": 16384,
    "skipPrompt": false
  },
  "retry": {
    "enabled": true,
    "maxRetries": 3,
    "baseDelayMs": 2000,
    "provider": {
      "maxRetries": 0,
      "maxRetryDelayMs": 60000
    }
  },
  "steeringMode": "one-at-a-time",
  "followUpMode": "one-at-a-time",
  "transport": "auto",
  "httpIdleTimeoutMs": 300000,
  "websocketConnectTimeoutMs": 15000,
  "sessionDir": ".pi/sessions",
  "terminal": {
    "showImages": true,
    "hyperlinks": "auto",
    "images": "auto",
    "trueColor": "auto"
  },
  "images": {
    "autoResize": true,
    "blockImages": false
  },
  "warnings": {
    "anthropicExtraUsage": true
  },
  "packages": ["@org/pi-resources"]
}

For a merge example, start with this global file:

settings-global.json
{
  "theme": "dark",
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  },
  "defaultTools": ["read", "bash", "edit", "write"]
}

Then add the trusted project override:

.pi/settings.json
{
  "compaction": {
    "reserveTokens": 8192
  },
  "defaultTools": ["read"]
}

The result keeps theme, compaction.enabled, and keepRecentTokens, changes reserveTokens, and replaces the whole defaultTools array.

Validate and continue

Pi parses JSON and reports load failures as settings warnings. It does not expose the retired pi --dry-run command, a public full-schema validator, or a logPrompts setting. On initial load, an invalid scope contributes no settings; on reload, SettingsManager keeps that scope's last valid values and exposes the error through drainErrors(). Unknown fields are not proof of validity, so inspect effective values through public getters and exercise the affected runtime path. The system-prompt guide shows the current prompt-inspection APIs.

After editing in an interactive session, use /reload; an SDK host can await settingsManager.reload(). Then continue with API reference or Environment variables.

On this page