CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / integration (push) Successful in 35s
CI & Build / Python tests (push) Successful in 1m9s
CI & Build / Build & push image (push) Successful in 29s
Step 6 measured the claim the whole milestone rests on — that the notes corpus divides into norms and constraints, with constraints a minority worth sweeping — against a stratified sample of the real thing. It holds: ~29% in `reference`, ~8% general, ~0-5% in `decision`, 0% in `dev-log`; roughly 6-11% of ~395 plain notes. Written up as note 3210. The step was allowed to return "revert" and does not. Two things the measurement found that the guidance did not say, now added to both the skill and the create_note docstring: A SHARPER TEST. Every note that earned a check was about somebody ELSE's software — a signing service, a forge, a hub, an SDK, a model, a dependency set. Not one was about the operator's own code. "Is the thing this note describes yours to change?" is decidable from the title in nearly every case, where the abstract form needs thought. THREE FALSE CANDIDATES, one of them a live hazard. Resume pointers and "current state" notes go stale faster than anything else in the corpus, which is exactly why they tempt — but the cure is to update or delete them, not to schedule a check, and a sweep full of pointers is a sweep nobody reads. Measurements of our own system go false because we changed something and knew. And a decision RESTING on someone else's behaviour is still a decision — the check belongs on the note asserting the fact. Also recorded, not fixed: the corpus already contains a note titled "CONSTRAINT: software only — no DIY hardware", using the word for a self-imposed scope limit — a NORM in this taxonomy, exactly backwards. Both surfaces already lead with the question rather than the label, which is the mitigation; note 3210 names the collision so it is not rediscovered.
231 lines
13 KiB
Markdown
231 lines
13 KiB
Markdown
---
|
|
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. Cross-cutting records — audits, sweeps, reviews — take *several*
|
|
tags and are the prime discovery moment: a pass that walks the subsystems
|
|
has just enumerated the vocabulary, so mint the Systems it names as it
|
|
names them. Create liberally — `create_system` is duplicate-gated, and that
|
|
gate (plus reviewing the existing list) is the guardrail against sprawl,
|
|
not restraint. Only a record genuinely about no particular area goes
|
|
untagged.
|
|
|
|
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.
|
|
|
|
9. **A few notes assert a FACT, and those can carry their own check.**
|
|
Supersession only fires once somebody has read a note and disagreed — which
|
|
is the case where it was already believed. A note asserting something about
|
|
*someone else's* software — what a service does on a duplicate upload, how a
|
|
forge numbers its CI runs, what an updater compares — can instead carry
|
|
`verify_with` (how to check it) and `expires_when` (the STATE that ends it:
|
|
"when the forge numbers runs per workflow", never "in six months").
|
|
`notes_due_for_verification` lists them least-recently-confirmed first, with
|
|
never-checked at the top; `mark_note_verified` records what you found, and
|
|
`still_true=False` deliberately writes nothing — a note whose check failed
|
|
is wrong rather than in a state worth recording, so it keeps its place.
|
|
|
|
**The test is one question: could this note become false without anyone
|
|
editing it?** If no, leave both fields empty. That is the normal case, and
|
|
an empty `verify_with` is the positive marker for "this is a decision, there
|
|
is nothing to go and check" — not an unfinished record. The sweep is only
|
|
worth reading while almost nothing is on it, so a check added out of
|
|
tidiness costs the whole surface, not just that note.
|
|
|
|
**The sharper form of the same test: is the thing this note describes yours
|
|
to change?** If yes it is a decision — editing your own software is how it
|
|
changes, and you will know you did it. Measured against a real corpus, every
|
|
note that earned a check was about somebody ELSE's software: a signing
|
|
service, a forge, a hub, an SDK, a model, a dependency set.
|
|
|
|
**Three that look like candidates and are not:**
|
|
- **Resume pointers and "current state" notes.** They go stale fastest of
|
|
anything, which is exactly why they tempt — but the cure is to update or
|
|
delete them, not to schedule a check. A sweep full of pointers is a sweep
|
|
nobody reads.
|
|
- **Measurements of your own system.** They go false because you changed
|
|
something, and you knew. A measurement earns a check only when what it
|
|
measures is outside your control.
|
|
- **A decision that RESTS on somebody else's behaviour.** The decision is
|
|
still a decision. Put the check on the note asserting the fact, and link
|
|
the decision to it.
|
|
|
|
Not for tasks — a task's decay is its status, and a done issue records what
|
|
happened rather than asserting something that can go false. Not for snippets
|
|
either: `verify_snippet` compares the recorded location and code against the
|
|
repo, which is richer and already wired to drift detection.
|
|
|
|
## 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.
|
|
|
|
## Starting a project: decide what it inherits
|
|
|
|
A project's inheritance is a **decision, not a default**. Before
|
|
`create_project`, ask the operator the four inception questions and pass the
|
|
answers — never create a project bare by default:
|
|
|
|
- which **always-on rulebooks** it should NOT inherit (`list_rulebooks` shows
|
|
which are always_on; default: inherit them all) →
|
|
`exclude_always_on_rulebooks=[...]`
|
|
- which other rulebooks to **subscribe** → `subscribe_rulebooks=[...]`
|
|
- which **design system** its UI is built from (`list_design_systems`; or
|
|
none) → `design_system_id=<id | -1>`
|
|
- whether to **seed the standard starter Systems** so records can be tagged
|
|
from day one → `seed_systems=true|false`
|
|
|
|
If `enter_project` returns an `inception` key, the project was never decided
|
|
(it inherits its defaults silently): raise that ask once, with the defaults it
|
|
carries, then `decide_project_inception(project_id, …)`. Existing projects
|
|
were stamped "legacy" (inherit-all) and do not ask; any project can be
|
|
re-decided. The rules/design-system/Systems tools still work one at a time —
|
|
inception is the moment they are decided together, and the record of why.
|
|
|
|
## 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.
|