# Rembric — agent plugins Memory for AI coding agents, backed by your self-hosted [Rembric](https://github.com/susomejias/rembric) server. One source tree, five per-client surfaces. **Install everything with the TUI.** The single installer prepares the server and installs / updates / uninstalls every client plugin, detecting what you have and at which version: ```bash # inspect-first (recommended); or pipe straight to sh curl -fsSL https://raw.githubusercontent.com/susomejias/rembric/main/install.sh -o rembric-install.sh less rembric-install.sh && sh rembric-install.sh ``` It is an orchestrator — opencode uses its scripts, Claude/Codex their marketplace CLIs, Pi its registry CLI, and Hermes its native Git-subdirectory plugin manager. Hermes mutations reject explicit refs and local-source overrides; explicit TUI update offers recognized legacy copies a separately confirmed stopped-host migration with verified backup and native reinstall, never forced replacement. Hermes owns provider/plugin selection and grants, and removal deletes its entire managed directory while preserving unrelated settings, MCP pins and external credentials. [Hermes transition and update-check limitations](./.hermes-plugin/README.md#transition-from-a-copied-installation). | Client | Manifest dir | Docs | | ---------------- | ------------------- | -------------------------------------------------------------------------- | | **Claude Code** | `.claude-plugin/` | this file | | **Codex CLI** | `.codex-plugin/` | [`docs/agents.md`](../docs/agents.md#codex-cli-recommended-bundled-plugin) | | **Hermes Agent** | `.hermes-plugin/` | [`apps/plugin/.hermes-plugin/README.md`](./.hermes-plugin/README.md) | | **opencode** | `.opencode-plugin/` | [`apps/plugin/.opencode-plugin/README.md`](./.opencode-plugin/README.md) | | **Pi** | `.pi-plugin/` | [`apps/plugin/.pi-plugin/README.md`](./.pi-plugin/README.md) |
Manual install (per-client, fallback — what the TUI runs under the hood) | Client | Manual command | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Claude Code** | `claude plugin marketplace add https://github.com/susomejias/rembric.git && claude plugin install rembric@rembric` | | **Codex CLI** | `codex plugin marketplace add https://github.com/susomejias/rembric.git && codex plugin add rembric@rembric` | | **Hermes Agent** | `hermes plugins install susomejias/rembric/apps/plugin/.hermes-plugin --enable` | | **opencode** | `curl -fsSL https://raw.githubusercontent.com/susomejias/rembric/main/apps/plugin/.opencode-plugin/install.sh \| sh`, export `REMBRIC_SERVER_URL` + `REMBRIC_API_TOKEN`, then restart | | **Pi** | `pi install npm:@rembric/pi` then export `REMBRIC_SERVER_URL` + `REMBRIC_API_TOKEN` in your shell. Never append a version — a pinned spec is skipped by `pi update --extensions` / `--all` |
The rest of this file is the Claude Code plugin reference. For Codex see [`docs/agents.md`](../docs/agents.md). For Hermes see [`plugin/.hermes-plugin/README.md`](./.hermes-plugin/README.md). For opencode see [`plugin/.opencode-plugin/README.md`](./.opencode-plugin/README.md). For Pi see [`plugin/.pi-plugin/README.md`](./.pi-plugin/README.md). > **Using Codex CLI?** Hooks are stable and on by default as of `codex-cli 0.142.3+`; the one-time Codex-side step for hooks to fire is approving the 6 hook types via `/hooks` inside Codex. Full walk-through (including the `REMBRIC_*` shell-env requirement and the symptom-vs-cause troubleshooting table) lives in [`docs/agents.md`](../docs/agents.md#trust-hooks-required). ## Batch tools and recovery All five clients use `memory.get_batch`, `memory.session_get_batch`, `memory.confirm_batch` and `memory.judge_batch`, without old-name aliases. A one-item array replaces an individual read/mutation. Upgrade or roll back server and plugins together, then restart the client for discovery. [Date-based weekly recall, pages and errors](../../docs/agents.md#complete-batch-reads-by-date). Before rewriting a resumed summary, call `memory.session_get_batch({ ids: [sessionId] })` and read `sessions[0]` in full; context snippets are not the stored complete state. Pi registers provider-safe underscore names (e.g. `memory_session_get_batch`) and forwards canonical names and arrays unchanged. ## What you get - **One MCP server** declared automatically — no hand-editing `.mcp.json`, no plaintext tokens in your settings file. The API token lives in your system keychain. - **A zero-dependency stdio bridge** (`mcp-bridge/`) that reads `PROJECT_SLUG` from `.rembric`, path-scopes the MCP URL, and recovers a terminated session without replaying earlier tool calls. - **Four slash commands** under `/rembric:*` — `remember`, `recall`, `context`, `summary`. - **Eight lifecycle hooks** — all `command`-type, all POST to Rembric's HTTP API directly so sessions are tracked regardless of whether the agent remembers to call them: - `SessionStart` (matcher `startup|resume|clear|fork`) reads the host session id from stdin and POSTs `/api//sessions` to register the session (idempotent), then `/api//sessions//resume`, which returns a row a previous run ended (or the sweep abandoned) to `active` so a reopened conversation keeps its memories. Also nudges the agent to load recent context. - `SessionStart` (matcher `compact`) injects a multi-line nudge to read `memory.session_get_batch({ ids: [sessionId] })` / `sessions[0]` in full before rewriting via `memory.session_summary`; use `memory.context` only for missing detail. - `UserPromptSubmit` (matcher on recall keywords) nudges the agent to search before responding. - `UserPromptSubmit` (matcher-less, every prompt) prints, on plain stdout, whatever the previous turn's report cached: the reminder the SERVER composed from the session's own state — a `memory.save` clause when tool work followed the session's last saved memory, and a session-summary refresh when the summary is stale — plus the session-opening line on a newly created session. It counts nothing — the firing decision belongs to the server. - `PreCompact` POSTs the live transcript to `/api//sessions//summary` BEFORE compaction wipes context, so the snapshot survives independent of model cooperation. - `PostCompact` POSTs the model-authored `compaction_summary` (delivered on stdin) directly to `/api//sessions//summary` — the highest-quality summary we can capture. - `Stop` (synchronous, side-effect only) reports the finished turn to `/api//sessions//turn` — whether it invoked a tool, and the first prompt as a provisional title — and caches the reminder lines the server hands back for the next `UserPromptSubmit`. It emits nothing to the model. - `SessionEnd` POSTs `/api//sessions//end` when the session terminates, closing the row cleanly. It and `PreCompact` keep the first-prompt title `Stop` already delivered; they fall back to the first assistant message only when no prompt was ever recorded. Proactive memory protocol ("save after decisions, fixes, conventions, preferences, discoveries") is delivered server-side via the Rembric MCP `initialize.instructions` handshake — it applies to every MCP client (Claude Code plugin, Codex CLI, Cursor, …) automatically, with no per-client skill needed. ## Install Use the TUI installer (top of this file) and pick **Plugins → claude → install** — it runs the marketplace commands below for you and handles updates/uninstall too. ### Manual install (marketplace) ```bash claude plugin marketplace add https://github.com/susomejias/rembric.git claude plugin install rembric@rembric ``` Auth uses your existing git credentials (SSH key or PAT). The repo can stay private — same access pattern as `git clone`. You will be prompted for two values at install time, both required: - **Rembric server URL** — base URL of your deployment, **without the `/mcp` suffix**. The bridge appends `/mcp/` itself. - ✓ Good: `https://memory.example.com`, `http://192.168.1.10:8787` - ✗ Bad: `https://memory.example.com/mcp` - No trailing slash. - **Rembric API token** — issued from the Rembric dashboard at `/dashboard/tokens` (plaintext shown exactly once). Stored in your system keychain (not in `settings.json`). That's it — the `userConfig` values reach the MCP bridge via `${user_config.*}` substitution in `mcp.json::env`, and reach the lifecycle hooks via the `CLAUDE_PLUGIN_OPTION_SERVER_URL`/`CLAUDE_PLUGIN_OPTION_API_TOKEN` environment variables Claude Code injects into every hook subprocess (referencing `${user_config.*}` directly in a hook's shell-form `command` string is rejected — the substituted value would be re-parsed by the shell). No shell exports required. ### Verifying the hooks reach the server After install + restart, open a Claude Code session and check `/dashboard/sessions` on your Rembric deployment. A new row should appear within seconds with `agent=claude-code`. If sessions never appear, fall back to exporting in your shell so we can rule out the substitution path: ```bash # diagnostic fallback — only if the wizard route does not work export REMBRIC_SERVER_URL="https://memory.example.com" export REMBRIC_API_TOKEN="$(security find-generic-password -s rembric -w 2>/dev/null || echo MISSING)" ``` Restart Claude Code and try again. If sessions now appear with the shell exports but not without, the plugin's `CLAUDE_PLUGIN_OPTION_*` env injection is misbehaving — open an issue with the Claude Code version. Either way the hook scripts emit a one-line stderr diagnostic (`[rembric] missing REMBRIC_SERVER_URL or REMBRIC_API_TOKEN; skipping POST ...`) when credentials are missing; `claude --debug` shows them. ### Updating to a new version Claude Code caches plugins by version. When we ship a new `version` in `plugin/.claude-plugin/plugin.json` (e.g. `0.1.0` → `0.2.0`), follow the official update flow: ```shell # 1. Refresh the marketplace catalog so Claude Code sees the new version /plugin marketplace update rembric # 2. Update the installed plugin /plugin update rembric@rembric # 3. Apply the new hooks/scripts without restarting /reload-plugins ``` If `/reload-plugins` is not enough (e.g. when the MCP bridge or `bin/*` changed), restart Claude Code fully so the bridge re-spawns from the new cache. Third-party marketplaces have **auto-update disabled by default**. To opt in, run `/plugin` → **Marketplaces** tab → select rembric → **Enable auto-update**. Then Claude Code refreshes the catalog and updated installed plugins on startup, prompting `/reload-plugins` when something changed. If the version field hasn't been bumped but you know new code shipped (or your environment refuses to pick it up), force a clean reinstall: ```shell /plugin uninstall rembric@rembric /plugin install rembric@rembric ``` You can also blow away the cache directly: `rm -rf ~/.claude/plugins/cache` (Claude Code rebuilds it on next install). For a temporary rollback after a broken release, see the [emergency plugin rollback](../../docs/agents.md#emergency-plugin-rollback) runbook. ### As the plugin author (local iteration) ```bash claude plugin marketplace add ~/path/to/rembric claude plugin install rembric@rembric -s local ``` Reload after edits with `/reload-plugins`. For deep changes (e.g. editing the bridge), restart Claude Code so the MCP transport reattaches. ## Picking the project per repo Drop a `.rembric` file in each project's root with `PROJECT_SLUG=`: ```bash echo "PROJECT_SLUG=my-app-slug" > .rembric ``` Format is dotenv-style (`KEY=VALUE`, `#` for comments). Reserved for future fields (e.g. `DEFAULT_SCOPE=`, `AUTO_SAVE=`) — today only `PROJECT_SLUG` is read. The bridge parses it on every MCP session start and builds the URL `${server_url}/mcp/my-app-slug`. The Rembric server pins the project from the URL path automatically. If `.rembric` is missing, unparseable, or `PROJECT_SLUG` is invalid, the bridge falls back to path-less `/mcp` and writes a diagnostic to stderr (visible in `claude --debug`). The session still works — a path-less connection resolves to the server's default project until the agent pins another with `project.use`. ### Whether to commit `.rembric` - **Commit it** when the whole team should share the same Rembric project for this repo. - **Gitignore it** if each teammate uses their own memory scope. ### Choosing a slug Pick something stable, lowercase, hyphen-separated (`acme-foo`, `my-app-api`). For monorepos, one slug per subproject (`acme-foo-frontend`, `acme-foo-api`). Slugs must match `^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$`. ## Keeping content out of memory: `` tags Wrap anything in `…` and every client — Claude Code, Codex CLI, Hermes Agent, opencode, Pi — replaces the whole span with `[REDACTED]` **before** any transcript-derived text (session summaries, pre/post-compact snapshots, derived titles) leaves your machine: ``` Connect with postgresql://user:s3cret@db.internal/prod and check the row count. ``` is uploaded as `Connect with [REDACTED] and check the row count.` - Matching is case-insensitive and spans newlines; each span closes at the first ``. - An **unclosed** `` redacts through end-of-text — the redaction fails closed, never open. - Redaction is client-side; the marked content never reaches the wire. The server does not strip these tags for you. ## Token budget | What | Cost | When | | ---------------------------- | --------- | ---------------------------------- | | 4 command listings | ≤ 40 tok | always-on (per turn) | | SessionStart nudge (startup) | ~ 20 tok | once per session | | SessionStart nudge (compact) | ~ 120 tok | once per /compact (model-context) | | UserPromptSubmit nudge | ~ 20 tok | per matched prompt | | PreCompact | 0 tok | side effect; no model output | | PostCompact | 0 tok | side effect; no model output | | SessionEnd | 0 tok | side effect; runs after model exit | The proactive-save protocol travels via the MCP `initialize.instructions` (~1 400 chars, paid once per connection by every client) — it does not show up in the plugin's per-turn budget. ## Bridge runtime - **Requires Node 18+** on PATH. Claude Code already needs Node, so this is normally satisfied. - The bridge uses `npx -y @rembric/mcp-bridge@` for the stdio↔HTTP MCP transport. The first launch downloads the pinned package; subsequent launches use npx's cache. Measured cold start to the first MCP frame was **586.7 ms** for the bridge versus **1,895.9 ms** for `mcp-remote@0.1.38`. - The measured session-start transport instrument was **2 requests** for the bridge (`GET /healthz`, `POST /mcp` initialize; **1 ms** to initialize) versus **4** for `mcp-remote` (`GET /mcp` plus three `.well-known` GETs; **25 ms**); the bridge makes zero `.well-known` requests. - One bridge process per MCP session. It forwards host frames verbatim and owns the one-request 404 recovery. ## Notes - This plugin is designed to be the **sole memory layer** for the agent. It does not migrate from or coexist with other memory tools — if one is already installed, uninstall it before enabling this plugin to avoid cross-tool drift. - The plugin is **client-side only** — it does not modify Rembric's server code. - Hook scripts are designed to **never block a session**: any error exits 0 with empty stdout. ## Releases This package is released independently via [release-please](https://github.com/googleapis/release-please) (tag prefix `plugin-v*`), driven by Conventional Commit messages on `main`. **Always merge PRs with "Create a merge commit"**, never "Squash and merge" — a squashed commit's message defaults to the PR title, which release-please cannot parse as a Conventional Commit. A squash merge silently yields zero release commits until a new, real Conventional Commit lands on top of it. ## License MIT, same as the server.