4b4b76e80e
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.
219 lines
10 KiB
Markdown
219 lines
10 KiB
Markdown
# AGENTS.md
|
|
|
|
## What this is
|
|
|
|
Harness-side bring-up for the [pi coding-agent](https://github.com/earendil-works/pi).
|
|
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`](https://gitea.jordbo.se/joakimp/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`](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` → `cp` 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.json` → `cp` **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.json` → **not 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:
|
|
|
|
```bash
|
|
./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:
|
|
|
|
```bash
|
|
SHELL=/bin/bash HOME=/tmp/fake ./install.sh --yes # should print ~/.bashrc snippet
|
|
```
|
|
|
|
Environment verification (after install + `exec zsh` or new shell):
|
|
|
|
```bash
|
|
zsh -ic 'echo $AWS_PROFILE $AWS_REGION' # should print values from ~/.config/pi/.env
|
|
```
|
|
|
|
Drift simulation:
|
|
|
|
```bash
|
|
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.
|
|
|
|
## Related repos
|
|
|
|
- [`mempalace-toolkit`](https://gitea.jordbo.se/joakimp/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`](https://gitea.jordbo.se/joakimp/opencode-toolkit)
|
|
— sibling pattern for the opencode coding-agent. Same install.sh
|
|
shape.
|
|
- [`opencode-devbox`](https://gitea.jordbo.se/joakimp/opencode-devbox)
|
|
— Docker containers; composes any subset of these toolkits via
|
|
independent install.sh invocations.
|
|
- [`myconfigs`](https://gitea.jordbo.se/joakimp/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`.
|