Files
FabledScribe/plugin/skills/reusing-code/SKILL.md
T
bvandeusen 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
feat(acl): shared records are search-only and always labelled as someone else's
Narrows the b7d6fc7 widening 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): b7d6fc7 widened 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
2026-07-25 22:43:00 -04:00

4.8 KiB

name, description
name description
reusing-code 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.