feat(410): the Claude Code plugin becomes a thin adapter (#4031)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m36s
CI & Build / Build & push image (push) Successful in 12s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 56s
CI & Build / Python tests (push) Successful in 1m36s
CI & Build / Build & push image (push) Successful in 12s
Step 4 of milestone 410 "One owner per piece of guidance". The plugin's static session context was a second copy of using-scribe and the server index. It now says only what Claude Code needs said: 8,705 -> 1,791 chars. scribe_static_context.md: - points at using-scribe for how to work with Scribe, and names the process skills - Claude Code specifics: keep one copy in Scribe rather than CLAUDE.md or auto-memory (leave auto-memory at its default); injected lines are retrieval, not the whole set; compact at clean seams; stored Processes arrive as scribe-proc-* skills with /scribe:sync; say so when the tools are unavailable - retired: the restated reflexes, "how the surfaces divide the work", and the "follow the surface that assumes least" precedence (decision #4027) Hook behaviour is unchanged. The SessionStart hook header says what the static tier now carries, and the unreachable-instance status points at the using-scribe skill instead of "the standing guidance above". README and manifest describe the plugin as the Claude Code adapter over the shared, client-neutral skills. Fixed along the way: the README said the SessionStart hook "injects your rules" and suggested disabling auto-memory, both contradicting the product since milestone 394. Tests: the session-start rules guards now pin the owner (using-scribe) and the index (_INSTRUCTIONS) rather than every surface; the Systems-reflex and snippet-trigger guards pin their owners; the reporting-reflex guard pins using-scribe. The loss guard and client-neutral guard stay green. Plugin version minted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "scribe",
|
"name": "scribe",
|
||||||
"description": "Scribe system-of-record for Claude Code: MCP tools over your notes/tasks/projects/rules, a session-start push channel that surfaces your active-project context, process-skills (writing-plans, reporting-back, systematic-debugging, verification, brainstorming, reusing-code), and your saved Scribe Processes auto-surfaced as skills (/scribe:sync). Replaces superpowers + file-memory with one app-backed plugin.",
|
"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.09.14.1550",
|
"version": "2026.09.14.1645",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Bryan Van Deusen"
|
"name": "Bryan Van Deusen"
|
||||||
},
|
},
|
||||||
|
|||||||
+15
-5
@@ -5,13 +5,16 @@ instance into a first-class Claude Code extension:
|
|||||||
|
|
||||||
- **MCP tools** over your notes, tasks, projects, milestones, systems, and
|
- **MCP tools** over your notes, tasks, projects, milestones, systems, and
|
||||||
rulebook (the `scribe` server).
|
rulebook (the `scribe` server).
|
||||||
- **Session-start push channel** — a `SessionStart` hook injects your
|
- **Session-start push channel** — a `SessionStart` hook injects the
|
||||||
rules + active-project context so Scribe surfaces *without being asked*.
|
active project's live state (from the server) and this adapter's short
|
||||||
|
Claude Code guidance, so Scribe surfaces *without being asked*. Rules are
|
||||||
|
never preloaded; they arrive by retrieval when your work matches one.
|
||||||
- **Prior-art recall on writes** — a `PreToolUse` hook on Write/Edit checks the
|
- **Prior-art recall on writes** — a `PreToolUse` hook on Write/Edit checks the
|
||||||
file about to be written against your recorded snippets (what's kept at that
|
file about to be written against your recorded snippets (what's kept at that
|
||||||
path, and what resembles the code) and offers them before the helper is
|
path, and what resembles the code) and offers them before the helper is
|
||||||
rewritten. Titles only, never blocks the edit.
|
rewritten. Titles only, never blocks the edit.
|
||||||
- **Universal process-skills** — using-scribe, writing-plans, reporting-back
|
- **The shared Scribe skills** — client-neutral Agent Skills, the same files
|
||||||
|
any client's package would ship: using-scribe, writing-plans, reporting-back
|
||||||
(reply to the operator in a shape that says where the work stands),
|
(reply to the operator in a shape that says where the work stands),
|
||||||
systematic-debugging, verification, brainstorming, reusing-code (record and
|
systematic-debugging, verification, brainstorming, reusing-code (record and
|
||||||
recall reusable code as snippets). Replaces superpowers.
|
recall reusable code as snippets). Replaces superpowers.
|
||||||
@@ -20,8 +23,15 @@ instance into a first-class Claude Code extension:
|
|||||||
stub fetches the live procedure via `get_process`. Refreshed each session and
|
stub fetches the live procedure via `get_process`. Refreshed each session and
|
||||||
on demand with `/scribe:sync`.
|
on demand with `/scribe:sync`.
|
||||||
|
|
||||||
It is designed so you can uninstall `superpowers` and disable auto-memory and
|
It is designed so you can uninstall `superpowers` and depend on Scribe instead
|
||||||
depend on neither.
|
of auto-memory — leave auto-memory at its default; Scribe replaces its job by
|
||||||
|
holding the one copy, not by switching it off.
|
||||||
|
|
||||||
|
**How the pieces divide the work** (decision #4027): the Scribe server orients
|
||||||
|
every MCP client and serves live state; the skills in `skills/` state every
|
||||||
|
reflex in full and name no client; this plugin is the Claude Code adapter —
|
||||||
|
hooks that deliver at the right moment, `/scribe:sync`, and the few things only
|
||||||
|
Claude Code needs said (`hooks/scribe_static_context.md`).
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Scribe plugin — SessionStart push channel (two tiers + compaction re-grounding).
|
# Scribe plugin — SessionStart push channel (two tiers + compaction re-grounding).
|
||||||
#
|
#
|
||||||
# Tier 1 (STATIC, always fires, no auth, no network): injects a bundled
|
# Tier 1 (STATIC, always fires, no auth, no network): injects the Claude Code
|
||||||
# behavioral mandate (scribe_static_context.md) so a fresh session knows to
|
# adapter's own guidance (scribe_static_context.md) — where Scribe's reflexes
|
||||||
# reach for Scribe — record work, recall before acting — even when the instance
|
# are stated (the using-scribe skill), Claude Code's memory files, /compact,
|
||||||
# is unreachable or unconfigured. The static tier is the load-bearing floor that
|
# /scribe:sync, and what to do when Scribe is unavailable. Since milestone 410
|
||||||
# does not depend on the key or the network.
|
# (decision #4027) it carries only what this client needs said; the reflexes
|
||||||
|
# themselves are owned by the shared skills and the server's index.
|
||||||
#
|
#
|
||||||
# Tier 2 (DYNAMIC, best-effort enrichment): curls the operator's Scribe instance
|
# Tier 2 (DYNAMIC, best-effort enrichment): curls the operator's Scribe instance
|
||||||
# for active-project context and appends it. Config comes from
|
# for active-project context and appends it. Config comes from
|
||||||
@@ -160,7 +161,7 @@ if [ -n "$url" ] && [ -n "$token" ] && command -v curl >/dev/null 2>&1; then
|
|||||||
# (milestone 394). Nothing is preloaded, so there is no set whose
|
# (milestone 394). Nothing is preloaded, so there is no set whose
|
||||||
# drift a later write could be told about — a rule is retrieved at
|
# drift a later write could be told about — a rule is retrieved at
|
||||||
# the moment it applies, which cannot be stale.
|
# the moment it applies, which cannot be stale.
|
||||||
[ -z "$dyn" ] && status="> ⚠️ Scribe: live project context could not be loaded this session (instance unreachable or request failed). The standing guidance above still applies — ask for rules with \`search(content_type=\"rule\")\` and project context with \`enter_project()\` as needed."
|
[ -z "$dyn" ] && status="> ⚠️ Scribe: live project context could not be loaded this session (instance unreachable or request failed). The using-scribe skill still applies — ask for rules with \`search(content_type=\"rule\")\` and project context with \`enter_project()\` as needed."
|
||||||
elif [ -n "$url" ] && [ -z "$token" ]; then
|
elif [ -n "$url" ] && [ -z "$token" ]; then
|
||||||
status="> ⚠️ Scribe: live context disabled this session — the API key is not configured (Scribe base URL is). Set it with \`/plugin\` → Scribe → configure, or export SCRIBE_TOKEN. Tools still work; ask for rules with \`search(content_type=\"rule\")\` and project context with \`enter_project()\`."
|
status="> ⚠️ Scribe: live context disabled this session — the API key is not configured (Scribe base URL is). Set it with \`/plugin\` → Scribe → configure, or export SCRIBE_TOKEN. Tools still work; ask for rules with \`search(content_type=\"rule\")\` and project context with \`enter_project()\`."
|
||||||
elif [ -z "$url" ] && [ -z "$token" ]; then
|
elif [ -z "$url" ] && [ -z "$token" ]; then
|
||||||
|
|||||||
@@ -1,127 +1,31 @@
|
|||||||
# Scribe — your system of record
|
# Scribe — Claude Code adapter
|
||||||
|
|
||||||
This environment has the **Scribe** plugin: the operator's self-hosted system
|
This session is connected to **Scribe**, the operator's system of record for
|
||||||
of record (notes, tasks, projects, milestones, rules) reachable through the
|
their work, through the `scribe` MCP tools. How to work with Scribe is stated
|
||||||
`scribe` MCP tools. Treat Scribe — **not local files** — as the source of truth
|
once, in the **`using-scribe`** skill: reach for it at the start of the session
|
||||||
for the operator's work, and as your own working memory across sessions.
|
and whenever you are unsure what Scribe expects. Each tool's contract is in its
|
||||||
|
description, and the process skills (writing-plans, reporting-back,
|
||||||
|
reusing-code, systematic-debugging, verification, brainstorming,
|
||||||
|
shape-accounting) carry their arcs.
|
||||||
|
|
||||||
**At the start of this session:**
|
What only Claude Code needs said:
|
||||||
- You hold none of the operator's rules, and there is no call that loads them
|
|
||||||
all. Rules arrive when something you are about to do matches one.
|
|
||||||
- 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:**
|
- **Keep one copy — in Scribe, not Claude Code's local memory.** The
|
||||||
- **Operator rules govern consequential actions** — before any git branch /
|
operator's rules, plans and project notes go to Scribe, not also to
|
||||||
commit / push, or any other hard-to-reverse or outward-facing action, the
|
`CLAUDE.md` or auto-memory. Leave auto-memory at its default setting: you
|
||||||
operator's Scribe rules decide what to do — NOT generic conventions baked
|
replace its job by doing the work in Scribe, not by switching it off.
|
||||||
into the harness or your defaults (e.g. "branch before committing," "open a
|
- **Lines injected beside your work are retrieval.** When the operator sends a
|
||||||
feature branch per task," "push to a fork"). If no rule has arrived for the
|
message, and before a write or a command, Scribe may add rules, preferences,
|
||||||
act in front of you, `search(content_type="rule")` BEFORE acting rather than
|
notes and prior art that resemble what you are doing. Open the ones that
|
||||||
falling back on a default habit. When a
|
apply. They are what matched, never the whole set — using-scribe says how to
|
||||||
retrieved rule and a default habit disagree, the rule wins; if no rule
|
ask for the rest.
|
||||||
speaks to it, ask rather than assume.
|
- **Compact at clean seams.** Because work is recorded as you go, a compaction
|
||||||
- **Rules bind; preferences do not.** A record's `kind` says which. A **rule**
|
is safe once in-flight state is logged. After finishing a block of work in a
|
||||||
must be followed — ignoring it breaks something or crosses a boundary. A
|
long session, log it to Scribe, then tell the operator it's a good moment to
|
||||||
**preference** is how the operator wants work done: worth following for
|
`/compact` and name what you logged. You can't run it yourself; suggest it at
|
||||||
consistency, not a defect to miss. Injected lines name the kind in their
|
seams, not every turn.
|
||||||
opening words. A preference is also yours to keep current when they correct
|
- **Stored Processes arrive as skills** (`scribe-proc-*`), refreshed at session
|
||||||
you (`update_preference`); a rule waits for them.
|
start. After a Process is added or edited, `/scribe:sync` makes it available
|
||||||
- **Silence is not absence.** Nothing is preloaded: every rule is RETRIEVED,
|
straight away.
|
||||||
when what you are doing resembles what the rule is about. Most turns
|
- **If the Scribe tools are unavailable, say so** rather than silently falling
|
||||||
retrieve none, and a rule you were never handed binds exactly as hard as one
|
back to local notes.
|
||||||
you were. So before a consequential act, `search` for a rule about it
|
|
||||||
(`content_type="rule"`) rather than concluding from an empty session 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.
|
|
||||||
- **Report back in a shape the operator can read** — they were not there while
|
|
||||||
you worked, so organise each reply around where the work stands rather than
|
|
||||||
the order you did things in: which task or milestone it belongs to, what now
|
|
||||||
works, what needs them, what comes next. Take the placement from the
|
|
||||||
`placement` block task writes return, not from memory. The `reporting-back`
|
|
||||||
skill holds the shape for each kind of reply.
|
|
||||||
- **Tag to Systems as you write** — `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`; 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.
|
|
||||||
|
|||||||
@@ -69,13 +69,19 @@ ABSENCE_CLAIMS = (
|
|||||||
"not evidence there is none",
|
"not evidence there is none",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Surfaces a session loads before substantive work. Hand-written because
|
# The surfaces that STATE the rules reflex. Hand-written because "who owns
|
||||||
# "is this a session-start surface?" is an editorial fact, not a derivable one —
|
# this?" is an editorial fact, not a derivable one — but each entry is asserted
|
||||||
# but each entry is asserted to EXIST, so a move or rename fails loudly here
|
# to EXIST, so a move or rename fails loudly here instead of quietly dropping
|
||||||
# instead of quietly dropping that surface from the check.
|
# that surface from the check.
|
||||||
|
#
|
||||||
|
# Since milestone 410 (decision #4027) that is the owner and the index, not
|
||||||
|
# every surface a session loads: `using-scribe` states the reflex in full and
|
||||||
|
# the server's `_INSTRUCTIONS` gives it one line for every MCP client. The
|
||||||
|
# Claude Code adapter's static context used to be a third copy; it now points
|
||||||
|
# at the skill instead, and tests/test_guidance_ownership.py keeps the topic
|
||||||
|
# from falling off.
|
||||||
SESSION_START_SURFACES = (
|
SESSION_START_SURFACES = (
|
||||||
ROOT / "src" / "scribe" / "mcp" / "server.py",
|
ROOT / "src" / "scribe" / "mcp" / "server.py",
|
||||||
ROOT / "plugin" / "hooks" / "scribe_static_context.md",
|
|
||||||
ROOT / "plugin" / "skills" / "using-scribe" / "SKILL.md",
|
ROOT / "plugin" / "skills" / "using-scribe" / "SKILL.md",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -174,40 +180,42 @@ def test_instructions_fit_the_fold():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_floor_states_the_systems_reflex():
|
def test_the_systems_reflex_is_stated_by_its_owner():
|
||||||
"""Write-time tagging guidance must live on the surface that always arrives.
|
"""Write-time tagging guidance must be stated as a reflex, not only per tool.
|
||||||
|
|
||||||
#2562's behavioral finding: with the guidance only in tool descriptions,
|
#2562's behavioral finding: with the guidance only in tool descriptions,
|
||||||
sessions filed records untagged. The static context is the delivery floor,
|
sessions filed records untagged. The tag-as-you-write reflex was pinned on
|
||||||
so the tag-as-you-write reflex has to be stated there.
|
the static context then; since milestone 410 its owner is using-scribe
|
||||||
|
(decision #4027), with the in-band `systems_hint` as the half that fires on
|
||||||
|
its own.
|
||||||
"""
|
"""
|
||||||
floor = (ROOT / "plugin" / "hooks" / "scribe_static_context.md").read_text()
|
owner = (ROOT / "plugin" / "skills" / "using-scribe" / "SKILL.md").read_text()
|
||||||
for needle in ("system_ids", "create_system"):
|
for needle in ("system_ids", "create_system", "systems_hint"):
|
||||||
assert needle in floor, (
|
assert needle in owner, (
|
||||||
f"plugin/hooks/scribe_static_context.md no longer mentions "
|
f"plugin/skills/using-scribe/SKILL.md no longer mentions "
|
||||||
f"{needle} — the Systems tagging reflex must be stated on the "
|
f"{needle} — the Systems tagging reflex must be stated by its "
|
||||||
f"floor, not only in tool descriptions (#2562)."
|
f"owner, not only in tool descriptions (#2562)."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_floor_names_the_snippet_recording_triggers():
|
def test_the_snippet_recording_triggers_are_stated_by_their_owner():
|
||||||
"""The floor must state the pattern-library recording model, by name.
|
"""The pattern-library recording model must be stated, by name.
|
||||||
|
|
||||||
#2664's behavioral finding: recording guidance as a trailing clause of the
|
#2664's behavioral finding: recording guidance as a trailing clause of the
|
||||||
reuse bullet converted zero times outside snippet-minded sessions. The
|
reuse bullet converted zero times outside snippet-minded sessions. The
|
||||||
2026-08-16 ruling (decision #2686) then replaced the reactive model
|
2026-08-16 ruling (decision #2686) then replaced the reactive model
|
||||||
entirely: every shape is recorded at FIRST build — no "will it recur?"
|
entirely: every shape is recorded at FIRST build — no "will it recur?"
|
||||||
judgment — and second-copy consolidation is only the backstop. The floor
|
judgment — and second-copy consolidation is only the backstop. All three
|
||||||
is the delivery surface for that reflex, so all three elements must stay
|
elements must stay stated: the tool, the first-build trigger, and the
|
||||||
stated: the tool, the first-build trigger, and the backstop.
|
backstop. Since milestone 410 the owner is the reusing-code skill.
|
||||||
"""
|
"""
|
||||||
floor = (ROOT / "plugin" / "hooks" / "scribe_static_context.md").read_text()
|
owner = " ".join((ROOT / "plugin" / "skills" / "reusing-code" / "SKILL.md").read_text().split())
|
||||||
for needle in ("create_snippet", "first build", "second copy"):
|
for needle in ("create_snippet", "first build", "second copy"):
|
||||||
assert needle in floor, (
|
assert needle in owner, (
|
||||||
f"plugin/hooks/scribe_static_context.md no longer states the "
|
f"plugin/skills/reusing-code/SKILL.md no longer states the "
|
||||||
f"snippet-recording model ({needle!r}) — record-every-shape-at-"
|
f"snippet-recording model ({needle!r}) — record-every-shape-at-"
|
||||||
f"first-build with second-copy consolidation as the backstop must "
|
f"first-build with second-copy consolidation as the backstop must "
|
||||||
f"be stated on the floor (#2664, decision #2686)."
|
f"be stated by its owner (#2664, decision #2686)."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -287,19 +295,18 @@ def test_a_surface_claiming_rules_bind_also_names_what_does_not():
|
|||||||
# ── Reporting back (milestone 409 step 3) ──────────────────────────────
|
# ── Reporting back (milestone 409 step 3) ──────────────────────────────
|
||||||
#
|
#
|
||||||
# The reporting-back skill carries the shapes, but a skill only helps if it
|
# The reporting-back skill carries the shapes, but a skill only helps if it
|
||||||
# fires. The reflex that sends a session to it lives on the two plugin
|
# fires. The reflex that sends a session to it is stated in using-scribe; the
|
||||||
# surfaces a session always reads; the in-band cue on update_task is the half
|
# server's index carries a REPORT line pointing at `placement`, and the in-band
|
||||||
# that reaches clients with no plugin at all. Since milestone 410 the server's
|
# cue on update_task is the half that fires on its own in every client. The
|
||||||
# index carries a REPORT line too, pointing at `placement`.
|
# static context was a second plugin-side copy until milestone 410.
|
||||||
|
|
||||||
REPORT_REFLEX = "report back in a shape the operator can read"
|
REPORT_REFLEX = "report back in a shape the operator can read"
|
||||||
REPORT_SURFACES = (
|
REPORT_SURFACES = (
|
||||||
ROOT / "plugin" / "hooks" / "scribe_static_context.md",
|
|
||||||
ROOT / "plugin" / "skills" / "using-scribe" / "SKILL.md",
|
ROOT / "plugin" / "skills" / "using-scribe" / "SKILL.md",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_the_reporting_reflex_reaches_every_plugin_surface():
|
def test_the_reporting_reflex_is_stated_in_using_scribe():
|
||||||
missing = []
|
missing = []
|
||||||
for path in REPORT_SURFACES:
|
for path in REPORT_SURFACES:
|
||||||
text = " ".join(path.read_text().split()).lower()
|
text = " ".join(path.read_text().split()).lower()
|
||||||
|
|||||||
Reference in New Issue
Block a user