04b58ce01e
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 28s
CI & Build / integration (push) Successful in 35s
CI & Build / Python tests (push) Failing after 41s
CI & Build / Build & push image (push) Has been skipped
Narrows theb7d6fc7widening per the operator's call, and fixes a regression it introduced. Decision recorded as note 2094. Two scopes now, deliberately different: readable_notes_clause — everything the ACL permits, including records reached only via a direct/group note share. For EXPLICIT acts: a search the caller typed, a fetch by id. browsable_notes_clause — the caller's own records plus anything in a project they can reach. For PASSIVE surfaces: browse lists, facet counts, the process->skill manifest. The split is a trust boundary. Anything appearing unasked — in your own list, your own counts, or as a skill installed on your machine — reads as material you endorsed. A one-off someone shared with you hasn't earned that standing, so it waits until you go looking. This also dissolves the shared-Process problem by construction rather than by special case: the manifest is a passive surface, so a directly-shared Process is never installed as an auto-surfacing skill. Regression fix (#2093):b7d6fc7widened the list queries but left the fetch path owner-only, so on the MCP path a record could be listed and then not opened — get_snippet raised not-found, get_process couldn't resolve, and the manifest emitted stubs whose get_process call would fail. snippets.get_snippet and notes.resolve_process now resolve the read scope. delete_snippet gained an explicit can_write_note guard, since being able to SEE a shared snippet must not imply being able to bin it. Provenance, so nothing arrives looking like the operator's own work: - access.describe_provenance / label_shared_items add shared/owner/permission; labelling costs no query when everything is the caller's own. - MCP: get_snippet, list_snippets, get_process and list_processes carry it, and get_process now says outright NOT to follow a shared process verbatim — its follow-as-written contract was the sharpest instance of the problem. - The skill stub for a shared Process names its author and asks for a go-ahead, instead of describing it as "the operator's saved Scribe process". - Policy stated once in the MCP _INSTRUCTIONS and the reusing-code skill: a shared record is that person's suggestion, weigh it, attribute it, ask before adopting it. - UI: shared snippets show "by <owner>" in the list and a notice above the code in the detail view, reusing SharedWithMeView's vocabulary. Plugin 0.1.15 -> 0.1.16 (skill text changed). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLwAaV4DQEmVyn496HnEvt
86 lines
4.8 KiB
Markdown
86 lines
4.8 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.
|
|
- 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.
|
|
|
|
## 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.
|