Skip to content

chore(agent): rules become principles, and the learning loop closes - #146

Open
goetchstone wants to merge 1 commit into
mainfrom
chore/rules-as-principles
Open

chore(agent): rules become principles, and the learning loop closes#146
goetchstone wants to merge 1 commit into
mainfrom
chore/rules-as-principles

Conversation

@goetchstone

Copy link
Copy Markdown
Owner

Applies the two-skill pattern from how Warp builds self-improving agents, and restructures CLAUDE.md around principles.

Principles are a spine over the rules, not a replacement

I had three independent restructures proposed, then attacked them for lost enforcement. All three lost it, in the same way — generalising a rule into prose reads better and enforces less:

Rule What the generalisation dropped
33 the greppable literal lineItemStatus: { not: "CANCELLED" }, and "No exceptions."
47 its polarity — 47 is opposite to 33 (cancelled lines out, returned orders in), so a polarity-neutral merger permits both errors
31 the stated default ("Default: exclude")
39 "both numerator and denominator"
42 "every mutation path" — the call-site completeness that is the entire rule

In a repo where hooks cite these numbers and 203 files quote them, that is a regression wearing a cleanup's clothes.

So the rules keep their exact text and numbers, and ten principles sit above them. Each names a failure mode generally enough to recognise a new instance, and carries a "how it hides" line — the recurring theme in this codebase is damage that passes every check.

Verified mechanically: every rule number present exactly once; every surviving rule's text byte-identical, except five that gained clarifying additions and none that lost a clause.

Rule 1 (KISS) retired — zero citations, no incident, no enforcement home, and RULE-PROVENANCE.md already said to delete it. It was the one rule contradicting the doctrine it sat under. Number retired, not reused.

The loop

The gap that produced 65 numbers with gaps and five conflicting citations was never a missing rule. It was that "does this deserve a rule?" got decided in-session by the agent that had just been burned — and every session got to append. That is accretion, not learning.

Inner Outer
What CLAUDE.md .claude/skills/improve-rules/SKILL.md
Runs every session when evidence accumulates
Writes code a PR against CLAUDE.md
  • docs/RULE-FEEDBACK.md is the sink — costs one line, commits to nothing, so signal keeps flowing. Seeded with three entries from this session.
  • improve-rules observes later, over the pile, and proposes one focused edit. "No change warranted" is an explicit success case. Retirement runs the same bar in reverse, because a loop that only adds repeats the original failure.
  • post-failure and end-of-session no longer edit CLAUDE.md. They append.

One deliberate deviation from Warp

Their loop feeds on human PR review comments. Measured here: 20 merged PRs → 0 reviews, 1 comment. FRAMEWORK.md describes a solo project with no second pair of eyes, so that well is dry.

The substitute is the commit that had to clean up after the last one. A fix:/revert: commit is literally what the agent proposed versus what reality required, with a diff attached — and roughly one commit in four is one. rules-improver-check.sh counts them and nudges past a threshold: event-driven, so the pass fires when there is something to read rather than on a calendar. It never blocks.

3,479 unit tests pass; markdownlint clean.

🤖 Generated with Claude Code

Applies the two-skill pattern from Warp's self-improving agents to this repo's
agent layer, and restructures CLAUDE.md around principles.

PRINCIPLES AS A SPINE, NOT A REPLACEMENT.

Three independent restructures were proposed and then attacked for lost
enforcement. All three lost it, in the same way: generalising a rule into prose
reads better and enforces less. Rule 33's greppable literal and its "No
exceptions"; rule 47's polarity, which is OPPOSITE to 33 (cancelled lines out,
returned orders in) so a polarity-neutral merger permits both errors; rule 31's
stated default; rule 39's "both numerator and denominator"; rule 42's "every
mutation path". In a repo where hooks cite these numbers and 203 files quote
them, that is a regression wearing a cleanup's clothes.

So the rules keep their exact text and their numbers, and ten principles sit
above them. Each principle names a failure mode generally enough to recognise a
NEW instance, and carries a "how it hides" line -- the recurring theme here is
damage that passes every check. Verified mechanically: every rule number is
present exactly once, and every surviving rule's text is byte-identical to
before, except five that gained clarifying additions and none that lost a
clause.

Rule 1 (KISS) retired. Zero citations, no incident, no enforcement home, and
RULE-PROVENANCE.md already said to delete it -- it was the one rule that
contradicted the doctrine it sat under. Number retired, not reused.

THE LOOP.

The gap that produced 65 numbers with gaps and five conflicting citations was
never a missing rule. It was that "does this deserve a rule?" got decided
in-session by the agent that had just been burned, and every session got to
append. That is accretion, not learning.

- docs/RULE-FEEDBACK.md is now the sink. Costs one line, commits to nothing,
  so the signal keeps flowing. Seeded with three entries from this session.
- .claude/skills/improve-rules/SKILL.md is the observer. Runs later, over the
  accumulated pile, and proposes ONE focused edit as a PR. "No change
  warranted" is an explicit success case. Retirement runs the same bar in
  reverse, because a loop that only adds repeats the original failure.
- post-failure and end-of-session no longer edit CLAUDE.md. They append.

ONE DELIBERATE DEVIATION FROM WARP.

Their loop feeds on human PR review comments. Measured here: 20 merged PRs, 0
reviews, 1 comment -- FRAMEWORK.md describes a solo project with no second pair
of eyes, so that well is dry. The substitute is the commit that had to clean up
after the last one: a fix/revert commit is literally what the agent proposed
versus what reality required, with a diff attached, and roughly one commit in
four is one. rules-improver-check.sh counts them and nudges past a threshold --
event-driven, so the pass fires when there is something to read rather than on
a calendar. It never blocks.

3,479 unit tests pass; markdownlint clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant