Step 7's live check (#4034 "a real session shows each topic stated once") found nothing copied across surfaces, but found the owner repeating itself: using-scribe said "rules are retrieved; ask before a consequential act; an empty session is not an empty rulebook" in "Do this first", in reflex 2, and twice more further down reflex 2. - using-scribe: reflex 2 now holds the one full statement (how rules arrive, why that is the surface working, what silence means, when to ask). "Do this first" keeps the enter_project step and a short lead-in pointing at reflex 2. "A retrieved rule outranks a default habit" and "Ask hardest where you feel most certain" stay, since each adds something. - Adapter static context: "Lines injected beside your work" keeps only the Claude Code timing and leaves "never the whole set" to the skill. "Keep one copy" names CLAUDE.md and auto-memory and points at using-scribe, which already says to leave a client's settings as they are. - The ownership registry's markers and statement for the topic still sit on using-scribe, and nothing else changed owner. Plugin version minted. Sizes: using-scribe 18,823 -> 18,197 chars; scribe_static_context.md 1,797 -> 1,714. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Scribe plugin for Claude Code
Turns a self-hosted Scribe instance into a first-class Claude Code extension:
- MCP tools over your notes, tasks, projects, milestones, systems, and
rulebook (the
scribeserver). - Session-start push channel — a
SessionStarthook injects the active project's live state (from the server) and this adapter's short Claude Code guidance, so Scribe surfaces without being asked. Rules are never preloaded; they arrive by retrieval when your work matches one. - Prior-art recall on writes — a
PreToolUsehook on Write/Edit checks the file about to be written against your recorded snippets (what's kept at that path, and what resembles the code) and offers them before the helper is rewritten. Titles only, never blocks the edit. - The shared Scribe skills — client-neutral Agent Skills, the same files any client's package would ship: using-scribe, writing-plans, reporting-back (reply to the operator in a shape that says where the work stands), systematic-debugging, verification, brainstorming, reusing-code (record and recall reusable code as snippets). Replaces superpowers.
- Your Scribe Processes as skills — saved Processes are synced into local
~/.claude/skills/scribe-proc-*stubs that auto-surface by relevance; the stub fetches the live procedure viaget_process. Refreshed each session and on demand with/scribe:sync.
It is designed so you can uninstall superpowers and depend on Scribe instead
of auto-memory — leave auto-memory at its default; Scribe replaces its job by
holding the one copy, not by switching it off.
How the pieces divide the work (decision #4027): the Scribe server orients
every MCP client and serves live state; the skills in skills/ state every
reflex in full and name no client; this plugin is the Claude Code adapter —
hooks that deliver at the right moment, /scribe:sync, and the few things only
Claude Code needs said (hooks/scribe_static_context.md). Packaging Scribe for
another client: see PACKAGING.md.
Install
The plugin ships inside the Scribe app repo, so the marketplace is that repo — you always get the plugin version that matches your Scribe instance.
/plugin marketplace add https://git.fabledsword.com/bvandeusen/FabledScribe.git
/plugin install scribe@scribe-plugin
On install you'll be asked for:
| Setting | What |
|---|---|
| Scribe base URL | e.g. https://scribe.example.com (no trailing slash) |
| Scribe API key | an fmcp_ key from Settings → API Keys (stored in your OS keychain) |
| Active project id | optional — numeric project id to scope the session-start context |
What gets wired
plugin.jsonmcpServers→ thescribeMCP server at<base URL>/mcp(Bearer auth).hooks/hooks.json→ SessionStart hook (hooks/scribe_session_context.sh), fail-open: if Scribe is unreachable it injects nothing and never blocks the session.hooks/hooks.json→ PreToolUse hook onWrite|Edit(hooks/scribe_prior_art.sh) →GET /api/plugin/prior-art. ReturnsadditionalContextwith no permission decision, so it can inform the write but never stop it; silent when nothing is recorded, which is most of the time. Two framings: a REUSE menu (similar/nearby records), and a SYNC nudge when a snippet records the exact file being edited — "updating the record is part of the edit" — each with its own once-per-session dedup. A third, ledger-fed line names a duplicate family (no canon) or a canon recorded elsewhere for the names being written (its own dedup channel,exclude_derive). Fail-open but not fail-silent: a configured instance that does not answer in time is said, once per outage ("Scribe did not answer … this write went UNCHECKED"), so a session can tell "checked, nothing there" from "never checked"; an answer clears the marker. The local by-name arm needs no server and always runs. Toggle in Settings → Knowledge auto-inject.hooks/hooks.json→ PostToolUse hook onBash(hooks/scribe_after_write.sh): code written through sed/heredocs/scripts never reaches the PreToolUse hook, so this one diffs the working tree after every Bash call (per-session path+blob snapshot; onegit statuswhen nothing changed) and runs the same arms on the definitions just written, through the same endpoint and the same dedup channels.additionalContextonly; never blocks, and shares the pre-write hook's once-per-outage "did not answer" line (8 s budget here — it runs after the tool, so it gates nothing). The extractor, the prose/data skip list, the local by-name duplicate arm and the outage line are shared inhooks/scribe_defs.sh.skills/→ the universal process-skills, surfaced by description match.hooks/scribe_sync_processes.sh(a 2nd SessionStart hook) + the/scribe:synccommand → generate~/.claude/skills/scribe-proc-*stubs from your Scribe Processes (viaGET /api/plugin/processes); also fail-open, and pruned to match what exists in Scribe.
Notes
- Do not hand-edit
versionin.claude-plugin/plugin.json. It is minted from the clock — runpython3 scripts/mint_plugin_version.py(ormake mint-plugin, wheremakeis installed) after changing anything underplugin/, and commit the result. The installer decides whether to refresh the cache it executes from by comparing that string, so content that ships without a new version reaches the repo and stops there (#2209). CI fails the lane if you forget. - The session-start, auto-inject and prior-art hooks need only a read-scoped key; the MCP tools need write scope to create/update. Every hook is a GET for that reason — a read key cannot POST.