Files
joakimp ce09d25c97 Rename to @earendil-works/pi-coding-agent + earendil-works/pi URL
Pi moved to its new home at earendil-works on 2026-05-07
(https://pi.dev/news/2026/5/7/pi-has-a-new-home).

Sweep:
- extensions/pi/mempalace.ts: 'import type { ExtensionAPI } from
  "@mariozechner/pi-coding-agent"' -> @earendil-works/pi-coding-agent.
- README and extensions/pi/README: github.com/mariozechner/pi-coding-agent
  URL refs -> github.com/earendil-works/pi.
- install.sh: same URL substitution in the user-facing pointer line.

Brew install references (`brew install pi-coding-agent`) left as-is:
formula still works at 0.73.1, tap update tracked upstream at
earendil-works/pi#2755.
2026-05-09 17:56:46 +02:00

207 lines
7.5 KiB
Markdown

# pi ↔ MemPalace MCP bridge
The canonical source of `~/.pi/agent/extensions/mempalace.ts` — the TypeScript
extension that wires [MemPalace](https://github.com/MemPalace/mempalace)'s MCP
server into the [pi coding-agent](https://github.com/earendil-works/pi)
harness. Installs wake-up context injection, per-tool schema passthrough,
and a `/mempalace-diary` slash-command.
This directory **only** holds the bridge. Pi's own base config (keybindings,
environment loader, settings template) lives in the sibling
[`pi-toolkit`](https://gitea.jordbo.se/joakimp/pi-toolkit) repo — split out
2026-05-05 so [`opencode-devbox`](https://gitea.jordbo.se/joakimp/opencode-devbox)
can build slim containers that include pi without dragging in mempalace's
dependencies (~300 MB).
**Jump to:**
- [What it does](#what-it-does)
- [The `Type.Unsafe` gotcha](#the-typeunsafe-gotcha)
- [Deploying pi with mempalace on a new machine](#deploying-pi-with-mempalace-on-a-new-machine)
- [Fail-soft, identity, debugging](#fail-soft)
---
## 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.
---
## Deploying pi with mempalace on a new machine
This is the "pi + memory" recipe. For pi without mempalace, see
[`pi-toolkit`'s README](https://gitea.jordbo.se/joakimp/pi-toolkit/src/branch/main/README.md#deploying-pi-on-a-new-machine).
### 0. Prerequisites
- Shell: zsh + oh-my-zsh recommended (both toolkits install loaders into
`~/.oh-my-zsh/custom/`; bash works too, installers print the manual
`source` snippet).
- `git`, `node` ≥ 20, `uv`, `tmux` ≥ 3.2, pi installed upstream.
- AWS credentials reachable via `AWS_PROFILE` — only if using
`amazon-bedrock` as pi's provider.
### 1. Dotfiles (if you keep one)
Brings `~/.config/pi/.env` (AWS creds, git-crypt encrypted), tmux CSI-u
extended keys, and other machine state:
```bash
git clone <your-dotfiles> ~/src/dotfiles
cd ~/src/dotfiles
git-crypt unlock <key>
./provision.sh --profile <profile> # or your equivalent tool
```
### 2. Install pi upstream
```bash
brew install pi-coding-agent # macOS
# or see https://github.com/earendil-works/pi for Linux
pi --help # creates ~/.pi/agent/
```
### 3. Install pi-toolkit (base pi config)
```bash
git clone ssh://git@gitea.jordbo.se:2222/joakimp/pi-toolkit.git ~/pi-toolkit
cd ~/pi-toolkit && ./install.sh
```
Symlinks `keybindings.json`, copies `pi-env.zsh` into
`~/.oh-my-zsh/custom/`, and prints the `settings.json` bootstrap command.
### 4. Bootstrap pi settings
```bash
cp ~/pi-toolkit/settings.example.json ~/.pi/agent/settings.json
$EDITOR ~/.pi/agent/settings.json # eu./us./anthropic: prefix
```
### 5. Install mempalace CLI + this toolkit
```bash
uv tool install mempalace
git clone ssh://git@gitea.jordbo.se:2222/joakimp/mempalace-toolkit.git ~/mempalace-toolkit
cd ~/mempalace-toolkit && ./install.sh
```
Detects pi, symlinks `mempalace.ts` into `~/.pi/agent/extensions/`.
Also detects pi-toolkit artifacts and prints a green check (or a warning
telling you to install pi-toolkit first if you skipped step 3).
### 6. Register mempalace MCP with opencode (if applicable)
Skip if this box is pi-only. Otherwise:
- Install [`opencode-toolkit`](https://gitea.jordbo.se/joakimp/opencode-toolkit) so `~/.config/opencode/.env` is sourced into every shell (GitHub / Gitea / other MCP server tokens).
- Register the mempalace MCP server in `~/.config/opencode/opencode.json` — see [root README § Registering mempalace with opencode](../../README.md#registering-mempalace-with-opencode-or-other-mcp-clients).
### 7. First run
```bash
exec zsh
pi # should start with defaults; wake-up injection shows palace status
```
If the wake-up doesn't print, run `MEMPALACE_EXT_DEBUG=1 pi` to surface
`mempalace-mcp` stderr.
### Verification checklist
```bash
# MCP bridge in place
ls -la ~/.pi/agent/extensions/mempalace.ts # → this repo
# pi-toolkit artifacts also in place
ls -la ~/.pi/agent/keybindings.json # → pi-toolkit
ls -la ~/.oh-my-zsh/custom/pi-env.zsh # cp from pi-toolkit
# Env loaded
zsh -ic 'echo $AWS_PROFILE $AWS_REGION'
# Palace reachable
mempalace status
```
### Uninstall
```bash
cd ~/mempalace-toolkit && ./install.sh --uninstall --yes # bridge only
cd ~/pi-toolkit && ./install.sh --uninstall --yes # pi base config
# Leaves pi itself, mempalace CLI, and ~/.config/pi/.env alone.
```
---
## File layout
```
mempalace-toolkit/
└── extensions/
└── pi/
├── README.md ← this file
└── mempalace.ts ← symlinked into ~/.pi/agent/extensions/
```
Pi base config (keybindings, env loader, settings template) lives in
[`pi-toolkit`](https://gitea.jordbo.se/joakimp/pi-toolkit). `install.sh`
detects pi via `~/.pi/agent/extensions/` and runs a `check_pi_toolkit`
probe that warns if pi-toolkit's artifacts are missing.