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

10 KiB

pi ↔ MemPalace extension

The canonical source of ~/.pi/agent/extensions/mempalace.ts — the bridge that wires the MemPalace MCP server into the 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

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. 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:

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)

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

# 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)

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:

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.

7. First run

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

# 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

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:

{
  "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:

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).