CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m36s
CI & Build / Build & push image (push) Successful in 12s
Step 4 of milestone 410 "One owner per piece of guidance". The plugin's static session context was a second copy of using-scribe and the server index. It now says only what Claude Code needs said: 8,705 -> 1,791 chars. scribe_static_context.md: - points at using-scribe for how to work with Scribe, and names the process skills - Claude Code specifics: keep one copy in Scribe rather than CLAUDE.md or auto-memory (leave auto-memory at its default); injected lines are retrieval, not the whole set; compact at clean seams; stored Processes arrive as scribe-proc-* skills with /scribe:sync; say so when the tools are unavailable - retired: the restated reflexes, "how the surfaces divide the work", and the "follow the surface that assumes least" precedence (decision #4027) Hook behaviour is unchanged. The SessionStart hook header says what the static tier now carries, and the unreachable-instance status points at the using-scribe skill instead of "the standing guidance above". README and manifest describe the plugin as the Claude Code adapter over the shared, client-neutral skills. Fixed along the way: the README said the SessionStart hook "injects your rules" and suggested disabling auto-memory, both contradicting the product since milestone 394. Tests: the session-start rules guards now pin the owner (using-scribe) and the index (_INSTRUCTIONS) rather than every surface; the Systems-reflex and snippet-trigger guards pin their owners; the reporting-reflex guard pins using-scribe. The loss guard and client-neutral guard stay green. Plugin version minted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
102 lines
5.7 KiB
Markdown
102 lines
5.7 KiB
Markdown
# Scribe plugin for Claude Code
|
|
|
|
Turns a self-hosted [Scribe](https://git.fabledsword.com/bvandeusen/FabledScribe)
|
|
instance into a first-class Claude Code extension:
|
|
|
|
- **MCP tools** over your notes, tasks, projects, milestones, systems, and
|
|
rulebook (the `scribe` server).
|
|
- **Session-start push channel** — a `SessionStart` hook 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 `PreToolUse` hook 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 via `get_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`).
|
|
|
|
## 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.json` `mcpServers` → the `scribe` MCP 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 on `Write|Edit`
|
|
(`hooks/scribe_prior_art.sh`) → `GET /api/plugin/prior-art`. Returns
|
|
`additionalContext` with **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 on `Bash`
|
|
(`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; one `git status` when
|
|
nothing changed) and runs the same arms on the definitions just written,
|
|
through the same endpoint and the same dedup channels. `additionalContext`
|
|
only; 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 in `hooks/scribe_defs.sh`.
|
|
- `skills/` → the universal process-skills, surfaced by description match.
|
|
- `hooks/scribe_sync_processes.sh` (a 2nd SessionStart hook) + the `/scribe:sync`
|
|
command → generate `~/.claude/skills/scribe-proc-*` stubs from your Scribe
|
|
Processes (via `GET /api/plugin/processes`); also **fail-open**, and pruned to
|
|
match what exists in Scribe.
|
|
|
|
## Notes
|
|
|
|
- **Do not hand-edit `version` in `.claude-plugin/plugin.json`.** It is minted
|
|
from the clock — run `python3 scripts/mint_plugin_version.py` (or `make
|
|
mint-plugin`, where `make` is installed) after changing anything under
|
|
`plugin/`, 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.
|