feat(guidance): an operator's ruling lives on the System it governs, and code is read as behaviour, not intent (milestone 444 steps 1-2, #4754 #4755)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 55s
CI & Build / Python tests (push) Successful in 1m46s
CI & Build / Build & push image (push) Successful in 56s

A Librarian session contradicted a decision the operator had made 13 days
earlier. The ruling ("retry, then replace, never give up on a book") was
kept only as a quote in a work log, beside a session's reading of it that
capped replacements at 3. Three later sessions built on the reading, and one
carried the cap into an option as a "known cost", which the operator then
approved without being asked about it.

- writing-records.md: "A ruling goes on the System it governs". What a
  ruling is (the operator decided it; a later change could undo it), how it
  differs from a rule, and where it goes: a Rulings section at the end of
  the System description, one line each with who, when and the source
  record. Written the turn the operator decides; holds what is in force,
  not history; a charter line that contradicts a ruling is fixed in the
  same edit.
- using-scribe SKILL.md: reflex 1 says code tells you what a thing does,
  not what was wanted, and a limit read from code is unconfirmed until a
  System's Rulings says otherwise. Reflex 9 points to the ruling section.
- reporting-back: an option that carries existing behaviour says whose call
  it was (the operator's ruling, or a past session's never confirmed); one
  that contradicts a ruling is a Conflict.
- create_system / update_system docstrings: the Rulings section, and that
  description replaces the whole text.
- test_guidance_ownership: three topics pinned to their owners.
- Plugin version minted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 18:59:36 -04:00
co-authored by Claude Opus 5.5
parent cf4206469b
commit 01d8a0b9f1
6 changed files with 106 additions and 3 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "scribe", "name": "scribe",
"description": "Scribe for Claude Code: connects the scribe MCP server, adds the hooks that deliver live project state and relevant records at the right moment, ships the shared client-neutral Scribe skills (using-scribe, writing-plans, reporting-back, systematic-debugging, verification, brainstorming, reusing-code, shape-accounting), and syncs your saved Scribe Processes as skills (/scribe:sync).", "description": "Scribe for Claude Code: connects the scribe MCP server, adds the hooks that deliver live project state and relevant records at the right moment, ships the shared client-neutral Scribe skills (using-scribe, writing-plans, reporting-back, systematic-debugging, verification, brainstorming, reusing-code, shape-accounting), and syncs your saved Scribe Processes as skills (/scribe:sync).",
"version": "2026.10.01.1724", "version": "2026.10.02.2259",
"author": { "author": {
"name": "Bryan Van Deusen" "name": "Bryan Van Deusen"
}, },
+9
View File
@@ -153,6 +153,15 @@ name.
Before asking, check whether you can find the answer yourself — something that Before asking, check whether you can find the answer yourself — something that
can be read or looked up is a fact to check, not a question to send. can be read or looked up is a fact to check, not a question to send.
**An option carries assumptions, and the operator approves only what they can
see.** When an option keeps or depends on existing behaviour — a limit, a
default, a fallback already in place — say whose call that behaviour was: the
operator's, citing the ruling ("you ruled this, #N"), or a past session's that
nobody confirmed ("a past session chose this; you were never asked"). Choosing
between options is not a decision about the assumptions they share, and an
unlabelled one gets approved as if it had been asked. An assumption that
contradicts a recorded ruling is a **Conflict**, not an option's fine print.
## Answers — the operator asked something ## Answers — the operator asked something
| Kind | Sections | | Kind | Sections |
+15 -1
View File
@@ -52,6 +52,12 @@ Two constraints on *how* that's achieved:
re-deriving it or opening a duplicate. When a project is in scope, pass its re-deriving it or opening a duplicate. When a project is in scope, pass its
`project_id` so results stay scoped. `project_id` so results stay scoped.
**Code tells you what a thing does, not what was wanted.** A limit, a
default or a fallback found by reading the work is a past session's choice
until a record says the operator made it. Before presenting one as a
safeguard or a known cost, read the `Rulings` on the System it belongs to;
when none speaks to it, call it unconfirmed rather than settled.
2. **Rules are binding, and they reach you by retrieval.** No call loads the 2. **Rules are binding, and they reach you by retrieval.** No call loads the
operator's rules and no standing set is handed to a session. A rule arrives operator's rules and no standing set is handed to a session. A rule arrives
when what you are about to do resembles what it is about — a command, the when what you are about to do resembles what it is about — a command, the
@@ -227,6 +233,13 @@ Two constraints on *how* that's achieved:
re-measurement, a reversed decision), pass the old id in `supersedes` so the re-measurement, a reversed decision), pass the old id in `supersedes` so the
stale record is demoted and labelled rather than left competing. stale record is demoted and labelled rather than left competing.
**What the operator decided an area must do is a ruling, and it lives on
that System** — a `Rulings` section in its description, written the turn
they decide. A quote in a work log reaches the next session only if a
search happens to match it; the description arrives with every record
filed there. [writing-records.md](writing-records.md) has the two tests and
the form.
10. **A note that asserts a fact about someone else's software can carry its 10. **A note that asserts a fact about someone else's software can carry its
own check** (`verify_with`, `expires_when`), swept by own check** (`verify_with`, `expires_when`), swept by
`notes_due_for_verification`. Most notes should not: read `notes_due_for_verification`. Most notes should not: read
@@ -264,7 +277,8 @@ moment rather than on every turn:
(`decide_project_inception` when `enter_project` returns `inception`). (`decide_project_inception` when `enter_project` returns `inception`).
- [writing-records.md](writing-records.md) — before writing a rule, preference - [writing-records.md](writing-records.md) — before writing a rule, preference
or lesson (where it goes, its `when_to_apply`, what already covers the or lesson (where it goes, its `when_to_apply`, what already covers the
moment), and before giving a note a check. moment), when the operator decides how an area must behave (a ruling), and
before giving a note a check.
- [missed-retrieval.md](missed-retrieval.md) — a rule that missed the moment it - [missed-retrieval.md](missed-retrieval.md) — a rule that missed the moment it
governed, or keeps arriving where it doesn't apply. governed, or keeps arriving where it doesn't apply.
+49 -1
View File
@@ -2,11 +2,13 @@
Part of the using-scribe skill. Read it before `create_rule`, Part of the using-scribe skill. Read it before `create_rule`,
`create_project_rule`, `create_preference` or `create_lesson`; when a lesson `create_project_rule`, `create_preference` or `create_lesson`; when a lesson
arrives that names the situation you are actually in; and before filling arrives that names the situation you are actually in; when the operator
decides how some area of the work must behave; and before filling
`verify_with` or `expires_when` on a note. `verify_with` or `expires_when` on a note.
## Contents ## Contents
- Where a new rule goes — its home, its trigger, what already covers the moment - Where a new rule goes — its home, its trigger, what already covers the moment
- A ruling goes on the System it governs
- A lesson grows each time it proves itself - A lesson grows each time it proves itself
- A lesson names the rule it is an instance of - A lesson names the rule it is an instance of
- A note that asserts a fact can carry its own check - A note that asserts a fact can carry its own check
@@ -65,6 +67,52 @@ insight that costs time is a **lesson** (`create_lesson`), keyed to the
situation it applies to so a later session meets it there. Both are first-class situation it applies to so a later session meets it there. Both are first-class
outcomes of noticing something, not what's left when a rule proposal fails. outcomes of noticing something, not what's left when a rule proposal fails.
## A ruling goes on the System it governs
A **ruling** is the operator's decision about what the work itself does in one
area: how it behaves, what it must never do, which way a trade-off goes. It is
not a rule. A rule governs how *you* work and reaches you when your work
resembles it; a ruling governs what the *thing being built* does, and it has to
reach every session working in that area, whatever words that session is using.
Two tests, and it needs both:
- **The operator decided it.** They said it, or approved it when it was put to
them as its own question. Approving an option is not approving every
assumption the option carried — only what it named.
- **A later change could plausibly undo it.** "Failed work is retried until it
succeeds" qualifies. The name of the table that tracks the retries does not;
that is implementation, and it lives in the code and the logs.
A choice a session made on its own is not a ruling, however sound. Keeping the
two apart is the point: once code embodies a session's choice, it reads exactly
like the operator's intent, and the next session builds on it as if it were.
**Where it goes: a `Rulings` section at the end of the System's description**,
one line each — the statement, who decided, when, and the record it came from:
Rulings
- Failed work is retried until it succeeds; no attempt limit. (Operator, 2026-09-19, #1234; restated 2026-10-02, #1290)
The description arrives with every record filed under that System, so a ruling
there reaches each session working in the area without having to win a search.
A quote inside a work log does not: it surfaces only when a query happens to
match it, and the passage that matches is usually the prose around it — often a
session's *reading* of the ruling rather than the ruling.
**When: in the turn the operator decides, before building on it.**
`get_system(id)`, then `update_system(id, description=...)` with the whole
description — the field is replaced, not appended to. Also when the operator
corrects work that departed from something they had already said: that ruling
existed and did not reach the work, and writing it where it will is half the
fix. No System fits? The area is probably unnamed — create it.
**It holds what is in force, not its history.** When a ruling is overturned,
change or remove its line and cite the record that changed it; the work log
keeps the history. If the charter above the section contradicts a ruling —
usually a charter written before the decision — fix that sentence in the same
edit. A stale charter line is a ruling nobody made, and it is read as one.
## A lesson grows each time it proves itself ## A lesson grows each time it proves itself
When one arrives and the situation it names is the one you are actually in, you When one arrives and the situation it names is the one you are actually in, you
+16
View File
@@ -188,6 +188,13 @@ async def create_system(
charter, not just a label: the description is what tells a later session charter, not just a label: the description is what tells a later session
whether a record belongs here. whether a record belongs here.
The description is also where the operator's RULINGS for the area live:
a `Rulings` section at its end, one line per decision the operator made
about how this area must behave — the statement, who decided, when, and
the record it came from. The description arrives with every record filed
under the System, so a ruling there reaches each session working in the
area; a quote in a work log reaches one only if a search matches it.
Args: Args:
project_id: The project this system belongs to (required). project_id: The project this system belongs to (required).
name: Short label (required). name: Short label (required).
@@ -303,6 +310,15 @@ async def update_system(
) -> dict: ) -> dict:
"""Update a System. Only explicitly provided fields change. """Update a System. Only explicitly provided fields change.
`description` REPLACES the whole text, so read it with get_system first
and send it back entire. Recording a RULING — the operator's decision
about how this area must behave — is an edit here: add or change its line
in the `Rulings` section at the end, in the turn they decide, citing the
record it came from. Overturned, the line changes rather than gaining a
successor: the section holds what is in force, and the work log keeps the
history. If the charter above it contradicts a ruling, fix that sentence
in the same edit.
Args: Args:
status: 'active' or 'archived'. Archive a system to retire it without status: 'active' or 'archived'. Archive a system to retire it without
losing history; archived systems hide from default lists. losing history; archived systems hide from default lists.
+16
View File
@@ -195,6 +195,16 @@ TOPICS: tuple[Topic, ...] = (
("what_might_apply",), "ask what already covers that moment"), ("what_might_apply",), "ask what already covers that moment"),
Topic("reference notes update in place; dev-logs don't", U, ("reference note",), Topic("reference notes update in place; dev-logs don't", U, ("reference note",),
"state updates in place; chronicles don't"), "state updates in place; chronicles don't"),
# Milestone 444: an operator's ruling was kept only as a quote in a work
# log, beside a session's reading of it that contradicted it, and three
# later sessions built on the reading. No index marker: both fire
# mid-work — when the operator decides, and when code is read as intent.
Topic("an operator's ruling lives on the System it governs", U,
("rulings", "update_system", "the operator decided it"),
"a stale charter line is a ruling nobody made"),
Topic("code says what a thing does, not what was wanted", U,
("rulings", "unconfirmed"),
"code tells you what a thing does, not what was wanted"),
# ── process arcs — owned by their skills ── # ── process arcs — owned by their skills ──
Topic("plan in a milestone, steps created together", "skill:writing-plans", ("start_planning", "{{ref:"), Topic("plan in a milestone, steps created together", "skill:writing-plans", ("start_planning", "{{ref:"),
"a milestone earns its place when the work has an arc", index=("start_planning",)), "a milestone earns its place when the work has an arc", index=("start_planning",)),
@@ -229,6 +239,12 @@ TOPICS: tuple[Topic, ...] = (
Topic("a settled decision is acted on, not re-opened", Topic("a settled decision is acted on, not re-opened",
"skill:reporting-back", ("already made",), "skill:reporting-back", ("already made",),
"reads as contradicting yourself rather than as being careful"), "reads as contradicting yourself rather than as being careful"),
# Milestone 444: a cap a past session chose rode inside an option as a
# "known cost", the operator approved the option, and the cap read as
# theirs from then on.
Topic("an option says whose call each carried assumption was",
"skill:reporting-back", ("past session chose this", "conflict"),
"an unlabelled one gets approved as if it had been asked"),
# Milestone 409 step 8: `placement` rides a WRITE, so a task the reply only # Milestone 409 step 8: `placement` rides a WRITE, so a task the reply only
# cites arrived with nothing vouching for it — which is how a step finished # cites arrived with nothing vouching for it — which is how a step finished
# four days earlier was reported as the open one (#4154). # four days earlier was reported as the open one (#4154).