Adds pi-atelier.json (defaults for the pi-atelier extension) and an install/uninstall step for it, so the config survives a devbox volume wipe and applies to pi on the host too — ~/.pi/agent is a named volume in a container, which the extension's own config path alone does not outlive. cp-if-absent rather than a symlink, unlike keybindings.json/AGENTS.md: the extension rewrites this exact path when the user saves from its menu (src/config.ts writeJsonAtomic -> "<path>.<pid>.tmp" then rename). rename(2) REPLACES a symlink with a regular file instead of following it, so a link would detach on the first menu save and the repo copy would quietly stop applying. Verified empirically before choosing the idiom, not assumed. Drift is respected in both directions, matching the pi-env.zsh shape: install never clobbers an existing file (warns + prints a diff hint), uninstall removes it only while its content still matches the repo. All five paths exercised against an isolated HOME: fresh copy, idempotent re-run, drift-preserved install, drift-preserved uninstall, matched-content uninstall. Values chosen for this setup and validated against the extension's own validateConfig (no warnings, no coercion): - segments drop "brand" (decoration, and first in the drop order anyway) - density compact — the rail relayouts at 132/96/72/56 cols and these sessions run over plain SSH at unknown width - contextWarning/Danger 60/85, earlier than the 70/90 default because defaultModel is opus-5 at xhigh thinking with obsmem compaction behind it - showSidebarToolNames true — MCP/tool-heavy sessions, names beat "something is running" - completionNotifications false — deliverSystemNotification only spawns for darwin/win32 and returns undefined on linux, and a container has no desktop session to reach anyway Docs: file inventory + install/uninstall tables in README.md and AGENTS.md, including why the symlink idiom does not apply here.
10 KiB
AGENTS.md
What this is
Harness-side bring-up for the pi coding-agent. Installs three pi-generic config artifacts into the right places and runs a couple of non-halting probes. Does not depend on MemPalace.
Sibling to opencode-toolkit —
same shape: one install.sh at the root, cp-or-symlink the config files,
probe the environment, compose independently of the palace memory layer.
Read README.md first for the user-facing walk-through.
This file is for agents modifying the repo.
Structure
install.sh # Idempotent installer (symlink + cp + probes)
pi-env.zsh # Shell loader sourcing ~/.config/pi/.env (POSIX-compatible)
keybindings.json # ~/.pi/agent/keybindings.json — mosh/tmux newline fix
pi-atelier.json # ~/.pi/agent/pi-atelier.json (cp) — Status Rail defaults
pi-global-AGENTS.md # ~/.pi/agent/AGENTS.md (symlink) — global agent instructions
settings.example.json # Template for ~/.pi/agent/settings.json (copy + edit)
README.md # User-facing quickstart + new-machine deploy recipe.
AGENTS.md # This file.
LICENSE # MIT.
Conventions
- One install step per artifact, with a matching uninstall step.
- Symlink what's safe to symlink, cp what's part of a dotfiles backup,
template what the harness rewrites.
keybindings.json→ symlink. pi doesn't rewrite it; the symlink lets edits flow through git without a re-install step.pi-env.zsh→cpinto~/.oh-my-zsh/custom/. That dir is typically part of a dotfiles backup (e.g.myconfigs'srsync_copy.sh); a symlink into this repo's absolute path breaks when the backup is restored on another host.pi-atelier.json→cpif absent. The pi-atelier extension rewrites this exact path when the user saves from its menu, using write-temp-then-rename.rename(2)replaces a symlink with a regular file instead of following it, so a symlink would detach silently on the first menu save and the repo copy would quietly stop applying. Verified, not assumed. Drift is respected in both directions: install won't clobber an existing file, uninstall only removes one whose content still matches the repo.settings.example.json→ not installed. pi rewrites~/.pi/agent/settings.jsonat runtime (lastChangelogVersionbumps on upgrade), so any symlink back to the repo would dirty the working tree. Installer prints thecpcommand and walks away.
- Probes warn, never halt.
warn+return 0. The installer's only hard-fail path is "pi isn't installed at all" — that's an earlyexit 4fromrequire_pi_installedbecause there's nothing useful to do without~/.pi/agent/. - Non-destructive. Existing real files at symlink destinations get
backed up with a timestamp (
.bak.YYYYMMDD-HHMMSS) before linking. The shell loader's cp path refuses to clobber local edits: detects drift viacmp -s, prints adiffhint, leaves the file alone. - Do not auto-edit rc files. If oh-my-zsh isn't present, print the
sourcesnippet the user manually adds to~/.zshrcor~/.bashrc. Invasive shell-rc edits belong in a dotfiles installer, not here. - No hard dependency on mempalace. If the surface ever grows
mempalace-aware (unlikely — those pieces live in
mempalace-toolkiton purpose), it must degrade gracefully when mempalace is absent. - POSIX-compatible shell glue.
set -a/source/set +awork in bash and zsh both. Don't add zsh-only constructs to files that may end up sourced from~/.bashrc.
What install.sh does
Hard-required:
require_pi_installed— aborts with exit 4 if~/.pi/agent/is missing. Creates~/.pi/agent/extensions/proactively so a latermempalace-toolkitinstall has somewhere to symlink into.
Always (once pi is present):
- Symlinks
keybindings.jsoninto~/.pi/agent/. Backs up any pre-existing real file.
oh-my-zsh path (gated on ~/.oh-my-zsh/custom/ existing):
- Copies
pi-env.zshinto that directory. Drift-safe — prints adiffhint if installed content differs from repo, doesn't clobber.
No oh-my-zsh path:
- Prints a shell-specific source snippet for
~/.zshrcor~/.bashrc(selected from$SHELL). User pastes manually.
Probes (non-halting):
~/.pi/agent/settings.jsonexists. Without it pi refuses to start without--provider/--model. Prints thecp settings.example.jsoncommand.AWS_PROFILE+AWS_REGIONare set, only ifsettings.jsonselectsamazon-bedrock. Silent for non-Bedrock providers. Silent if settings.json is missing (check_pi_settings already handled that case).
Adding a new artifact
Follow the same shape keybindings.json / pi-env.zsh / settings.example.json use:
- One file at repo root. Flat layout; no
extensions/subdir yet. Revisit if five+ artifacts ever accumulate. - Choose symlink / cp / template per the conventions above. Document
the choice in a comment next to the variable declarations at the top
of
install.sh. - One install step + one uninstall step in
install.sh, guarded bylink_if_into_repo(for symlinks) orcmp -s(for copies). Never remove user edits silently. - One probe per external dependency the artifact implies.
warn+return 0. - Update this file's Structure block and
README.md.
Adding mempalace-aware functionality
Don't. Those pieces belong in mempalace-toolkit/extensions/pi/:
- The mempalace MCP bridge TypeScript extension (
mempalace.ts) — imports pi'sExtensionAPI, registers MCP tools, injects wake-up context. - The
install_pi_extensionfunction that symlinks it in. - Any probes that check for mempalace being reachable through pi.
That boundary is load-bearing for opencode-devbox's slim container
path: a container built with INSTALL_MEMPALACE=false should install
pi-toolkit cleanly and get a functional pi without dragging in
chromadb + embedding models (~300 MB).
Testing
No framework. Manual:
./install.sh --help # flags
./install.sh --yes # fresh install
./install.sh --yes # re-run (idempotent)
./install.sh --uninstall --yes # remove
./install.sh --yes # reinstall
oh-my-zsh fallback simulation:
SHELL=/bin/bash HOME=/tmp/fake ./install.sh --yes # should print ~/.bashrc snippet
Environment verification (after install + exec zsh or new shell):
zsh -ic 'echo $AWS_PROFILE $AWS_REGION' # should print values from ~/.config/pi/.env
Drift simulation:
echo "# local edit" >> ~/.oh-my-zsh/custom/pi-env.zsh
./install.sh --yes # should warn "differs from repo" and leave alone
Gotchas
- pi must be installed upstream first.
~/.pi/agent/is created by pi on first run, not by this installer. Missing → exit 4 with pointer to https://github.com/earendil-works/pi. settings.example.jsonis region-specific. The shipped default useseu.Bedrock inference-profile prefixes. Users on us-east need to swap tous.before first run, or pi will reject the model ID.- Bedrock is not the only provider. If the user is on bare
Anthropic or OpenAI,
AWS_PROFILE/AWS_REGIONare irrelevant. The probe gates ongrep -q '"amazon-bedrock"' settings.jsonto stay quiet in those cases. - Mosh strips modifiers upstream of tmux. The keybindings file's
ctrl+j/alt+jfallbacks are specifically because mosh's vt220-ish emulation does not forwardShift+Enteras CSI-u — tmux'sextended-keys csi-usetting doesn't help over mosh (only helps on direct ssh / local / WireGuard). Documented in README. - The shell loader runs on every shell start. Keep it fast. If it
grows beyond a few lines, gate on
[[ $- == *i* ]]so non-interactive shells skip the work. ~/.config/pi/.envshould be chmod 600. It's plaintext on disk; git-crypt encryption only applies in the dotfiles repo. The installer does not enforce this because it doesn't ship the file.
Related repos
mempalace-toolkit— adds a pi↔mempalace MCP bridge on top of this toolkit. Installs themempalace.tsextension into~/.pi/agent/extensions/. Optional.opencode-toolkit— sibling pattern for the opencode coding-agent. Same install.sh shape.opencode-devbox— Docker containers; composes any subset of these toolkits via independent install.sh invocations.myconfigs— dotfiles repo where~/.config/pi/.envis tracked (git-crypt encrypted).
History
Split out of mempalace-toolkit/extensions/pi/ on 2026-05-05. Previously
the pi-generic config artifacts (env loader, keybindings, settings
template) lived alongside the mempalace.ts MCP bridge inside
mempalace-toolkit because that's where the pattern first crystallized.
The split was motivated by opencode-devbox's mempalace opt-out and
future pi-option: a container built with mempalace off should still be
able to install a functional pi, and that dependency asymmetry is
cleanest when pi's own config lives in its own repo. Mirrors the
2026-05-05 split of opencode-toolkit out of the same parent.
Documentation drift sweep
Before committing any non-trivial change, check that prose still matches code. Drift hotspots in this repo:
README.md— install instructions, the file/artifact table, the testing recipe. The installer's behaviour and the README's description of it must stay in lockstep — the README is what users follow.AGENTS.md(this file) — theConventionssection codifies symlink-vs-cp-vs-template decisions per artifact; if you change how an artifact is installed, update the conventions too.install.sh— contains its own usage block at the top; keep the--helpoutput and the README in sync.settings.example.json— the canonical template for pi settings; if pi adds a new top-level setting that this toolkit blesses with defaults, update the example here.
Quick triage: git diff --name-only HEAD | xargs -I{} grep -l 'thing-you-changed' README.md AGENTS.md install.sh.