Files
mempalace-toolkit/AGENTS.md
T
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

165 lines
10 KiB
Markdown

# AGENTS.md
## What this is
Producer-side tooling for [MemPalace](https://github.com/MemPalace/mempalace). Three thin wrappers in `bin/` (opencode + pi session feeders, a docs miner), a companion agent skill, and an `extensions/` tree with per-harness bridges (currently `pi/`). Pairs with the consumer-side `mempalace` skill.
Read [`ARCHITECTURE.md`](ARCHITECTURE.md) first — it's the canonical spec for what this repo does and why.
## Structure
```
install.sh # Idempotent installer — see "What install.sh does" below
ARCHITECTURE.md # Canonical spec: diagrams, setup recipe, ops notes, upstream roadmap
README.md # Human-facing quickstart + per-tool usage reference
SKILL.md # Agent skill (symlinked into ~/.agents/skills/ on install)
bin/
mempalace-docs # Docs-only MemPalace miner (bash wrapper)
mempalace-session # Opencode session → MemPalace bridge (bash + inline Python)
mempalace-pi-session # pi session → MemPalace bridge (bash + inline Python)
contrib/ # systemd / launchd / cron templates for scheduling feeders
extensions/
pi/ # pi coding-agent bring-up: MCP bridge, keybindings, settings template
mempalace.ts # Symlinked into ~/.pi/agent/extensions/ (MCP <→ pi glue)
keybindings.json # Symlinked into ~/.pi/agent/ (mosh/tmux newline fix)
pi-env.zsh # Copied into ~/.oh-my-zsh/custom/ or sourced from .bashrc (loads ~/.config/pi/.env)
settings.example.json # Template; user copies + edits (pi rewrites settings.json at runtime)
README.md # Extension internals, schema-passthrough gotcha, env setup
```
## What `install.sh` does
Idempotent, safe to re-run. Always:
- Symlinks `bin/*` into `~/.local/bin/`.
- Creates `~/.agents/skills/opencode-mempalace-bridge/` with a `SKILL.md` symlink and a `.skill-source` marker.
Gated on pi being installed (`~/.pi/agent/extensions/` exists):
- Symlinks `extensions/pi/mempalace.ts` into `~/.pi/agent/extensions/`. Backs up any real file in the way.
- Symlinks `extensions/pi/keybindings.json` into `~/.pi/agent/`. Backs up any real file in the way.
- `settings.example.json` is **not** symlinked — pi rewrites `settings.json` at runtime, so we'd dirty the repo. Installer warns if `settings.json` is missing and prints the `cp` command.
Probes (never halt, `warn` + `return 0`):
- `~/.local/bin` is on `$PATH`.
- `~/.config/opencode/instructions/mempalace.md` exists (opencode wake-up protocol).
- `mempalace` is registered as an MCP server in `~/.config/opencode/opencode.json`.
- `~/.pi/agent/settings.json` exists (if pi is installed).
- `AWS_PROFILE`/`AWS_REGION` set, but only if `settings.json` exists *and* selects `amazon-bedrock`. Silent otherwise.
All non-destructive: if something is already in place and points into this repo, prints "already linked" and moves on. If a non-symlink real file is in the way, backs it up with a timestamp.
## Conventions
- **Standalone executables** in `bin/` with `#!/usr/bin/env bash` shebang, no extension, `chmod +x`. Must work in non-interactive contexts (agent processes, cron, CI).
- **Thin wrappers only.** Neither tool reimplements the mempalace miner. Both follow the **stage-to-cache-then-mine** idiom: curate input to `~/.cache/…/<wing>/`, then delegate to `mempalace mine`.
- **Idempotent + dry-runnable.** Every tool supports `--dry-run`. Second invocation on unchanged input is a no-op (dedup via `source_file` path, optionally + `mtime`).
- **No external Python deps.** Stdlib only (`sqlite3`, `json`, `pathlib`). Inline in the bash wrapper via heredoc.
- Argument parsing: `--help`/`-h` first, then mode flags, then positional args.
- Comment sections use `# ── Section Name ──────` style (matches sibling `cli_utils` repo).
## Adding a new wrapper
Three wrappers live happily as standalone scripts — no shared helper library yet, because each one's stage-to-cache logic differs enough that the common surface is thin (arg parsing + `mempalace mine` invocation). A fourth wrapper might tip the balance; re-evaluate then. Until then, copy the pattern from `mempalace-session` (richest example):
1. Create `bin/<name>` with `#!/usr/bin/env bash` + `chmod +x`.
2. Implement `--help`, `--dry-run`, `--repair` flags (repair is opt-in; `--no-repair` kept as deprecated alias).
3. Stage to `~/.cache/<name>/<wing>/` with deterministic filenames.
4. Invoke `mempalace mine ...` (choose `--mode convos` if input is chat-like).
5. Do NOT end with `mempalace repair` unless `--repair` was explicitly passed. Repair is a destructive in-place HNSW rebuild and must never run on an unattended schedule.
6. Update `README.md` with usage + rationale.
7. Update `install.sh`? No — `bin/*` is auto-linked.
8. Update `ARCHITECTURE.md` if the wrapper fills a new architectural gap.
9. Update `SKILL.md` if agents should know when to invoke it.
## Adding a new harness extension
`extensions/<harness>/` is the home for per-agent-harness bridges — code that
lives inside an agent runtime (pi, claude-code, kiro, …) and talks to the
mempalace MCP server. Currently only `extensions/pi/` exists. If you add
a second one (e.g. `extensions/claude-code/`), follow the same shape:
1. **One directory per harness.** Never mix harnesses in one dir.
2. **A `README.md`** covering: what it does, harness-specific install path,
debug knobs, and any gotchas (e.g. the pi `Type.Unsafe` schema passthrough).
3. **Symlink what's safe to symlink, template what the harness rewrites.**
Pi rewrites `~/.pi/agent/settings.json` at runtime — shipped as
`settings.example.json` with a `cp` instruction, not a symlink, to avoid
dirtying the repo. Whereas `mempalace.ts` and `keybindings.json` are
pure config, safe to symlink.
4. **Gate `install.sh` steps on the harness being present.** Detect via
a well-known path (pi uses `~/.pi/agent/extensions/`). Skip silently on
machines without that harness. Never force-install.
5. **Back up real files, never clobber.** If a destination exists and isn't
our symlink, `mv` it to `<path>.bak.YYYYMMDD-HHMMSS` before linking.
6. **Probe, don't halt.** Any harness-specific env / config checks use
`warn` + `return 0`, never exit non-zero. Gate on evidence the user
actually opted into the affected path (e.g. AWS probe only fires if
`settings.json` selects `amazon-bedrock`).
7. **Mirror in `--uninstall`.** Every symlink this repo creates must have
a matching removal step guarded by `link_if_into_repo`.
8. **Update the root `README.md`** — add to the "What this repo contains"
list and to Setup with a one-line pointer to the extension's own README.
9. **Update this file's Structure block** to list the new `extensions/<harness>/`
contents.
See `extensions/pi/README.md` and the `install_pi_extension` /
`install_pi_keybindings` / `check_pi_settings` / `check_aws_env` functions
in `install.sh` for a full worked example.
## Testing
Manual only. Integration-shaped:
```bash
# Smoke test — does it parse args and list what would happen?
./bin/mempalace-session --help
./bin/mempalace-session --dry-run
# Real test on a single session (safe, deterministic)
./bin/mempalace-session --session ses_<id> --dry-run
./bin/mempalace-session --session ses_<id> # file into palace
mempalace_search "a phrase from that session" # verify visibility
./bin/mempalace-session --session ses_<id> # re-run → should skip
```
For `mempalace-docs`, test on a small repo (e.g. this one) first:
```bash
./bin/mempalace-docs "$PWD" --dry-run
```
## Gotchas
- `install.sh` is idempotent but interactive — use `--yes` in non-interactive contexts.
- `~/.local/bin` must be on `$PATH`. The installer warns if not.
- The companion skill lives at `~/.agents/skills/opencode-mempalace-bridge/SKILL.md` and is a **symlink into this repo**. Editing that file edits `SKILL.md` here. To propagate to Claude Code / Kiro, run `agents-sync` from [`cli_utils`](https://gitea.jordbo.se/joakimp/cli_utils).
- The opencode DB path defaults to `~/.local/share/opencode/opencode.db`. Override via `$OPENCODE_DB` or `--db`.
- The mempalace miner **skips symlinks** (as of v3.3.3 — `miner.py` line ~828). That's why the wrappers use `cp -p` / explicit file writes for staging, not symlinks.
- The convos miner dedups on `source_file` path only (no mtime check). Staging filenames must be stable per session; deleting a staged JSONL forces a re-mine.
- The docs miner dedups on `source_file` path + `mtime`. That's why staging uses `cp -p` (preserves mtime).
## Colocated skill pattern
This repo owns an agent skill (`SKILL.md`) that lives alongside the code it documents, rather than in a central skills repo like [`skillset`](https://gitea.jordbo.se/joakimp/skillset). The advantages: the skill moves in lockstep with the wrappers it explains, one `git clone` gets you the full producer-side setup, and retirement (when upstream gaps close) removes skill + code + docs in one commit.
The convention for making this coexist cleanly with sibling tooling:
1. **`install.sh` creates `~/.agents/skills/<name>/` as a real directory** containing a `SKILL.md` symlink back into this repo. It does **not** create a dir-symlink, because real dirs are the signal that sibling reconcilers (skillset's `deploy-skills.sh`, cli_utils's `agents-sync.zsh`) should leave the dir alone.
2. **`install.sh` drops a `.skill-source` marker file** at the root of the skill dir:
```
# skill-source: mempalace-toolkit
# repo: <absolute path>
# url: ssh://git@gitea.jordbo.se:2222/joakimp/mempalace-toolkit.git
```
This is a breadcrumb for humans and future tooling — it answers "who owns this skill dir?" at a glance. `deploy-skills.sh` and `agents-sync.zsh` don't read it today (their existing logic already handles external dirs correctly) but may surface it in status reports later.
3. **`install.sh --uninstall` removes the marker** (only if it still says `mempalace-toolkit`) and the now-empty skill dir.
If you add a third colocated skill from a new repo, follow the same convention. The marker format is shared; only the repo name changes.
## History
Split out from [`cli_utils`](https://gitea.jordbo.se/joakimp/cli_utils) on 2026-04-30. The wrappers originated there but the conceptual fit was weak (`cli_utils` is interactive shell tools; these are agent memory infrastructure). Some older diary entries and KG facts in the palace reference the original paths.