The pi coding-agent extension at ~/.pi/agent/extensions/mempalace.ts was living only on tor-ms22, including hand-edited fixes (Type.Unsafe schema-passthrough for MCP tool parameters). One disk wipe away from losing it, and no way to reproduce the install on a new machine. - extensions/pi/mempalace.ts: canonical copy (matches tor-ms22 byte-for-byte) - extensions/pi/README.md: what it does, the schema-passthrough gotcha, debugging knobs - install.sh: new install_pi_extension step — gated on ~/.pi/agent/extensions/ existing, backs up any real file in the way, idempotent re-runs, mirror block in uninstall. Works on macOS and Linux (plain ln -s, readlink -f). - README.md: mention extensions/pi/ in the repo-contents list and in the Setup section Verified on tor-ms22: install (backs up existing real file) → uninstall (removes symlink) → reinstall (clean symlink). Re-runs are no-ops.
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).
What it does
- Spawns
mempalace-mcpas a subprocess and does the MCP stdio JSON-RPC handshake (initialize+notifications/initialized+tools/list). - Registers each MCP tool as a pi tool with its real
inputSchemapassed through viaType.Unsafe(...)(see gotcha below). - Wake-up auto-injection (
before_agent_start, one-shot per fresh session): callsmempalace_status+mempalace_diary_readand injects the result as amempalace-wakeupsystem message so the agent orients itself the way~/.agents/skills/mempalace/SKILL.mddescribes. Skipped on resume/fork (context is already in the thread). - Manual wind-down via a
/mempalace-diary [topic]slash command: sends a prompt asking the LLM to callmempalace_diary_writewith an AAAK-formatted entry summarizing the session. Not fully auto because pi sessions are typically short/tactical andsession_shutdownfires 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— surfacemempalace-mcpstderr 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-mcpmanually 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.
File layout
mempalace-toolkit/
└── extensions/
└── pi/
├── README.md ← this file
└── mempalace.ts ← symlinked into ~/.pi/agent/extensions/
install.sh detects pi by probing for ~/.pi/agent/extensions/ and
only creates the symlink when that directory exists. On machines
without pi the file stays dormant in the repo. Re-runs are idempotent
(same pattern as bin/ and SKILL.md).