Files
FabledScribe/plugin/skills/using-scribe/SKILL.md
T
bvandeusen 3f1523b19f
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / TypeScript typecheck (push) Successful in 10s
CI & Build / integration (push) Successful in 18s
CI & Build / Python tests (push) Successful in 46s
CI & Build / Build & push image (push) Successful in 25s
feat(systems): read-side teeth — the vocabulary at session start, a search filter, and the state/chronicle instructions
Step 4 of #278, product half. The audit that motivated it: one System in
project 2, thirty records tagged, nothing since July 28 — three days after the
feature landed. Not a discipline failure; retrieval was completely blind to
the association (zero references in embeddings, knowledge, search, auto-inject,
or enter_project), so tagging was a write-side label with no read-side payoff,
and labels nobody reads don't get maintained.

Three changes, ordered by what makes the others workable:

1. enter_project returns the project's Systems (id, name, first line of the
   charter). Load-bearing for the tagging instruction: you cannot ask an agent
   to check a record against a vocabulary it never sees. Trimmed because it
   rides on every session start; the full charter stays get_system's job.
   Present-and-empty rather than absent when a project has none — "no named
   areas yet" is information the create-the-System instruction acts on.

2. search accepts system_id, MCP and REST (#33). Implemented once in
   semantic_search_notes as an EXISTS against record_systems — an association
   filter deciding candidate-set membership before scoring, like project_id,
   not a ranking signal. The REST route's missing project filter stays #2463's:
   it carries a default-scope UI decision this change must not preempt.

3. The instructions (#119, _INSTRUCTIONS + using-scribe skill; plugin 0.1.25
   for the cache):
   - Tag as you write, with an executable test — "would someone investigating
     that subsystem want this in the pile list_system_records returns?" —
     rather than "tag appropriately", which is what died.
   - Create the System when the area has no record: the two-or-more test
     snippets use, plus "don't wait to be asked to name an area that plainly
     exists", because the agent's default was leaving un-modelled areas
     un-modelled forever.
   - State vs chronicle: dev-logs are written once and never rewritten; durable
     findings live in the System's reference note, updated in place — safe
     because note versions are the changelog, which has existed since the
     feature shipped and was never named as one.

list_system_records' docstring now sells it as the way to READ a subsystem,
reference note first. No auto-inject boost by System — vocabulary and filter
first, measure before adding ranking behaviour (the #2486 lesson).

Refs #278, #2546
2026-08-08 18:19:58 -04:00

8.9 KiB


name: using-scribe description: Use at the START of every session, and before answering anything about the operator's work or starting any task — establishes the Scribe-first reflex. FIRST ACTION of a session: call list_always_on_rules() (and enter_project when a repo/project is in scope) to load the operator's binding rules. Then recall before acting, update over duplicate, plan in Scribe not in files.

Using Scribe

Scribe is the operator's self-hosted system of record (notes, tasks, issues, projects, milestones, systems) and rulebook, reachable through the bundled scribe MCP server. Its value is mostly in what it already holds — so make reading it a reflex, not something you wait to be asked for.

Do this first (every session)

Pull the standing rules yourself — do not wait for them to be handed to you. At the start of a session, before substantive work, call list_always_on_rules() to load the operator's always-on rules. If the working repo maps to a Scribe project (you're in a known repo, or list_repo_bindings shows a binding), call enter_project(id) instead/as-well — it returns the project plus its applicable rules, open tasks, and recent notes in one shot.

Do this actively. A SessionStart hook may also inject a rule index, but treat that as a bonus, not a precondition: it can be absent (e.g. when the instance is unreachable, or the token didn't reach the hook), so the reliable path is this explicit pull. Rules loaded this way are binding for the session.

Scribe holds these functions — don't keep a second copy

This plugin makes Scribe the home for the operator's rules, recall, and planning — the jobs Claude's native auto-memory would otherwise do. When the plugin is present, route those jobs to Scribe and do not also write them to native memory: codify rules with create_rule / create_project_rule, capture durable knowledge as Scribe notes, and keep plans in Scribe milestones (via start_planning) — not in MEMORY.md or CLAUDE.md. One copy, in Scribe; let any existing local memory shrink as Scribe takes over. Don't maintain both stores in parallel.

Two constraints on how that's achieved:

  • Steer behavior; never flip a native switch. The plugin must work with native auto-memory at its default (ON). Never tell the operator to set autoMemoryEnabled:false or otherwise disable a built-in function to make Scribe "win" — a setting the operator may not know was changed (and wouldn't know to restore) is exactly the hidden breakage to avoid. You replace memory's functions by doing the work in Scribe, not by turning memory off.
  • A Scribe-shaped hole is acceptable. If the plugin is later removed, the operator recovers context over time — that's fine. You do not need to keep native memory as a self-sufficient fallback. The only thing to avoid is breakage caused by a settings change the operator didn't make knowingly.

The reflex

  1. Recall before acting. Before answering a question about the operator's work, or starting a task, search Scribe (and list_tasks / list_notes) for related prior work — an existing task, decision, or note — instead of re-deriving it or opening a duplicate. When a project is in scope, pass its project_id so results stay scoped.

  2. Standing rules are binding. Load them via list_always_on_rules() at session start (see "Do this first"); treat every one as binding. Pull a rule's full statement with get_rule(id) when it's about to bite. When a project is in scope, enter_project(id) also returns its applicable rules.

  3. Update over duplicate. When recording, prefer updating an existing note/rule/task over creating a new one. Search first; revise what's there.

  4. When you plan, plan in Scribe. Work with an arc — several steps toward one goal — gets a plan, and a plan is a milestone: start_planning(project_id, title) creates one whose body holds the design, each step is its own task under it (create_task(milestone_id=...)), progress goes in work-logs (add_task_log). Work without an arc (a fix, a one-file change, a question) is just a task — don't wrap it in a milestone. Either way, do not write plans/specs to local .md files. See the writing-plans skill.

  5. Keep state honest. Set a task in_progress when you start it, done the moment it's complete; log progress as you go.

  6. Fixes are issues, not work-logs. When you fix a problem — even one solved in passing — record it as its own issue (create_task(kind="issue")) with symptom → root cause → fix, optionally linked to the task it arose from (arose_from_id) and the subsystem it touches (system_ids). Don't bury a fix as a work-log line on whatever task happened to be open.

  7. Tag records to Systems. enter_project lists the project's Systems — its named subsystems/areas. When you create or meaningfully update a record, ask which areas it is about and pass system_ids. The test: would someone investigating that subsystem want this record in the pile list_system_records returns? If the area has no System yet, create one (create_system: name + a one-paragraph charter) — an area that plainly exists deserves naming the moment two records would share it; don't wait to be asked. A record about no particular area takes none.

  8. State updates in place; chronicles don't. A dev-log records what happened — write it once, never rewrite it. A durable finding (how a subsystem works, a measured number) lives in that System's reference note ("«System» — reference"), which you UPDATE as facts change — safe, because every meaningful edit is snapshotted and the version history is the changelog. The dev-log then [[links]] the reference note instead of restating state. When a new record outright corrects an older one (a re-measurement, a reversed decision), pass the old id in supersedes so the stale record is demoted and labelled rather than left competing.

Stay inside the active project's scope

Once a project is in scope — you called enter_project, or the working repo is bound — confine the session to it:

  • Pass that project_id to every read (search, list_tasks, list_notes). An unscoped read bleeds every other project's work into your context.
  • Only reference or offer work on the in-scope project. Don't surface, suggest, or start work on other projects unless the operator explicitly widens scope.
  • If something clearly belongs to a different project, say so and ask before switching — never silently operate cross-project.

Where a new rule goes

When codifying a rule, pick its home by who it should bind — and keep shared homes general:

  • Always-on rulebook (create_rule in an always_on rulebook) — universal norms that bind every project. Cross-project standards only.
  • Subscribed rulebook (create_rule + subscribe_project_to_rulebook) — a reusable, themed module of general rules that binds only projects that opt in (e.g. a review checklist → every service). Themed, but project-agnostic.
  • Project rule (create_project_rule) — anything specific to one project (its files, paths, quirks).

Both rulebook tiers are shared, so their rules stay general; they differ in reach (all vs opt-in), not generality. Names one project's specifics → project rule; a standard a category shares → subscribed rulebook; a universal norm → always-on rulebook. Never put project-specific detail in a shared rulebook — it leaks to every other project that gets it.

First ask whether it's a rule at all. A rule is prose you have to remember and apply; Scribe's other entities are structure a tool can resolve and check. Visual standards belong in a design system, not a rulebook — a token can be inherited, resolved per mode, rendered to a stylesheet and diffed against code, and none of that survives being written as a rule. A repeatable procedure is a process; reusable code is a snippet. Reach for a rule when the thing really is a standing instruction about how to work.

Building UI: the project's design system binds

enter_project returns a design_system when the project has one, with the guidance chain-merged — the house style it inherits plus its own departures from it. Treat it the way you treat a rule.

Before writing a colour, size, radius, weight or duration by hand, reach for a token: resolve_design_system(id) for the values, or get_design_system_stylesheet(id) for the rendered sheet. A literal is a value stated outside the system, so it can never follow a palette change — and nothing will tell you it drifted.

Other Scribe process-skills

This plugin also ships focused process-skills — writing-plans, systematic debugging, verification, and brainstorming. Reach for the matching one when its situation arises, the same way you reach for this skill.