Files
FabledScribe/plugin/skills/reusing-code/SKILL.md
T
bvandeusen e0328f2b1c
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
feat(plugin): write-path trigger — offer prior art before code is rewritten
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.
2026-07-28 09:08:17 -04:00

99 lines
5.7 KiB
Markdown

---
name: reusing-code
description: Use when you're about to write a helper, utility, hook, or reusable component — search recorded snippets FIRST so prior art is reused instead of re-solved. And the moment you build or notice something reusable, record it as a snippet so a later session finds it. Triggers on "write a util/helper", "I need a function that…", "let me add a component", or just having built something worth reusing.
---
# Reusing code — recall before you rebuild
Reusable code is worth writing once. Scribe stores **snippets** — a named,
reusable function or component recorded with its language, signature, canonical
location (repo · path · symbol), a one-line *"when to reach for it,"* and the
code itself — so prior art can surface *before* it's re-written as a one-off.
Snippets are ordinary embedded notes, so a recorded one also surfaces on its own
through recall/auto-inject; this skill is the active reflex around that.
## Before you write a new helper — search first
- About to write a utility, hook, formatter, adapter, or a reusable component?
**Search snippets before writing it.** `list_snippets(q="…")` (or a plain
`search`) — a matching one may already exist, in this project or another.
`list_snippets` searches every project by default; that's deliberate, since a
helper you need here was quite possibly written somewhere else. Narrow with
`project_id` only when you specifically want this project's own.
- **About to edit an existing file? Ask by place, not just by meaning.**
`list_snippets(repo="…", path="…")` answers "what canonical helpers are already
recorded here?" — `path` matches the exact file or anything beneath it, so
`path="frontend/src"` covers the whole tree. Cheaper and sharper than a
wording search when you already know where the code is going, and it catches
the helper you'd otherwise duplicate a few lines down. `symbol="…"` narrows
further, and all three must match the same recorded location. Combine with `q`
to ask both at once.
- If a snippet fits, pull it in full with `get_snippet(id)` and reuse it — its
`location` points at the reference implementation. Adapt, don't re-derive.
- If auto-inject already surfaced a snippet title that looks relevant, that's
your cue to `get_snippet` it rather than start from scratch.
- **Prior art offered beside a write is not noise — read it.** When Scribe notes
that a snippet is already recorded for the file you just wrote or edited, open
it before you go any further. Either it's the helper you were about to
duplicate — reuse it and drop yours — or it isn't, and the record needs the new
location adding. Both are cheaper now than after the duplicate settles in.
## The moment you build something reusable — record it
- Just wrote (or noticed) a helper, hook, pattern, or component worth repeating?
Record it with `create_snippet` while it's fresh:
- **name** — what it's called, e.g. `useDebouncedRef`.
- **code** — the implementation.
- **when_to_use** — one sharp line on when to reach for it. This becomes part
of the title, so it's what a later recall menu shows — make it earn the pull.
- **language**, **signature**, and **location** (`repo` / `path` / `symbol`)
so the recorded copy points back at the canonical source.
- **project_id** / **system_ids** to associate it with the work it belongs to.
- Record the *reference* implementation, not every call site — one good entry
per reusable thing. If it already exists, `update_snippet` it instead of
recording a second copy (the create gate will flag a near-duplicate anyway).
## A shared snippet is a suggestion, not a standard
Scribe is multi-user, so a search can return snippets other people own. Those
come back marked `shared: true` with an `owner`.
- Read one as **that person's suggestion**, not as the way things are done here.
Judge the code on its merits before reaching for it.
- Say whose it is when you propose it — "there's a snippet from *alex* that does
this" — so the operator can weigh the source, not just the code.
- Don't treat it as the house pattern, and don't build on it at scale, without
the operator agreeing to adopt it.
- Snippets shared directly with the operator only appear when you search for
them, never in a plain `list_snippets` — so anything ambient is genuinely
theirs.
## Keep the record honest
A recorded snippet is offered as prior art on every matching turn, so a wrong
one costs more than a missing one.
- Details gone stale — a renamed symbol, a moved file, a signature that's
changed? Fix it with `update_snippet`. Passing an **empty string** clears a
field, so a wrong signature or location can be removed, not just written over.
- Recorded something that turned out not to be reusable, or that no longer
exists? Retire it with `delete_snippet` — it goes to the trash and can be
restored. Don't leave it competing for attention.
## Found the same thing in several places — unify it
When you notice the same reusable thing recorded (or written) as several
one-offs, don't leave the duplicates competing in recall — **merge them**.
`merge_snippets(canonical_id, [other_ids])` keeps one canonical record, folds in
the others' call sites as locations, and retires the duplicates to the trash.
The result is a single entry that shows every place the thing is used — which is
exactly the signal that it was worth consolidating. This is the cure the create
gate only hints at when it blocks a near-duplicate.
## Why this pays off
A one-off written a second time is the cost this avoids. Recording a snippet
once — with a location and a crisp "when to use" — means the next session is
offered the prior art instead of re-solving it. Search before writing; record
what's worth reusing.