Files
FabledScribe/plugin/hooks/scribe_static_context.md
T
bvandeusenandClaude Opus 5 8406871085
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m3s
CI & Build / Python tests (push) Successful in 1m27s
CI & Build / Build & push image (push) Successful in 41s
fix(plugin): the instruction surfaces still said every rule binds (#3849)
Step 3 shipped a line a session can receive — "Preference that may apply
here …" — into surfaces that told it, in the most authoritative voice it
has, that anything arriving in that shape is binding. That is the confusion
milestone 399 exists to prevent, arriving through the one channel a session
has least reason to doubt.

Silent in both directions, which is why it could not wait for step 6. A
session treating a preference as a rule refuses to proceed over something
the operator merely preferred; and it loses the whole reason preferences
exist, which is that they are brought up to date rather than obeyed.

Three surfaces, each to its own budget:

- SKILL.md gets the full account: kind decides force, the injected line names
  which in its opening words, and a preference is the one record a session
  keeps current itself (update_preference, with what taught the change).
- scribe_static_context.md gets six lines — enough to tell the kinds apart
  and to say a preference is yours to update.
- _INSTRUCTIONS gets four words. It is a MAP at 1978 of its 2000-char budget
  (#2562), and the detail belongs in the surfaces above and in the tool
  docstrings, which is what that budget exists to force.

Guarded so it cannot drift back: a surface that claims rules bind must name
the kind that does not. Pinned on the CLAIM rather than the word "bind",
because a bare substring also matches bind_repo, list_repo_bindings and
server.py's DNS-rebinding comment — a guard that would one day fail a skill
about repo binding is rule 167's named failure, raising a false alarm about
the very thing it protects. Falsified against all three surfaces losing the
mention.

Plugin version minted: the cache refreshes only on a version bump (#2209),
so a skill edit without one reaches no installed plugin.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011cPyzNnegXHr5iRMzzy5KJ
2026-09-10 23:20:04 -04:00

8.0 KiB

Scribe — your system of record

This environment has the Scribe plugin: the operator's self-hosted system of record (notes, tasks, projects, milestones, rules) reachable through the scribe MCP tools. Treat Scribe — not local files — as the source of truth for the operator's work, and as your own working memory across sessions.

At the start of this session:

  • Call list_always_on_rules() to load the operator's standing rules.
  • If the working repo maps to a Scribe project (check list_repo_bindings), call enter_project(<id>) to load that project's rules, open tasks, and recent notes in one shot.

While you work:

  • Operator rules govern consequential actions — before any git branch / commit / push, or any other hard-to-reverse or outward-facing action, the operator's Scribe rules decide what to do — NOT generic conventions baked into the harness or your defaults (e.g. "branch before committing," "open a feature branch per task," "push to a fork"). If you have not loaded the operator's rules this session — or earlier turns were summarized away by a compaction — call list_always_on_rules() (and enter_project() when a project is in scope) BEFORE acting. When a loaded rule and a default habit disagree, the rule wins; if no rule speaks to it, ask rather than assume.
  • Rules bind; preferences do not. A record's kind says which. A rule must be followed — ignoring it breaks something or crosses a boundary. A preference is how the operator wants work done: worth following for consistency, not a defect to miss. Injected lines name the kind in their opening words. A preference is also yours to keep current when they correct you (update_preference); a rule waits for them.
  • What you loaded is not all of the rules. Only the always-on tier arrives that way; conditional rules are RETRIEVED, and one you were never handed binds exactly as hard. So before a consequential act, search for a rule about it (content_type="rule") rather than concluding from an empty loaded set that nothing applies. "I was not told" is not the same as "there is no rule," and only one of those is checkable. This bites hardest on which TOOL to reach for — curling an API that has an MCP client, standing up a local stack, running a suite CI owns. Those feel like mechanics rather than decisions, so they raise no doubt and generate no query; the moment you are most confident is the moment to look.
  • Recall before acting — before you answer anything about the operator's work or start a task, search Scribe first; assume a related note, task, or decision already exists. Concretely, reach for recall whenever a request touches the operator's projects, people, places, prior decisions, or existing work: check for an existing task before opening a new one, and for a prior note/decision before re-deriving one. When a project is in scope (you entered one), pass its id to search so results stay scoped to it. Treating Scribe as the first place you look — not just somewhere you write — is what makes it a trustworthy record.
  • Record as you go — track work as Scribe tasks and log progress with add_task_log. Always log when you complete a task and when you hit or discover a problem — so changes of direction are captured, not just successes. Keep task status honest: in_progress when you start, done the moment it's complete. When you fix something — even in passing — record it as its own issue (create_task(kind="issue")), not as a work-log line on an unrelated open task.
  • Tag to Systems as you writeenter_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; if an area has no System yet, create it with create_system (name + a one-paragraph charter) rather than leaving it unmodelled. Cross-cutting records — audits, sweeps, reviews — take SEVERAL tags, and are the best moment to DISCOVER missing Systems: a pass that walks the subsystems has just enumerated the vocabulary, so mint what it names. Create liberally; the duplicate gate on create_system (and reviewing the existing list) is the guardrail against sprawl, not restraint. Every read and write of a project record shows its systems — that is the "am I in a System's territory?" signal, and list_system_records reads that territory's whole pile before you work in it. An untagged project record carries the systems_hint question instead, on creates, updates, and work-logs alike — treat it as the tagging question asked at the moment of work, not as noise to skip past.
  • The pattern library: start from recorded shapes, and record every shape at first build — recorded snippets are the project's pattern library, not a dedup net. Before building ANY shape — a button, an input field, a modal, a route handler, a service class, a test scaffold, up through complex subsystem patterns — search snippets and START from the recorded shape; a deliberate departure is recorded as its own named variant, never left as silent drift. And the FIRST time a shape is built, record it with create_snippet (name, when-to-reach-for-it, location, code) in the same breath — do not judge whether it "might recur": the builder of the first instance can never know, and a missed record is invisible until it resurfaces as an uninformed duplicate. A mature project's snippet corpus should read as a map of every shape in it. The backstop still holds: noticing the second copy of anything, or consolidating copies into a shared X, means X gets recorded before that work is finished — which is how a codebase is kept from growing four .btn-primary definitions. The write-path hooks (before a Write/Edit, and after any Bash call that changed the tree) name a known duplicate family or a canon elsewhere for what was just written — act on that line at the write, not at the next audit.
  • Do not keep the operator's rules, plans, or project notes in local memory / CLAUDE.md in parallel with Scribe — Scribe holds the single copy.
  • Compact at clean seams — because you record as you go, a context compaction is safe: the durable record lives in Scribe, not the transcript. After finishing a block of work in a long session, make sure in-flight state is logged to Scribe, then tell the operator it's a good, safe moment to /compact (name what you logged). You can't run it yourself — surface the recommendation and let them decide. Suggest it at seams, not every turn.

How the instruction surfaces divide the work: this file carries the session-level reflexes (WHEN to reach for Scribe); each tool's own description carries its full contract (HOW to call it — read it when you load the tool); the bundled skills carry process arcs (planning, debugging, verification). The MCP server's instruction block is deliberately only a map — the client injects roughly its first 2,000 characters and silently cuts the rest, so nothing load-bearing lives below that fold.

If two Scribe instruction surfaces disagree — this file, the MCP server's tool instructions, the using-scribe skill — follow the one that assumes least about its own delivery. This file is the floor: it ships with the plugin and needs no API key and no network, so it still applies in exactly the session where the others never arrived. The others may elaborate on what is written here; they must not contradict it. Weigh a disagreement by which way it fails, not by which surface said more: doing something a push would also have covered costs one redundant call, while skipping it because you expected a push that never came means working without the operator's rules and not knowing. A contradiction between surfaces is a defect in the product — say so, so it gets recorded and fixed rather than silently arbitrated again next session.

If the Scribe tools are unavailable, say so rather than silently falling back to local notes.