Files
mempalace-toolkit/extensions/pi/README.md
T
joakimp 71c335148a docs(pi): full 'new machine' deploy recipe in extensions/pi/README
Consolidates the step-by-step recipe that's been living in diary entries
and session chat into the canonical pi bring-up doc. Covers:

  0. Prerequisites (zsh+oh-my-zsh, uv, tmux 3.2+, AWS creds)
  1. Dotfiles: myconfigs provision (tmux CSI-u, ~/.config/pi/.env, zsh loader)
  2. pi install (upstream brew/npm)
  3. mempalace CLI (uv tool install) + mempalace-toolkit install.sh
  4. pi settings bootstrap (start without --model, region prefix table)
  5. AWS env verification (git-crypt unlock gotcha)
  6. Opencode MCP registration pointer (if applicable)
  7. First run + wake-up injection smoke test
  + Verification checklist + uninstall

Root README.md adds a short summary box in the Setup section pointing at
the full recipe, so readers coming in from the front door find the pi
path immediately but the details stay with the files they install.

Covers: macOS + Linux. Works for homelab / work-macos / any myconfigs
profile that ships .config/pi/ + pi-env.zsh.
2026-05-05 15:20:47 +02:00

286 lines
10 KiB
Markdown

# pi ↔ MemPalace extension
The canonical source of `~/.pi/agent/extensions/mempalace.ts` — the bridge
that wires the [MemPalace](https://github.com/MemPalace/mempalace) MCP
server into the [pi coding-agent](https://github.com/mariozechner/pi-coding-agent)
harness.
`install.sh` at the repo root symlinks `mempalace.ts` from this directory
into `~/.pi/agent/extensions/` so the live file on every machine tracks
version control. Works on macOS and Linux (the extension itself is plain
Node / TypeScript; the symlink is a POSIX `ln -s`).
**Jump to:**
- [Deploying pi on a new machine](#deploying-pi-on-a-new-machine) — step-by-step recipe.
- [Keybindings (mosh/tmux newline fix)](#keybindings-moshtmux-newline-fix)
- [Settings template](#settings-template-start-pi-without---model)
- [Environment setup](#environment-setup)
---
## Deploying pi on a new machine
Full recipe from a clean macOS or Linux box to a working pi+MemPalace
install with all modifications shipped by this repo and by
[`myconfigs`](https://gitea.jordbo.se/joakimp/myconfigs). Follow in order.
### 0. Prerequisites
- Shell: **zsh + oh-my-zsh** (the env loader is `~/.oh-my-zsh/custom/pi-env.zsh`).
On bash-only hosts, adapt by sourcing `~/.config/pi/.env` from `~/.bashrc`.
- `git`, `node` ≥ 20, `uv` (for installing mempalace), `tmux` ≥ 3.2.
- AWS credentials reachable via `AWS_PROFILE` (either `aws configure sso`
cache or static keys in `~/.aws/credentials`) — **only if** you'll use
`amazon-bedrock` as pi's provider.
### 1. Clone your dotfiles repo and provision
Brings `~/.tmux.conf` with CSI-u extended keys, `~/.config/pi/.env`
(git-crypt encrypted), and `~/.oh-my-zsh/custom/pi-env.zsh`:
```bash
git clone ssh://git@gitea.jordbo.se:2222/joakimp/myconfigs.git ~/src/src_local/myconfigs
cd ~/src/src_local/myconfigs
# Unlock git-crypt so ~/.config/pi/.env decrypts (skip on a box that has
# never held your git-crypt key; see myconfigs/GIT-CRYPT.md to set up).
git-crypt unlock ~/path/to/git-crypt-key
# Provision — choose the profile matching the box (homelab, work-macos, ...).
./provision.sh --dry-run --profile homelab # preview
./provision.sh --profile homelab # apply
```
### 2. Install pi (upstream)
```bash
brew install pi-coding-agent # macOS
# or: follow https://github.com/mariozechner/pi-coding-agent for Linux
```
First run creates `~/.pi/agent/`.
### 3. Install mempalace + the toolkit
```bash
# MemPalace CLI (isolated venv via uv, shim in ~/.local/bin)
uv tool install mempalace
# mempalace-toolkit (this repo) — the bin/ wrappers, the pi extension,
# keybindings, settings template, and install probes.
git clone ssh://git@gitea.jordbo.se:2222/joakimp/mempalace-toolkit.git ~/mempalace-toolkit
cd ~/mempalace-toolkit
./install.sh
```
`install.sh` detects pi, symlinks `mempalace.ts` + `keybindings.json` into
`~/.pi/agent/`, installs the companion skill, and runs five probes. The
AWS probe stays quiet until step 4 selects `amazon-bedrock`.
### 4. Bootstrap pi settings (start pi without `--model`)
```bash
cp ~/mempalace-toolkit/extensions/pi/settings.example.json \
~/.pi/agent/settings.json
$EDITOR ~/.pi/agent/settings.json
```
Adjust the inference-profile prefix to match your AWS region:
| Region | Prefix | Example model ID |
|---|---|---|
| eu-west-1 | `eu.` | `eu.anthropic.claude-sonnet-4-6` |
| us-east-1 | `us.` | `us.anthropic.claude-sonnet-4-6` |
| non-Bedrock | (none) | `anthropic:claude-sonnet-4-6` |
Run `pi --list-models` to confirm what your credentials can actually invoke.
### 5. Ensure AWS env vars are live in your shell
If you provisioned via step 1, `~/.config/pi/.env` exists and
`~/.oh-my-zsh/custom/pi-env.zsh` sources it on every new shell. Verify:
```bash
exec zsh
echo "$AWS_PROFILE $AWS_REGION" # should print your values
```
If empty, check that `~/.config/pi/.env` decrypted (`head ~/.config/pi/.env`
should show plain text, not binary). `git-crypt unlock` in step 1 is the
usual culprit when this is empty.
### 6. Register mempalace MCP with opencode (if using opencode too)
Skip if this box is pi-only. Otherwise see
[root README § Registering mempalace with opencode](../../README.md#registering-mempalace-with-opencode-or-other-mcp-clients).
### 7. First run
```bash
pi # should start with the default model, no --model needed
```
Inside pi, the wake-up auto-injection should print a `mempalace-wakeup`
system message with palace status and recent diary entries. If it doesn't,
run `MEMPALACE_EXT_DEBUG=1 pi` to surface `mempalace-mcp` stderr.
### Verification checklist
```bash
# Symlinks in place
ls -la ~/.pi/agent/mempalace.ts ~/.pi/agent/keybindings.json # → repo
ls -la ~/.agents/skills/opencode-mempalace-bridge/SKILL.md # → repo
# Env loaded
zsh -ic 'echo $AWS_PROFILE $AWS_REGION'
# tmux extended keys
tmux show-options -g | grep extended-keys # csi-u
# Palace reachable
mempalace status
# Installer re-run is idempotent
cd ~/mempalace-toolkit && ./install.sh --yes # all rows should say "already linked"
```
### Uninstall
```bash
cd ~/mempalace-toolkit && ./install.sh --uninstall --yes
# Leaves mempalace CLI, pi binary, and ~/.config/pi/.env alone —
# only removes symlinks this repo created.
```
---
## What it does
1. **Spawns `mempalace-mcp`** as a subprocess and does the MCP stdio
JSON-RPC handshake (`initialize` + `notifications/initialized` +
`tools/list`).
2. **Registers each MCP tool** as a pi tool with its real `inputSchema`
passed through via `Type.Unsafe(...)` (see gotcha below).
3. **Wake-up auto-injection** (`before_agent_start`, one-shot per fresh
session): calls `mempalace_status` + `mempalace_diary_read` and
injects the result as a `mempalace-wakeup` system message so the
agent orients itself the way `~/.agents/skills/mempalace/SKILL.md`
describes. Skipped on resume/fork (context is already in the thread).
4. **Manual wind-down** via a `/mempalace-diary [topic]` slash command:
sends a prompt asking the LLM to call `mempalace_diary_write` with
an AAAK-formatted entry summarizing the session. Not fully auto
because pi sessions are typically short/tactical and
`session_shutdown` fires too late to drive another LLM turn.
## Fail-soft
If `mempalace-mcp` can't be spawned (PATH missing, binary crashes at
startup, …) the extension logs to stderr and returns early. pi keeps
working without palace tools rather than refusing to start.
## Identity
`agent_name` for diary calls comes from `$MEMPALACE_AGENT_NAME`, defaulting
to `"pi"`. First diary write against that identity creates `wing_<name>`
in the palace. Set the env var if you want to run pi under a distinct
identity on a given machine (e.g. `pi-laptop` vs `pi-server`).
## Debugging
- `MEMPALACE_EXT_DEBUG=1` — surface `mempalace-mcp` stderr into pi's
stderr. Without this, stderr is drained silently so a misbehaving
server doesn't flood the TUI.
- If a tool call fails with a generic "Internal tool error", spawn
`mempalace-mcp` manually with raw JSON-RPC on stdin to read the
server-side error — much faster than guessing.
## The `Type.Unsafe` gotcha
Earlier versions of this extension registered every MCP tool with
`parameters: Type.Object({}, { additionalProperties: true })`, which
discarded each tool's real `inputSchema`. The LLM then saw no parameter
names and had to guess, leading to bugs like `mempalace_diary_read`
being called with `agent=` instead of the required `agent_name=` and
crashing the Python server with `TypeError: missing 1 required
positional argument`.
The fix (≈ lines 160-170) is to wrap the incoming JSON Schema with
`Type.Unsafe<...>(tool.inputSchema)`. TypeBox schemas are plain JSON
Schema at runtime plus a `Symbol` marker, so wrapping an
externally-sourced schema with `Unsafe` is sufficient — no conversion
to a full TypeBox tree is needed, and the LLM now sees every tool's
real parameter names.
If you ever need to re-loosen the schema for debugging, fall back to
the `Type.Object({}, { additionalProperties: true })` default only for
that specific tool, not globally.
## Keybindings (mosh/tmux newline fix)
`keybindings.json` is symlinked so edits flow through git. Default:
```json
{
"tui.input.newLine": ["shift+enter", "ctrl+j", "alt+j"]
}
```
Rationale: when pi runs over `kitty → mosh → tmux`, shift+enter doesn't
forward cleanly (mosh uses vt220-ish emulation, no kitty-keyboard-protocol
or csi-u extended keys). `ctrl+j` and `alt+j` pass through as plain
control/meta bytes and give you reliable newline insertion.
## Settings template (start pi without `--model`)
`settings.example.json` is a template — **not symlinked**. pi rewrites
its `settings.json` at runtime (`lastChangelogVersion` bumps on upgrade),
which would dirty a symlinked repo file. Instead, bootstrap with:
```bash
cp /path/to/mempalace-toolkit/extensions/pi/settings.example.json \
~/.pi/agent/settings.json
$EDITOR ~/.pi/agent/settings.json
```
The Bedrock inference-profile prefix on model IDs (`eu.`, `us.`) is
**region-specific** and must match `AWS_REGION` in `~/.config/pi/.env`.
For a bare Anthropic provider (non-Bedrock) drop the prefix entirely
and use `anthropic:claude-...`. Run `pi --list-models` to confirm what
your credentials can actually invoke.
`install.sh` warns (non-fatal) if `settings.json` is missing.
## Environment setup
pi with `defaultProvider=amazon-bedrock` needs `AWS_PROFILE` and
`AWS_REGION` exported into the shell that launches it. Recommended
layout (matches the tor-ms22 dotfiles pattern):
```
~/.config/pi/.env ← AWS_PROFILE=..., AWS_REGION=...
(git-crypt encrypted in dotfiles repo)
~/.oh-my-zsh/custom/pi-env.zsh ← set -a; source ~/.config/pi/.env; set +a
```
Historical note: these vars used to live under a `# Environment variables
for pi` block inside `~/.config/opencode/.env`. Split out 2026-05-05 so
each tool owns its own env file. `install.sh` runs a `check_aws_env`
probe that warns if the vars are missing and points back here.
## File layout
```
mempalace-toolkit/
└── extensions/
└── pi/
├── README.md ← this file
├── mempalace.ts ← symlinked into ~/.pi/agent/extensions/
├── keybindings.json ← symlinked into ~/.pi/agent/
└── settings.example.json ← template; copy + edit into ~/.pi/agent/
```
`install.sh` detects pi by probing for `~/.pi/agent/extensions/` and
only creates symlinks when that directory exists. On machines without
pi the files stay dormant in the repo. Re-runs are idempotent (same
pattern as `bin/` and `SKILL.md`).