Files
pi-toolkit/AGENTS.md
T
joakimp 4b4b76e80e feat(pi-atelier): ship Status Rail defaults, cp'd not symlinked
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.
2026-07-29 23:42:05 +02:00

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.zshcp into ~/.oh-my-zsh/custom/. That dir is typically part of a dotfiles backup (e.g. myconfigs's rsync_copy.sh); a symlink into this repo's absolute path breaks when the backup is restored on another host.
    • pi-atelier.jsoncp if 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.jsonnot installed. pi rewrites ~/.pi/agent/settings.json at runtime (lastChangelogVersion bumps on upgrade), so any symlink back to the repo would dirty the working tree. Installer prints the cp command 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 early exit 4 from require_pi_installed because 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 via cmp -s, prints a diff hint, leaves the file alone.
  • Do not auto-edit rc files. If oh-my-zsh isn't present, print the source snippet the user manually adds to ~/.zshrc or ~/.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-toolkit on purpose), it must degrade gracefully when mempalace is absent.
  • POSIX-compatible shell glue. set -a / source / set +a work 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 later mempalace-toolkit install has somewhere to symlink into.

Always (once pi is present):

  • Symlinks keybindings.json into ~/.pi/agent/. Backs up any pre-existing real file.

oh-my-zsh path (gated on ~/.oh-my-zsh/custom/ existing):

  • Copies pi-env.zsh into that directory. Drift-safe — prints a diff hint if installed content differs from repo, doesn't clobber.

No oh-my-zsh path:

  • Prints a shell-specific source snippet for ~/.zshrc or ~/.bashrc (selected from $SHELL). User pastes manually.

Probes (non-halting):

  • ~/.pi/agent/settings.json exists. Without it pi refuses to start without --provider/--model. Prints the cp settings.example.json command.
  • AWS_PROFILE + AWS_REGION are set, only if settings.json selects amazon-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:

  1. One file at repo root. Flat layout; no extensions/ subdir yet. Revisit if five+ artifacts ever accumulate.
  2. 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.
  3. One install step + one uninstall step in install.sh, guarded by link_if_into_repo (for symlinks) or cmp -s (for copies). Never remove user edits silently.
  4. One probe per external dependency the artifact implies. warn + return 0.
  5. 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's ExtensionAPI, registers MCP tools, injects wake-up context.
  • The install_pi_extension function 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.json is region-specific. The shipped default uses eu. Bedrock inference-profile prefixes. Users on us-east need to swap to us. 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_REGION are irrelevant. The probe gates on grep -q '"amazon-bedrock"' settings.json to stay quiet in those cases.
  • Mosh strips modifiers upstream of tmux. The keybindings file's ctrl+j / alt+j fallbacks are specifically because mosh's vt220-ish emulation does not forward Shift+Enter as CSI-u — tmux's extended-keys csi-u setting 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/.env should 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.
  • mempalace-toolkit — adds a pi↔mempalace MCP bridge on top of this toolkit. Installs the mempalace.ts extension 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/.env is 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) — the Conventions section 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 --help output 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.