Configuration¶
Global configuration¶
Global defaults are shared across workspaces in ~/.config/pcode/preferences.json
(or $XDG_CONFIG_HOME/pcode/preferences.json). Inspect and edit them without
opening a terminal UI or connecting a model:
pcode config # List effective startup defaults as JSON
pcode config diff # List only settings that differ from defaults
pcode config path # Print the resolved config path
pcode config get theme
pcode config set theme light
pcode config set autocompact on
pcode config set effort high
pcode config set model openai-codex:gpt-5.6-luna
pcode config unset model # Remove saved model; return to offline preview
pcode config unset theme # Restore automatic theme detection
pcode config reset # Remove every saved default at once
Inside pcode, /config opens a full-screen, searchable settings editor.
Its layout stays fixed as you browse, filter, and edit; only resizing the terminal
changes the pane sizes. Type to search setting names and descriptions, use ↑/↓
to select a setting, and press Enter to edit it. Choose from the available options or enter a value; Enter saves and
keeps the browser open. Escape cancels the current edit, or closes the browser
when you are not editing. Invalid values stay in the editor with an explanation.
Tab switches focus to the details so you can scroll long descriptions and values;
Shift+Tab returns to the search or value editor.
Each setting shows its built-in default, saved effective value, and whether that value comes from the user or project configuration. These are saved defaults, not a snapshot of the running conversation. The detail area identifies layout settings that apply immediately and warns when a project override takes precedence over a user edit.
The scope control shows the shortcut for switching between user and project settings. Project scope is available when a workspace is selected and omits user-only settings. Toggle Overrides only to see just the values saved in the selected scope, including explicit overrides equal to the built-in default. Removing an override clears that scope's saved value, letting the underlying user value or built-in default take over. The scope, filter, and reset shortcuts are shown in the browser and follow your configured key prefix; Keys opens the complete keyboard help.
Explicit commands remain available with tab completion: /config list prints
JSON, and /config set theme light, /config get autocompact,
/config unset effort, and /config diff work without opening the browser.
Most config edits affect the next launch, not the running conversation. To change
an active setting and save its default immediately, use /theme, /effort,
/model, or /autocompact instead. The layout settings attach_tasks,
tasks_max_height, tasks_min_rows, tasks_min_columns, task_style, tool_glyphs, tool_max_lines and tool_linger_seconds apply immediately through /config. CLI overrides such as
--theme and --model do not rewrite global defaults, and resumed sessions retain
their own model.
Model provider filter¶
Limit the /model selector to specific providers:
pcode config set model_providers openai-codex,anthropic
pcode config unset model_providers # Restore automatic detection of all active providers
Or run /config set model_providers openai-codex,anthropic inside pcode.
This setting is read each time the selector opens, without a restart. In
preferences.json it is a string: "model_providers": "openai-codex,anthropic".
Names match exactly: openai-codex does not include openai, openai-chat, or
openai-responses. Unknown provider names are rejected.
An unset or empty value shows all automatically detected active providers.
A nonempty list filters those providers; it does not configure credentials or
force inactive providers to appear. The current provider is also hidden if it
is excluded. This only filters the selector, not explicit /model PROVIDER:MODEL
commands, CLI model overrides, or resumed sessions.
Keybindings¶
Use /bind and /unbind to customize main-prompt action keys.
Mappings are user-only and stored in bindings.json, separate from
preferences.json: $PCODE_CONFIG_DIR/bindings.json when set, otherwise
$XDG_CONFIG_HOME/pcode/bindings.json, defaulting to
~/.config/pcode/bindings.json. There is no project binding file or project
configuration override. Writes are locked and atomic.
Binding edits apply immediately in the current terminal. Other running terminals
pick them up on their next start or a binding management edit, not automatically.
The editor and prefix preferences (editing_mode, vi_escape_sequence,
vi_key_prefix, and key_prefix) still require restarting the prompt; see
Keybindings for their setup and how global shortcuts and the
optional vi leader share mappings.
Independent instances¶
PCODE_CONFIG_DIR points pcode at a different config directory without moving
the rest of your XDG_CONFIG_HOME. Everything pcode keeps there follows it:
preferences.json, codex-credentials.json and mcp-credentials.json (so
each instance has its own /login openai-codex and MCP sign-ins), mcp.json,
bindings.json, extensions/, and worktree-setup.
Sessions and other state still live under XDG_STATE_HOME; set
PCODE_SESSION_DIR too if those should be separate.
PCODE_CONFIG_DIR=~/.config/pcode-work pcode # separate login and settings
PCODE_CODEX_CREDENTIALS_FILE and PCODE_MCP_CONFIG
still win over the directory for their single file.
Per-repository overrides¶
A workspace's .pcode/preferences.json is layered over the user file at launch,
so a setting can hold for one repository and be committed for everyone who
clones it. config list and config get show the merged result;
config project edits the repository file (from -C DIR or the current
directory):
pcode config project set worktree on # this repo only; writes .pcode/preferences.json
pcode config project list # the raw overlay
pcode config project unset worktree
pcode config project reset # Drop the whole overlay
A cloned repository must not be able to run code or pick credentials on your
behalf, so project_extensions, trusted_projects, extension_dirs,
extensions_off, and extensions_on are user-only: the project file cannot
set them, and pcode says so at launch if it tries. model and subagent_models
can be set, but only choose among the providers you are signed in to. When the
repository sets subagent_models, /subagents shows that list, says it comes
from the repository, and refuses to change it; edit it with
pcode config project set or unset instead. The overlay is read from the
launch workspace before any worktree is created, so worktree on in a
repository's file is what starts each of its sessions in a worktree.
Trusting a repository's own code¶
A repository can ship code that runs at launch with your permissions:
.pcode/extensions/*.py (see /extensions, which lists every extension and its
state, and turns one on or off) and .pcode/worktree-setup. Neither
runs until you trust that repository. The first interactive launch inside one
that ships either asks:
pcode: /path/to/repo ships code that runs at launch with your permissions: .pcode/worktree-setup
Trust this repository? [y/N]
y records the repository's primary checkout in trusted_projects (so all of
its worktrees are covered) and never asks again; n skips the code for this
launch and asks next time. --print has nobody to ask, so it skips and says so.
Revoke with pcode config unset trusted_projects (or edit the :-separated
list). pcode config set project_extensions on trusts every repository, which
is only sensible on a machine where you wrote all of them.
Settings reference¶
Every key works with pcode config set KEY VALUE and /config set KEY VALUE.
Models and providers¶
| Key | Built-in default | Values |
|---|---|---|
model |
null (offline preview) |
A model name, normally provider:model |
effort |
default |
low, medium, high, xhigh, default (OpenAI/Codex, Anthropic, Claude Code); fallback for models /effort has not set |
model_providers |
empty | ,-separated providers /model lists; empty shows every provider you're signed in to or have a key for |
claude_idle_processes |
1 |
Whole number of finished claude: CLI processes each session keeps warm (about 120 MB each beyond the first); 0 stops each when its turn ends. None are kept under memory pressure |
claude_idle_minutes |
10 |
Positive integer, minutes a finished claude: CLI process is kept warm |
retry_attempts |
3 |
Whole number, automatic retries after a dropped connection or streamed overload; 0 disables. See retries |
Editor and keys¶
| Key | Built-in default | Values |
|---|---|---|
send_mode |
steering |
steering, queue, interrupt (what Enter does while a turn runs; see sending while the agent is working) |
editing_mode |
emacs |
emacs, vi (prompt editor key bindings; see vi editing) |
vi_key_prefix |
off |
Additional leader for the main prompt's vi normal mode: <space> or a single printable non-whitespace character, such as , or \. Keeps the global prefix. Requires restart; see Use Space as the vi leader. |
vi_escape_sequence |
escape |
Escape-only by default; set jj (or another printable sequence without spaces) to also leave vi insert mode with that sequence. Escape remains available. Requires restart; see vi editing. |
key_prefix |
ctrl |
Direct Ctrl+letter shortcuts, such as Ctrl+L for models and Ctrl+Y to copy. No global action-menu leader by default. Set ctrl+b, ctrl+p, ctrl+space, f2 or "ctrl+x ctrl+p" to use a leader before the action letter. Ctrl+/ browses contextual help. See shortcut prefix |
popup_mouse |
on |
on, off (popups capture clicks and the wheel; off keeps native text selection, Ctrl+Q flips it inside one popup, see popup keys) |
btw_auto_open |
on |
on, off (open the viewer when a side answer is ready) |
Scrollback and display¶
| Key | Built-in default | Values |
|---|---|---|
theme |
auto |
dark, light, auto |
syntax_dark |
terminal |
terminal or a Pygments style, for the dark palette |
syntax_light |
terminal |
terminal or a Pygments style, for the light palette |
spinner |
dots |
The status row's animation while the model works. A Rich spinner name, e.g. dots, line, point (python -m rich.spinner previews them; /config set spinner lists the ones that fit; applies on next launch) |
tool_spinner |
arc |
The same, for a running tool call's row and the terminal's own waits, so they look different from the model's |
show_thinking |
status-line |
off, status-line, scrollback (where the model's readable reasoning shows; /show-thinking) |
thinking_max_lines |
10 |
Max rows of thinking above the status row in status-line mode, or a share of the screen (0.2). A row count is also capped at a quarter of the pane, so a short pane gets fewer. Applies on next launch |
show_edits |
on |
on, off (show a diff of each file edit; Ctrl+V or /show-edits) |
live_edits |
off |
on, off (preview an edit or run_code snippet at the bottom while the model writes it) |
diff_renderer |
delta |
delta, rich (draw diffs in scrollback and /diffs with delta when it's installed, falling back to Rich; see diffs with delta) |
delta_args |
empty | delta's arguments, quoted as in a shell, such as --line-numbers; the only delta configuration pcode reads (git config is ignored), and they override pcode's own choices |
diff_dedent |
on |
on, off (strip the indentation every line of a diff hunk shares, so an edit deep in a nested block starts at the left edge; with delta or Rich; see diffs with delta) |
diff_layout |
unified |
unified, side-by-side, auto (delta's layout; auto goes side by side at 180 columns or wider) |
show_commands |
off |
on, off (mirror each shell command and its output into scrollback; Ctrl+G or /show-commands) |
group_tools |
on |
on, off (fold each run of tool calls into one line; Ctrl+] or /group-tools, see grouping tool calls) |
command_scrollback_lines |
20 |
Positive integer, lines of each command's output mirrored into scrollback |
command_preview_lines |
10 |
Rows (10) or a share of the screen (0.25) for the live preview of a running command |
tool_error_scrollback |
off |
on, off (keep a failed tool call's full diagnostic in scrollback instead of one line) |
error_scrollback_lines |
20 |
Positive integer, lines of an error notice kept in scrollback before it is clipped |
show_tasks |
on |
on, off (show the Tasks/Tools widget; Ctrl+O or /show-tasks) |
autohide_tasks |
off |
on, off (hide the Tasks/Tools widget when a turn ends; /autohide-tasks) |
tasks_min_rows |
30 |
Hide the Tasks/Tools widget in a pane shorter than this, such as a stacked split; 0 never hides. Ctrl+O overrides it until the pane crosses the threshold again |
tasks_min_columns |
100 |
Hide the Tasks/Tools widget in a pane narrower than this, such as a side-by-side split; 0 never hides. Ctrl+O overrides it the same way |
show_hints |
on |
on, off (show one compact help indicator at the prompt instead of shortcut hints beside individual controls) |
attach_tasks |
on |
on, off (draw tasks inside the editor box; /config applies immediately) |
tool_glyphs |
auto |
on leads the tool row above the status row with a symbol for the call ($, ⌕, ✎, ⎘, ⧖), off drops them and spells out the verb once the call settles (shell calls keep $), for fonts that draw those symbols badly. auto is on except on the Linux console (/config applies immediately) |
tool_max_lines |
3 |
Max tool calls listed above the status row, newest last; 1 shows only the call the status row is on. A short pane gets fewer, sharing a quarter of its height with the thinking rows (/config applies immediately) |
tool_linger_seconds |
10 |
Seconds a finished tool call stays listed above the status row, so a long wait on the model doesn't keep showing stale calls; 0 keeps it until newer calls push it out (/config applies immediately) |
task_style |
status |
status (shade task text by status), icons (one text weight, coloured icons only; /config applies immediately) |
tasks_max_height |
unset | Rows (20) or a share of the screen (0.5) for the Tasks/Tools widget and editor together; unset keeps the widget to 10 rows or half the screen |
paced_scrollback |
typed |
typed, rows, off (type settled prose out, or roll blocks in a row per frame; see the transcript) |
regenerate_on_resize |
on |
on, off (rebuild scrollback at the new size after a resize; applies on next launch) |
transcript_max_chars |
2000000 |
Positive integer, retained text budget shared by resume and redraw; applies on next launch |
cache_notices |
on |
on, off (footer note, saved with the session, when a request reuses less of the prompt cache; see prompt cache notices) |
terminal_progress |
auto |
auto, on, off (the terminal's tab progress bar while a turn runs; OSC 9;4) |
desktop_notifications |
on |
on, off (desktop notification when a background session finishes; OSC 9) |
terminal_title |
on |
on, off (set the terminal tab title to the session's name; OSC 0) |
session_naming |
on |
on, off (ask the session's own model for a title beside the first turn) |
Tools and sub-agents¶
| Key | Built-in default | Values |
|---|---|---|
web_search |
auto |
auto, local, off (provider-native web search when available, pcode's own, or none; see web search) |
code_mode |
off |
on, off (batch read-only tools through a sandboxed run_code) |
job_wake |
on |
on, off (start a turn when a job the model backgrounded finishes while idle; see shell jobs) |
tool_retries |
3 |
Whole number, corrections the model gets per turn when a tool call has invalid arguments |
strict_tools |
on |
on, off (constrain edit_file arguments with Anthropic strict tool use) |
subagent_models |
empty | ,-separated models delegate_task lists for running a sub-agent; others can still be named per delegation (/subagents); empty runs every sub-agent on the session's model; /reload to apply |
worker_concurrency |
0 |
0 means unlimited; a positive integer caps concurrent built-in workers per session; /reload to apply |
tool_output_mode |
spill |
spill, truncate, off |
tool_output_threshold |
10000 |
Positive integer, characters that trigger reduction |
tool_output_preview_chars |
1000 |
Positive integer, spill preview characters |
tool_output_max_chars |
4000 |
Positive integer, truncation budget (also spill-failure fallback) |
tool_output_strategy |
head_tail |
head, tail, head_tail (truncation only) |
tool_output_retention_hours |
0 |
Whole number, spill retention; 0 keeps indefinitely |
Context¶
| Key | Built-in default | Values |
|---|---|---|
autocompact |
on |
on, off |
autocompact_tokens |
unset | Tokens such as 200000 or 200k (minimum 50k) at which to compact automatically; unset uses about 90% of the window |
Sessions and worktrees¶
| Key | Built-in default | Values |
|---|---|---|
session_host |
off |
on, off (run sessions in a background host that outlives the terminal from the start; off runs them in the terminal until /detach moves one into a host; --host/--no-host override it once) |
session_host_idle_minutes |
0 |
whole minutes a background session may sit idle with no terminal before its host stops; 0 stops it 15 seconds after it goes idle, off never |
worktree |
off |
on, off (start new sessions in .worktrees/ git worktrees; does not enable worker isolation on its own) |
worktree_exit |
ask |
ask, merge, keep (what to do with unmerged commits when a session worktree is left) |
worker_isolation |
off |
on, off (opt in to isolated built-in worker tasks; also requires effective worktree=on, not just the CLI launch override; checked at each delegation) |
Email remote control¶
Settings for pcode --email-listen. All of them are user-only: a repository's .pcode/preferences.json cannot set them.
| Key | Built-in default | Values |
|---|---|---|
email_owner |
unset | the Gmail address allowed to control pcode by email; set by pcode --email-setup |
email_mcp |
off |
on, off (start default MCP servers in email-started sessions; they run outside the sandbox) |
email_turn_minutes |
30 |
wall-clock minutes per email-started turn; 0 is no limit |
email_turn_requests |
100 |
model requests per email-started turn, sub-agents included; 0 is no limit |
email_turn_tool_calls |
100 |
tool calls per email-started turn, sub-agents included; 0 is no limit |
email_concurrent_sessions |
2 |
email sessions that may be working at once |
email_max_sessions |
20 |
sessions one --email-listen may start |
email_session_inputs |
20 |
emails that may wait in one session |
email_max_inputs |
100 |
emails that may wait across every session |
Repository instructions, skills and extensions¶
| Key | Built-in default | Values |
|---|---|---|
repo_context_walk_up |
on |
on, off (inherit ancestor instruction files) |
repo_context_nested |
off |
off, pointer, contents (discover instructions on file-tool traversal) |
skill_commands |
prefix |
prefix, bare, both, off (how discovered skills appear as slash commands) |
skill_dirs |
~/.agents/skills:.agents/skills |
:-separated directories searched for skills; relative entries resolve against the workspace |
project_extensions |
off |
on, off (on trusts every repository's .pcode/extensions and worktree-setup) |
trusted_projects |
empty | :-separated repository paths whose shipped code may run; the launch prompt appends here |
extension_dirs |
empty | :-separated extra directories searched for extensions, after the user one |
extensions_off |
empty | ,-separated extension names that never load (/extensions off NAME) |
extensions_on |
empty | ,-separated opt-in extension names to load (/extensions on NAME) |
Diagnostics¶
| Key | Built-in default | Values |
|---|---|---|
debug |
off |
on, off (also write request fingerprints to disk with each cache notice) |
profile |
off |
off, resources, cpu, memory (capture each session's resource use; see profiling) |
stall_log |
on |
on, off (when the editor stops responding for roughly 150 ms or more, append what was running to ~/.local/state/pcode/stalls.jsonl) |
Code highlighting styles¶
Each palette gets its own setting: syntax_dark applies whenever the resolved
theme is dark, syntax_light whenever it is light. /syntax NAME changes the
setting for the palette in use and saves it as that palette's default; /syntax
alone reports the current one. Tab completion lists the choices, and an unknown
name is rejected with the full list.
Both default to terminal, which is not a Pygments style: it hands every color
to the terminal's own ANSI palette. Scrollback uses named colors, fenced code
uses ansi_dark / ansi_light with no painted background, and the prompt, task
rows and completion popup use ANSI names too (the selected popup row is
reversed). pcode then looks right in whatever scheme the terminal runs.
/theme-preview draws a sample of every style on one line, marks the one in
use, and repeats the commands below, so a style can be chosen by eye rather than
by name. The terminal row is drawn with the palette's ANSI style.
Any other value is a Pygments style. The completion menu and the prompt chrome
(the chevron, plan rows, the frame, @file references) are painted from it, so the screen matches the
code on it. A Pygments style only colors code, though, so any color it leaves
out or that would be unreadable falls back to the palette's own. The two are
judged against different backgrounds: the menu brings the style's own surface
with it, while chrome lands on the terminal's background, so a light style
chosen while the dark palette is active keeps its popup but leaves the chrome
on the palette. Picking any Pygments style also switches scrollback headings,
links, quotes and tables from ANSI names to the palette's own colors.
These are the styles that come with Pygments; installing a Pygments style plugin package adds to the list automatically.
Darker backgrounds: coffee, dracula, fruity, github-dark, gruvbox-dark,
inkpot, lightbulb, material, monokai, native, night-owl, nord,
nord-darker, one-dark, paraiso-dark, rrt, solarized-dark, stata-dark,
vim, zenburn.
Lighter backgrounds: abap, algol, algol_nu, arduino, autumn, borland,
bw, colorful, default, emacs, friendly, friendly_grayscale,
gruvbox-light, igor,
lilypond, lovelace, manni, murphy, paraiso-light, pastie, perldoc,
rainbow_dash, sas, solarized-light, staroffice, stata-light, tango,
trac, vs, xcode.
Styles differ in how much they color: some leave plain identifiers and punctuation at the default foreground, so a snippet that is mostly names can look unhighlighted even though the lexer ran. Compare a few against your own terminal background before settling on one.
Outside the editor, pcode config set syntax_dark NAME and
pcode config set syntax_light NAME save the same two settings.
Notes¶
Automatic compaction still requires a known context window; setting its global
preference does not validate a particular model or trigger a compaction. For custom
deployments, use PCODE_CONTEXT_WINDOW as described in
context compaction. MCP configuration and
credentials are separate from these non-secret defaults.
Writes are atomic and serialized across terminals. Unknown JSON keys are preserved;
invalid setting values fall back to built-in defaults. Normal startup tolerates a
malformed file, but config commands report it and refuse to overwrite it: use
pcode config path to find and repair it first. Invalid commands exit nonzero.
At startup pcode looks up the latest release on PyPI, at most once a day and
without delaying the session, and shows a warning with the upgrade command for
your install (Homebrew, uv, pipx or pip) when a newer version is out. Development
and editable installs skip it; set PCODE_NO_UPDATE_CHECK=1 to turn it off.
PCODE_CONFIG_DIR overrides the user config directory for preferences, extensions,
MCP configuration, keybindings, worktree setup, and stored logins. Otherwise pcode uses
$XDG_CONFIG_HOME/pcode, defaulting to ~/.config/pcode. Per-file overrides
(PCODE_CODEX_CREDENTIALS_FILE, PCODE_MCP_CONFIG)
take precedence.