Configuration
Most extensions need no configuration. Everything that can be changed lives
under one top-level section of one document, bytefly.json, named for the
extension — bytefly itself owns four (price, notify, doctor, chrome).
This page is the how-to: where a setting lives and how to change it. Every key, with its type, default, and bounds, is in the configuration reference.
Contents
- Where a setting lives
- Change a setting
- What people usually change
- Migrating from older versions
- Environment variables
- State
- Related docs
Where a setting lives
A value resolves in three layers, each later one over the previous:
- the loader’s built-in default;
<agent-dir>/bytefly.json— the global document, in Pi’s agent directory (PI_CODING_AGENT_DIR, usually~/.pi/agent);<cwd>/.pi/bytefly.json— the project document.
A key set in the project file overrides the same key from the global file; a key
the project file leaves out keeps the global value. worktree is the exception:
it reads its project document from the repository root, not the effective working
directory, so the setting follows the checkout rather than a worktree inside it.
The three layers, and the screen that writes into two of them.
flowchart TD
D["built-in defaults"] --> G["global file · agent dir"]
G --> P["project file · .pi"]
P --> E["effective value"]
S["/bytefly settings"] -.-> G
S -.-> P
Read it top to bottom: a value falls through the defaults and the two files, and the last file that states it wins; the settings screen writes a single key into whichever file the scope selector names.
| Scope | File | Applies to | Written by |
|---|---|---|---|
| Global | <agent-dir>/bytefly.json |
every session on this machine | the settings screen’s Global scope, or a hand edit |
| Project | <cwd>/.pi/bytefly.json |
this project (for worktree, the repository root) |
the settings screen’s Project scope, or a hand edit |
Three exceptions are worth knowing:
- Pi’s own settings. The Startup screen and Theme rows write Pi’s
settings.jsonrather thanbytefly.json, and are Global only because Pi exposes no project scope for them. The other Pi preferences the screen once carried — output padding and the hardware cursor — stay in Pi’s own/settings. - One key at a time. The screen writes only the key you changed, preserving every sibling, other section, and metadata key.
- Metadata.
$schemaandversionare ignored by the loaders:migrate:configstampsversionwhen it is missing, and nothing warns about it. See Document metadata.
A missing or malformed document is ignored, so a broken file never blocks a
session; /bytefly doctor reports the file that failed to parse.
Change a setting
Two ways in, and the same two destinations.
Which control, and which file.
flowchart TD
Q1{"Changed from a screen?"} -->|yes| R["/bytefly settings"]
Q1 -->|no| F["the section table"]
R --> Q2{"Which scope, or file?"}
F --> Q2
Q2 -->|this project| PP["project .pi/bytefly.json"]
Q2 -->|all projects| GG["global agent dir/bytefly.json"]
If the row exists in /bytefly settings, change it there: the screen validates
the value and writes one key. If it does not, edit the section’s table below in
the file for the scope you want, and the next session reads it.
From the settings screen.
- Run
/bytefly settings(/bytefly, then→, opens the same section). - Press
sto choose Global or Project scope. - Move with
↑/↓, thenSpaceorEnterto change the value: a switch toggles, a choice cycles, and a text row opens an editor saved withEnter. uremoves the key so its default applies again; it refuses for Startup screen and Theme, which are Pi’s own rows, and for a Project row that only inherits Global.Jshows the stored section as JSON.- Close the screen and accept the reload it offers.
By hand.
- Open
<agent-dir>/bytefly.jsonfor every project, or<cwd>/.pi/bytefly.jsonfor one. Create the file if it does not exist. -
Put the key under its section, as a dotted path flattened into nested objects:
{ "version": 1, "chrome": { "rail": "│" }, "job": { "wakeOnFinish": true } } - Save valid JSON; a malformed file is ignored and
/bytefly doctornames it. The next session picks the value up.
What people usually change
| I want to… | Where |
|---|---|
| get a desktop alert when a turn, a job, or a question needs me | Desktop notifications in /bytefly settings |
| see costs in another currency, or set a budget | Currency, Session budget |
| set the cost precision after choosing a currency | price.currency.decimals |
| change the rail glyph beside tool results | chrome.rail |
| use the light palette, or follow the system’s preference | Theme in /bytefly settings, or theme in Pi’s own settings |
| keep an achieved goal visible | goal.achieved |
| keep more snapshots, or turn off the pre-restore one | rewind.max, rewind.safetySnapshot |
| wake the agent when a job finishes, or keep jobs after exit | Resume after a job, job.detachedByDefault |
| wake the agent on a watcher match | watch.wakeOnMatch |
| stop injecting memory notes | memory.inject |
| choose the worktree base, branch prefix, fetch, or prune age | worktree |
| pin the port every page of a session shares, so a bookmarked URL survives a restart | serve |
| use a self-hosted search service or a Brave key | web-access |
| change document read limits | file-read |
| raise the board’s WIP limits, name the team lead whose signature the board’s gates take, or say who is on the team | Plan limit, Execute limit, Lead, Teammates in /bytefly settings, or board and team |
/bytefly settings is a shortlist of the preferences a session changes — sixteen
rows under six headings (Startup, Notifications, Session, Board, Team, and Price), named in
bold above. Everything else — the tuning numbers, the
cosmetic labels, and the settings Pi’s own /settings owns — is the file or Pi’s
screen; the full list is on
the configuration reference.
Migrating from older versions
Before the shared document, each extension read its own <name>.json
(document.json, jobs.json, web-access.json, …). The migration ships with the
repository rather than with the published package — scripts/ is not in the tarball
pi install npm: unpacks — so run it from a checkout, once per machine and per
repository:
git clone https://github.com/gavin-hu/my-pi-agent && cd my-pi-agent && bun install
bun run migrate:config --project <repo-root> # --dry-run previews, --keep keeps the old files
It moves each legacy file into its section, renames an already-migrated
document section to file-read, moves bytefly’s former top-level
currency/rates/peak under price, stamps version, and deletes the legacy
files. It skips an existing section and refuses to touch a malformed document,
so it is safe to re-run. It reads the same agent directory an installed pi
writes, so the checkout migrates what the package left behind.
Environment variables
Three variables change how the package runs; the PI_WORKTREE_* ones are set by
the extension and need no attention.
You set these.
| Variable | Meaning |
|---|---|
PI_DISABLED_EXTENSIONS |
Comma- or whitespace-separated extension names to load without; case-insensitive, unknown names ignored. |
PI_OFFLINE |
Turns off Pi’s automatic network activity; bytefly’s update check reads it too, so an offline session makes no package-update or version request. |
PI_CODING_AGENT_DIR |
The agent directory the global document resolves against. |
The package sets these.
| Variable | Meaning |
|---|---|
PI_WORKTREE_ROOT |
The effective working directory while a worktree is active. |
PI_WORKTREE_BRANCH |
The worktree’s branch name. |
PI_WORKTREE_MAIN |
The main checkout path, used by exit and prune. |
Do not set those by hand: they describe the session to its child processes.
State
The wechat extension keeps runtime state under <agent-dir>/wechat/:
credentials.json (mode 0600, the one stored account this bridge runs),
state.json (the poll cursor, the one conversation’s reply token and last
inbound time, and the recent message ids used to ignore a replay), media/
(downloaded inbound files, pruned once they pass mediaRetentionDays), and
poller.lock (one runtime owns the account at a time). This is login and runtime
state, not configuration; each extension’s page names
the files it writes.
Related docs
| Topic | Document |
|---|---|
| Changing settings on screen, for a user | bytefly |
| Trust boundaries around state and credentials | Security |
| One extension’s own configuration section | each extension’s page |