feat(plugin): write-path trigger — offer prior art before code is rewritten
CI & Build / Python lint (push) Successful in 4s
CI & Build / integration (push) Successful in 27s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / Python tests (push) Successful in 47s
CI & Build / Build & push image (push) Successful in 1m2s

The milestone headline. Auto-inject fires on the operator's prompt; the
moment reuse is actually lost is later, when the agent decides mid-task to
write a helper. A PreToolUse hook on Write|Edit now fires there.

Channel: `additionalContext` with NO permissionDecision, so the note reaches
Claude beside the tool result and the write is never blocked — a recall aid
must not be able to stop the operator's work. Plain stdout would have been
invisible to the model, and deny/ask would have made a nudge into a gate.

Two arms, different in kind:
- BY PLACE — a snippet recorded at this path (or its directory) is prior art
  by definition, not resemblance, so it is neither scored nor thresholded.
  This is what #2083's reverse lookup was built to answer.
- BY MEANING — semantic search restricted to snippets (new `note_type` filter
  on semantic_search_notes) over the code about to be written.
Place ranks first; the top-k cap spans both arms.

Gates carried over from milestone 93 verbatim: threshold, margin, session
dedup, titles-never-bodies. Own `source='write_path'` in retrieval_logs so
precision is tunable separately — the docstring records that the place arm
is unlogged and hands that to #2085.

Its own on/off in Settings but the SAME threshold/top-k: one "how loud may
Scribe be" knob is easier to reason about than two that drift, and splitting
them later is then a data-backed change rather than a guess.

Details worth keeping: the hook sends a REPO-RELATIVE path because that is
how locations are recorded; the git remote resolves to a project and is never
used as the location `repo` filter (different namespaces, would silently
match nothing); the endpoint stays a GET because a read-scoped API key cannot
POST and every other hook depends on that.

plugin.json 0.1.17 -> 0.1.18. Refs #2082, milestone #232.
This commit is contained in:
2026-07-28 09:08:17 -04:00
parent 083944f0fd
commit e0328f2b1c
10 changed files with 810 additions and 3 deletions
+12 -2
View File
@@ -7,6 +7,10 @@ instance into a first-class Claude Code extension:
rulebook (the `scribe` server).
- **Session-start push channel** — a `SessionStart` hook injects your always-on
rules + active-project context so Scribe surfaces *without being asked*.
- **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.
- **Universal process-skills** — using-scribe, writing-plans,
systematic-debugging, verification, brainstorming, reusing-code (record and
recall reusable code as snippets). Replaces superpowers.
@@ -42,6 +46,11 @@ On install you'll be asked for:
- `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.
Toggle in **Settings → Knowledge auto-inject**.
- `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
@@ -52,5 +61,6 @@ On install you'll be asked for:
- Set a `version` bump in `.claude-plugin/plugin.json` per release so clients
pick up changes.
- The session-start hook needs only a **read**-scoped key; the MCP tools need
**write** scope to create/update.
- 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.