Lessons: the accretion reflex, and telemetry that can see across projects (#4195, #4196, #3735) #170

Merged
bvandeusen merged 3 commits from dev into main 2026-09-19 23:36:31 -04:00
4 changed files with 43 additions and 12 deletions
Showing only changes of commit 26a757ecfe - Show all commits
+1 -1
View File
@@ -1,7 +1,7 @@
{
"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).",
"version": "2026.09.19.1614",
"version": "2026.09.20.0317",
"author": {
"name": "Bryan Van Deusen"
},
+21 -9
View File
@@ -110,15 +110,27 @@ Two constraints on *how* that's achieved:
silently, because it sometimes answers that what you are holding was never
a rule — and routing an observation is not losing it.
**A preference is the one record you keep current yourself.** When the
operator corrects you, or the preference on file no longer matches how they
actually want something done, `update_preference` — that is expected, not a
liberty, and updating one mid-work is the normal case rather than an
interruption of it. It wants the task or note that taught the change. Say in the
same turn that you did it, so they can disagree while it is in front of
them. A rule waits for the operator instead: `create_rule` proposes and
asks. If what you learned is that something MUST be done a certain way,
that is a rule to propose, not a preference to harden in place.
**A preference is yours to keep current.** When the operator corrects you,
or the preference on file no longer matches how they actually want
something done, `update_preference` — that is expected, not a liberty, and
updating one mid-work is the normal case rather than an interruption of it.
It wants the task or note that taught the change. Say in the same turn that
you did it, so they can disagree while it is in front of them. A rule waits
for the operator instead: `create_rule` proposes and asks. If what you
learned is that something MUST be done a certain way, that is a rule to
propose, not a preference to harden in place.
**A lesson grows each time it proves itself.** When one arrives and the
situation it names is the one you are actually in, you are the single
reader placed to tell whether its trigger is keyed right and whether its
claim covers what you are seeing. `update_lesson` takes what you now know:
another incident added to what taught it, the claim stated more exactly,
or — the edit worth most — a trigger re-keyed to the situation that really
fired. A lesson nobody reaches is seldom wrong; far more often it is
waiting in a situation nobody is in. One claim that has met the same
failure four times is worth more than four claims that each met it once,
so when a near-duplicate create hands back an existing id, that is the
record to grow.
**Preferences shape how work is done, never what gets recorded.** They
govern your conduct — how you report, how carefully you pace, which form
+11 -1
View File
@@ -178,7 +178,17 @@ async def create_lesson(
async def get_lesson(lesson_id: int) -> dict:
"""Fetch one lesson by id, with its trigger and sources read back out."""
"""Fetch one lesson by id, with its trigger and sources read back out.
IF THIS LESSON JUST PROVED ITSELF, IT IS WORTH MORE THAN IT SAYS. You are
reading it inside the situation it names, which makes you the one reader
who can tell whether its trigger is keyed to what actually fired and
whether its claim covers what you are seeing. `update_lesson` takes
another incident into `learned_from`, a claim stated more exactly, or a
re-keyed trigger — and the trigger is the edit that pays most, because a
lesson keyed to a situation nobody is in looks exactly like one nobody
needed.
"""
uid = current_user_id()
note = await lessons_svc.get_lesson(uid, lesson_id)
if note is None:
+10 -1
View File
@@ -118,7 +118,8 @@ TOPICS: tuple[Topic, ...] = (
"an empty session is not evidence of an empty rulebook",
index=('content_type="rule"', "nothing matched")),
Topic("rules bind, preferences guide and are kept current", U, ("preference", "update_preference"),
"a preference is the one record you keep current yourself", index=("preferences guide",)),
"updating one mid-work is the normal case rather than an interruption of it",
index=("preferences guide",)),
Topic("kind is force: a rule binds, a preference guides, a lesson informs", U,
("lesson", "costs time", "costs consistency"),
"what happens if someone doesn't do this",
@@ -129,6 +130,14 @@ TOPICS: tuple[Topic, ...] = (
# mis-routing #3733 recorded happens, and the caller there has not
# necessarily read the skill.
shared_with=("docstrings",)),
Topic("a lesson grows each time it proves itself", U,
("update_lesson", "re-keyed", "grows each time"),
"one claim that has met the same failure four times is worth more "
"than four claims that each met it once",
# No index marker. The index names session-START reflexes, and this
# one fires mid-work, the moment a lesson arrives in a situation it
# actually names. `lessons inform` already points at the kind.
shared_with=("docstrings",)),
Topic("preferences shape how work is done, never what is recorded", U,
("never what gets recorded",),
"a preference never makes a task into a note"),