Commit Graph

13 Commits

Author SHA1 Message Date
Joakim Persson a94eb7fdd0 docs: native pi has no .env to flip, and EMB-7KJ4VR4G has no native pi
Follow-up to ec436ed, closing the one item that commit left as "unverified".

Verified on the EMB-7KJ4VR4G host: native pi is not installed at all -- no `pi`
or `mempalace` on PATH, no ~/.config/pi/, no ~/.pi/agent/extensions/. That
host's ~/.mempalace exists solely to back the devbox container through the bind
mount (.devbox-owner holds 1000:1000). So the 2026-08-14 flip covers every pi
on that machine and there is no split-brain to fix. The general hazard stays
documented, because it is a per-machine question.

Also documents how a native install *would* be flipped, since the obvious guess
is wrong: pi loads no dotenv file and has no `env` block in settings.json, and
the extension reads process.env only. The launching shell is the sole hook, so
the vars must be exported from a shell rc (a GUI-launched pi may not read one),
and ~/.config/pi/.env is not sourced by anything automatically.
2026-08-14 23:00:46 +02:00
Joakim Persson ec436ed3ad docs: reconcile the RFC-001 docs with what is actually deployed
Audit of every doc touching the global-palace rollout against the running
fleet. Each correction below was verified against the filesystem or the host,
not against another doc:

- synlig-primary-runbook: the decommission `rm -rf ~/.mempalace` now carries a
  STOP block. That tree holds the fleet palace *and* the only copy of the
  bearer token every client authenticates with; the old "empty today" comment
  stopped being true when the palace was seeded on 2026-08-14. Adds an ordered
  safe decommission, and drops count-based join verification.

- phase-1-exposure-runbook: new S3.8, how to verify a flip actually took --
  the procedure that until now existed only in an untracked handover file.
  Three claims that fail independently (env var / curl / the palace-path
  discriminator) plus an explicit list of checks that produce FALSE POSITIVES:
  drawer counts (both sides were seeded from the same palace, and `status`
  counts chunks not drawers), write-then-read through the same transport, and
  the `mempalace` CLI -- which has no remote support at all, so post-flip it
  reads the dead local archive and reports success.

- rfc-001: status Draft -> Phases 0-1 implemented. Records that the join was a
  file-level copy, which SIDESTEPPED the S7.6 diary-dedup question rather than
  answering it -- so S7.6 remains a hard blocker for the second machine, which
  is the one that will actually exercise merge semantics.

- ARCHITECTURE, SKILL, contrib/README, extensions/pi/README all claimed pi
  feeds the palace automatically, unconditionally. That is gated on
  mempalace-toolkit >= 29e660e and every deployed image predates it, so the
  claim is currently false fleet-wide. Each site now states the gate plus a
  check that inspects the *deployed* file rather than repo HEAD.

- extensions/pi/README: plaintext http://mempalace.lan example -> https
  endpoint; the two transports are either/or (no dual-write, no local mirror);
  the bridge fails CLOSED, so "the agent has no mempalace_* tools" is the
  expected symptom of a server/token/DNS fault, not of a broken install.

- contrib/README: documents mempalace-serve.service, which this directory has
  shipped since day one without explaining it (linger, the load-bearing
  172.17.0.1 bind and why loopback is the unsafe-looking-safe option, the
  token path, and an uninstall warning).

- Fixes a pre-existing stray ```sh fence that was swallowing S3.2's heading and
  the token command into a code block.

Docs only; no behaviour change.
2026-08-14 22:57:22 +02:00
Joakim Persson 29e660e18f feeders: stage beside the palace, not in ~/.cache; document Phase 1 exposure
Staging default moves out of ~/.cache to <palace-root>/pi-stage (pi) and
<palace-root>/opencode-stage (opencode), resolved with mempalace's own
palace-path precedence ($MEMPALACE_PALACE_PATH -> $MEMPAL_PALACE_PATH ->
~/.mempalace/config.json -> ~/.mempalace/palace), then dirname.

Why: the convos miner keys dedup on the *staged* path, so a wiped stage plus a
sync scoped to include it prunes the drawers mined from those sources --
deleting memories, not a cache. Under ~/.cache that state was reachable by
anything treating a cache as disposable. Staging inside the palace makes the
coupling structural: the stage cannot be wiped without touching the palace
itself. Overrides ($MEMPALACE_PI_STAGE / $MEMPALACE_SESSION_STAGE, --stage) are
unchanged. Note the old default had never been created on any host, so this
closed a latent hazard, not a live one.

Measured, and the docs now claim only this much: sync prunes only within the
scope it is given -- wing-only, 1299 scanned / 1299 out of scope / 0 removed;
scoped at the palace root, 651 kept / 648 out of scope. The previous blanket
"sync prunes every drawer" wording overstated it, which is a liability: the next
reader disproves the overstatement and discards the real constraint with it.

Also in this change:
- cron log dir ~/.cache/mempalace-session -> ~/.cache/mempalace-logs. The stage
  left that namespace, so the old name now read as "the stage".
- AGENTS.md: the convos miner *does* check mtime (verified against upstream
  convo_miner.py); the previous "no mtime check" claim was wrong.
- smoke-test assertions use `mktemp -d` for --sessions-dir. One pointed at /tmp,
  which still held earlier synthetic transcripts, so a --dry-run exported a fake
  session into the real stage: --dry-run skips the mine, not the export.

docs/phase-1-exposure-runbook.md -- the newt/DNS/auth step that RFC 001 and the
synlig runbook leave open (runbook section 4, items 2 and 5). Port 8765 at /mcp,
newt targets 172.17.0.1, and the authentication is the single shared bearer
token (RFC 6.2, decided 2026-08-09) rather than per-device proxy users. The
latter cannot work today: mempalace validates exactly one token, and Pangolin's
SSO/PIN/password are browser-shaped while every client here is a headless
JSON-RPC POST -- enabling that protection breaks the clients it protects. The
per-device axis that *does* exist is the feeder's SSH key + per-device inbox.

New finding recorded there: a loopback bind does not merely 403 behind a tunnel
(already known, runbook 2.4) -- it also silently starts the server with no token
at all, because auto-minting is gated on the bind being non-loopback.

extensions/pi/README.md: the HTTP transport IS authenticated as of mempalace
3.6.0; the "sessionless and unauthenticated" note dated from the v1.3.0 era.
Closes the RFC section 8 Phase-0 hygiene item.
2026-08-12 17:04:01 +02:00
pi 96699f2a17 feat(pi-bridge): external MemPalace transport via MEMPALACE_REMOTE_URL
Let the pi<->mempalace bridge connect to a shared MemPalace over HTTP instead
of always spawning a local mempalace-mcp:
- Extract IMcpClient; rename McpClient -> StdioMcpClient (ctor command, arg-less start()).
- Add RemoteMcpClient (vendored from pi-extensions/mcp-loader.ts): streamable-HTTP
  with AbortController timeouts, protocolVersion pinned 2024-11-05, alive/ensureAlive.
  mempalace-mcp --transport http is sessionless JSON-RPC today; session/SSE/404
  branches retained for a future streamable-HTTP server.
- createClient() selects transport from MEMPALACE_REMOTE_URL; MEMPALACE_REMOTE_TOKEN
  -> Authorization: Bearer. Lifecycle automation (wake-up, /mempalace-diary) unchanged.
- scripts/check-mcp-client-sync.sh: drift guard vs canonical mcp-loader.ts.
- README: document local-vs-external transport.

Typechecks clean (strict); both transports smoke-tested against live mempalace-mcp.
2026-07-02 13:09:29 +02:00
pi e12b624cf7 feat(pi-ext): self-healing respawn + scoped init timeout for mempalace-mcp
A stall-kill (or any crash) of mempalace-mcp was a permanent latch:
available flipped off and stayed off until pi restart. Now the next tool
call transparently respawns the server and retries.

- ensureAlive(): bounded respawn with capped exponential backoff
  (MEMPALACE_MCP_MAX_RESPAWNS, default 2; MEMPALACE_MCP_RESPAWN_BACKOFF_MS,
  default 1000). Respawn budget resets on any successful JSON-RPC response,
  so a recovered server regains full patience while a persistently-broken
  one hits the cap and stays down (no hot-loop).
- Init timeout default raised 120000 -> 300000 (scoped to init only): a
  genuine virtiofs cold-open shouldn't be killed mid-progress only to
  respawn and re-pay the same cost. Per-call timeout stays 60000.
- Concurrency hardening: generation counter so a late exit from a killed
  old process can't tear down a fresh respawn; explicit healthy flag
  replaces racy proc!=null liveness check.
- README: document self-heal, new env vars, and why generous-init +
  bounded-respawn compose rather than overlap.
2026-06-26 00:22:21 +02:00
joakimp a3b8829991 feat(pi-ext): per-request timeout + stall-kill for mempalace-mcp
A wedged mempalace-mcp (classically an OrbStack virtiofs cold-open of a
large chroma.sqlite3 / HNSW load) left the awaiting JSON-RPC promise
pending forever, freezing the pi TUI uninterruptibly: ESC cancels the
LLM stream, not a pending tool execute().

The JSON-RPC client now arms a per-request timer. On expiry it rejects
the request AND kills the stalled child (SIGTERM->SIGKILL), so pi gets
an error instead of hanging; the extension flips available=false so
later calls fail fast (restart pi to retry). Per-REQUEST, not
per-process: the long-lived server only dies on a genuine stall.

Knobs: MEMPALACE_MCP_TIMEOUT_MS (default 60000),
MEMPALACE_MCP_INIT_TIMEOUT_MS (default 120000), 0 = disable.

This supersedes the planned standalone stdio-watchdog shim: the
extension already owns request/response correlation, so a separate
framing-reparsing shim is unnecessary.
2026-06-13 23:48:33 +02:00
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
joakimp 16915f0e55 refactor: split pi-generic config into pi-toolkit repo
Parallel to the opencode-toolkit split earlier today. Pi's own config
(keybindings, shell env loader, settings template) moves to a new
sibling repo so opencode-devbox's mempalace opt-out can build slim
containers that include pi without dragging in chromadb + embedding
models (~300 MB).

What moved to pi-toolkit (https://gitea.jordbo.se/joakimp/pi-toolkit):
- extensions/pi/keybindings.json          (mosh/tmux newline fix)
- extensions/pi/pi-env.zsh                (sources ~/.config/pi/.env)
- extensions/pi/settings.example.json     (Bedrock template)
- install.sh::install_pi_keybindings      (symlink step)
- install.sh::install_pi_env_loader       (cp step + bash fallback)
- install.sh::check_pi_settings           (probe)
- install.sh::check_aws_env               (probe)

What stays here (this is the pi\u2194mempalace bridge, mempalace-side):
- extensions/pi/mempalace.ts              (the MCP extension)
- install.sh::install_pi_extension        (symlink step)
- NEW: install.sh::check_pi_toolkit       (probe: warns if pi is
                                           installed but pi-toolkit's
                                           artifacts are missing, with
                                           git-clone pointer)

install.sh shrank from 520 to 403 lines. Uninstall mirror correctly
does NOT touch pi-toolkit-owned files (explicit comment).

Docs updated:
- extensions/pi/README.md: rewritten as 'pi\u2194MemPalace MCP bridge',
  recipe becomes 'Deploying pi with mempalace' (pi-toolkit step 3,
  this repo step 5).
- AGENTS.md: Structure block + 'What install.sh does' section reflect
  the narrower scope and list the four things that moved out.
- README.md: repo-contents line + Setup section's deploy summary.

Verified on tor-ms22: full install\u2192uninstall\u2192reinstall lifecycle clean.
After mempalace-toolkit uninstall, pi-toolkit artifacts
(~/.pi/agent/keybindings.json, ~/.oh-my-zsh/custom/pi-env.zsh) remain
intact \u2014 correctly untouched. check_pi_toolkit probe fires green when
both exist.
2026-05-05 17:26:53 +02:00
joakimp 3d3a0fb125 docs(pi): add opencode-toolkit pointer in deploy recipe step 6
Cross-reference the newly-extracted opencode-toolkit repo, which owns
~/.config/opencode/.env loading. The recipe now distinguishes between
registering mempalace in opencode.json (still this repo's concern) and
ensuring opencode's own env loader is in place (opencode-toolkit's).
2026-05-05 17:14:32 +02:00
joakimp 118bd20fec feat(extensions/pi): ship pi-env.zsh shell loader
The loader that sources ~/.config/pi/.env into every shell was only
living in the myconfigs tor-ms22 backup \u2014 a fresh machine had nowhere
to get it from except copying by hand. Now canonical here.

- extensions/pi/pi-env.zsh: 20-line POSIX-compatible loader
  (set -a; source ~/.config/pi/.env; set +a). Works in bash and zsh.
- install.sh install_pi_env_loader:
  * oh-my-zsh detected (~/.oh-my-zsh/custom/ exists)
    \u2192 cp into that dir (NOT symlink \u2014 that dir is typically part of
      a dotfiles backup, and a symlink to mempalace-toolkit would
      break when restored on another host).
    \u2192 Idempotent: if target content matches repo, says 'already
      installed'. If it differs, leaves user edits alone and points
      at diff for manual reconcile.
  * No oh-my-zsh \u2192 prints source-this-line snippet for ~/.zshrc or
    ~/.bashrc (derived from $SHELL). Does NOT auto-edit rc files.
- install.sh uninstall: only removes the copy if content still matches
  repo. Local edits preserved.
- Docs:
  * extensions/pi/README.md Environment setup section rewritten with
    both install paths, step 5 of deploy recipe updated.
  * AGENTS.md Structure block lists pi-env.zsh.
  * Root README repo-contents line mentions it.

Verified on tor-ms22: install fresh \u2192 uninstall (content match \u2192 remove)
\u2192 reinstall \u2192 zsh -ic loads AWS vars correctly. Also tested bash fallback
path via HOME=/tmp/fake-home SHELL=/bin/bash \u2014 prints right .bashrc snippet.
2026-05-05 16:58:56 +02:00
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
joakimp 854ae41f65 feat(extensions/pi): keybindings symlink + settings template + AWS/pi probes
Round out the pi bring-up story so a fresh machine can reach a working
pi+mempalace install with just `git clone && ./install.sh`:

- extensions/pi/keybindings.json: generic mosh/tmux newline fix
  (shift+enter, ctrl+j, alt+j). Safe on any machine — not
  region/account-specific. Symlinked into ~/.pi/agent/.
- extensions/pi/settings.example.json: template for `settings.json`
  so pi can start without --provider/--model. NOT symlinked — pi
  rewrites settings.json at runtime (lastChangelogVersion bumps),
  which would dirty the repo. Installer prints the cp + edit hint.
- install.sh: new install_pi_keybindings + uninstall mirror; new
  check_pi_settings probe (warns if settings.json missing); new
  check_aws_env probe (warns if AWS_PROFILE/AWS_REGION unset and
  settings.json selects amazon-bedrock). All new steps gated on
  pi being installed (~/.pi/agent/extensions/ exists).
- extensions/pi/README.md: documents keybindings rationale,
  settings bootstrap, and the recommended ~/.config/pi/.env +
  ~/.oh-my-zsh/custom/pi-env.zsh env layout (paired with the
  myconfigs commit 884e329 that split AWS vars out of
  ~/.config/opencode/.env).

Verified on tor-ms22: full install → uninstall → reinstall cycle,
new shell loads AWS_PROFILE/AWS_REGION from the new pi-env.zsh hook.

Works on macOS and Linux (plain ln -s, POSIX bash).
2026-05-05 13:59:20 +02:00
joakimp ef1d022fbc feat(extensions): version-control pi mempalace extension + install.sh symlink
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.
2026-05-05 13:42:47 +02:00