← Pi Agents

Settings and Where Configuration Comes From

Pi merges the agent-directory and project .pi settings files: scalars override, resource lists combine, and environment variables and CLI flags are documented per setting rather than as higher layers.

You edit settings.json, run /reload, and the setting does not take effect. Or it takes effect in a way you did not predict. Both come from the same cause: you were reasoning about one file when Pi merges several.

configuration.md gives the shape in one sentence. Pi supports user-level and project configuration. User-level lives in the agent directory, defaulting to ~/.pi/agent. Project configuration lives in .pi under the working directory and loads after project trust is granted — with one exception, sessionDir, which Pi reads before resolving trust so it can locate sessions.

The agent directory

Everything user-level sits here. PI_CODING_AGENT_DIR moves it, or the SDK’s agentDir option.

Path Responsibility
<agent-dir>/settings.json Settings, resource paths, and Pi package declarations
<agent-dir>/keybindings.json Custom terminal UI and application keybindings
<agent-dir>/mcp.json MCP servers available in every project
<agent-dir>/models.json Compatible endpoints, models, and model overrides
<agent-dir>/auth.json Saved API keys and OAuth credentials
<agent-dir>/AGENTS.override.md, AGENTS.md, AGENTS.MD, CLAUDE.md, CLAUDE.MD User instructions applied across working directories
<agent-dir>/SYSTEM.md Replaces Pi’s default system prompt
<agent-dir>/APPEND_SYSTEM.md Adds instructions to Pi’s system prompt
<agent-dir>/extensions/, skills/, prompts/, themes/ User resources

Note that the instruction filenames sit next to SYSTEM.md in the same directory but do different jobs. Instructions and the system prompt are separate surfaces, and chapter 18 treats them separately.

Settings merge, resource lists do not

settings.md opens with the rule that surprises people: project settings override agent-directory settings, and resource lists are combined.

Scalar settings follow ordinary override. Lists of resources — extensions, skills, prompts, themes, packages — are unioned from both levels, and that is where the filter syntax comes from:

Entry Meaning
a bare path Load it
+path Include one exact path
-path Exclude one exact path
!pattern Exclude glob matches

The rule in one picture, including the list that behaves differently:

    flowchart TD
  K["A setting you want to change"] --> Q{"Which key is it?"}
  Q -->|"a scalar"| S["Project value wins"]
  Q -->|"a resource list"| L["Both files load, unioned"]
  L --> L2["Dropping an entry removes nothing"]
  L2 --> L3["Removal has to be explicit"]
  Q -->|"defaultTools"| T["Plain names replace, + and - edit"]
  

Wrong: “the project file lists the resources it wants, and that is what loads.” Correct: resource lists from both files are unioned, so the project file selects nothing by omission. To stop something loading you name it with -path or !pattern.

defaultTools is the list that does not follow the union rule. settings.md is explicit about it: a list of only +name and -name entries changes the inherited selection, while a project list containing a plain name replaces it. Within one list, plain names form the selection and +name and -name then apply in order.

Paths resolve differently per scope: user resource paths resolve from the agent directory, project resource paths from the project .pi directory. Absolute paths and ~ work in both.

Three settings that only exist at one level

settings.md marks these in bold:

  • defaultProjectTrust — agent-directory settings only.
  • httpProxy — agent-directory settings only.
  • cacheWarming — global setting only.

A project file that tries to set defaultProjectTrust is not layering a preference; the setting is ignored there. That matters when you expect a repository’s .pi to decide its own trust posture.

What the environment changes

environment-variables.md groups what Pi reads from the environment. Only one of these changes where configuration is found:

Variable Description
PI_CODING_AGENT_DIR Override the config directory; default is ~/.pi/agent
PI_CODING_AGENT_SESSION_DIR Override session storage; overridden by --session-dir
PI_PACKAGE_DIR Override the package directory, useful for Nix/Guix store paths
PI_OFFLINE Disable automatic network activity, including model catalog refreshes
PI_SKIP_VERSION_CHECK Disable the pi.dev latest-version request
PI_TELEMETRY Override install/update telemetry with 1/true/yes or 0/false/no
PI_CACHE_RETENTION Set to long for extended provider prompt caching where supported
PI_SHARE_VIEWER_URL Override the base URL used by /share
PI_RADIUS_GATEWAY Override the Radius gateway origin used by /bug uploads
VISUAL, EDITOR External editor fallback when externalEditor is unset

--offline is the command-line equivalent of PI_OFFLINE=1. Either way, environment variables apply for one process, which makes them the right tool for a temporary override and the wrong one for anything you want to keep:

PI_OFFLINE=1 pi --print "Summarize this repository"
PI_CODING_AGENT_DIR=/srv/pi pi --session-dir /srv/sessions

Put it in settings.json instead if it should persist.

Three files, and the overrides that reach past them

The file order itself is one sentence long, and its floor is the built-in default. .pi/settings.json joins it only after project trust is granted, which is chapter 8.

Environment variables and command-line options are not two more layers stacked on top. They are documented per setting, and they do not always win:

Override Documented against
--session-dir PI_CODING_AGENT_SESSION_DIR and the sessionDir setting
--tools, --no-tools, --no-builtin-tools defaultTools, including on reload
--system-prompt Replaces the default system prompt
--append-system-prompt Appends to it, and is repeatable
--verbose quietStartup

Where a capability has both a setting and an environment variable, the winner is stated for that capability, not globally: terminal-setup.md says settings take precedence over environment variables when overriding detected terminal features.

The difference from a stack is that there is nothing general to memorise about them: a handful of named settings, each with its own documented override. sessionDir is the one that bites, because Pi reads it before trust is granted — which is the next chapter.

A workable starting file

{
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  },
  "defaultTools": ["+grep", "+find", "+ls"],
  "shellPath": "C:\\Program Files\\Git\\bin\\bash.exe",
  "shellCommandPrefix": "export CI=1",
  "retry": {
    "enabled": true,
    "maxRetries": 3
  },
  "extensions": ["+./extensions", "!./extensions/experimental.ts"],
  "defaultProjectTrust": "ask"
}

Two entries deserve a note. retry.provider.maxRetries defaults to 0 on purpose: settings.md says keep it there unless provider-level retries are required, because provider retries can delay Pi from handling quota and usage-limit errors itself. And defaultProjectTrust belongs in the agent directory, not in a project file.

Reload is not symmetric

Run /reload after manually changing settings, keybindings, instructions, or resources. What reload does not do matches what chapter 6 described: it enables newly added tools but does not disable removed ones. If a change seems inert, restart before you start debugging it.

Read settings instead of guessing

/settings opens the settings UI for common preferences. Beyond that, settings.md is the reference and pi config is the resource inspector: packages.md describes it as listing discovered resources and Pi’s built-in extensions, with --local to start from project overrides.

Everything so far has assumed the project settings file is one of the files Pi reads. It is not, until a question is answered. Chapter 8 is about that question, and about the resources a folder supplies that no amount of declining will switch off.