A self-improvement loop for Claude Code: a Stop hook
catches corrections and repeated instructions from the user, a skill records them as
lessons, and repeated lessons escalate into an automatic edit of a skill or CLAUDE.md.
-
Hook — a
Stophook (lessons-guard.sh) scans the user's messages from the current turn against a list of correction markers ("not like that", "you forgot", "первый раз", "не так", etc.). Service messages (tool results, other agents, the hook's own feedback) are filtered out. -
If a marker matches, the hook blocks completion and sends the assistant into the skill (
skills/lessons/SKILL.md), which classifies what happened: a one-off task-level decision (ignored), a correction lesson, or a repeated-pattern lesson. -
A real lesson is written as a record with an episode counter (
occurrences) in~/.claude/lessons/(global) or the project's memory (project-specific). -
Repeated, independent episodes of the same lesson escalate:
Episode What happens 1 Recorded silently. 2 One warning line at the end of the reply. 3+ The lesson graduates: the skill auto-edits the relevant skill file, CLAUDE.md, or a scoped rule, and reports the change.An episode only counts as independent if it comes from a different session, or a different, unrelated chunk of work in the same session — repeating the same correction back-to-back until it lands is one episode, not several.
Escalation only edits files the user owns (their own skills, CLAUDE.md, ~/.claude/rules/).
It never touches ~/.claude/plugins/cache/ or anything installed from a marketplace —
for those, at episode 3 the skill offers to make a local copy first, and only edits it
after explicit consent.
claude plugin marketplace add RoboNET/claude-lessons
claude plugin install lessons@claude-lessons
Or via the /plugin command inside Claude Code:
/plugin marketplace add RoboNET/claude-lessons
/plugin install lessons@claude-lessons
- Markers — drop your own list at
~/.claude/lessons-markers.txtto fully replace the bundled defaults (one phrase per line; matching is plain substring, case-sensitive). The bundled list covers ten languages: English, Russian, Spanish, Portuguese, French, German, Italian, Japanese, Chinese, Korean. Chinese and Japanese only cover correction-style markers ("that's wrong", "you forgot") — instruction formulas like "first …" aren't included for these, since without word boundaries a bare "first" is unsafe as a substring in languages that don't separate words with spaces. - Lines starting with
#are treated as comments (e.g.# Spanishsection headers) and never match as patterns — this applies both to the bundled file and to your own~/.claude/lessons-markers.txt. LESSONS_MARKERS_FILE— env var pointing at an alternate markers file, takes priority over~/.claude/lessons-markers.txt.LESSONS_STATE_DIR— where the hook keeps its per-session read offset into the transcript (default~/.claude/.lessons-state).
- Global lessons (apply to any project):
~/.claude/lessons/, indexed by~/.claude/lessons/LESSONS.md. - Project-specific lessons: the project's own Claude Code memory directory,
indexed by its
MEMORY.md.
Run /lessons at any point to trigger a full retro over the session (or a named chunk
of work) instead of waiting for a correction marker. It reviews four categories —
corrections, friction/repeated instructions, skill gaps, and knowledge gaps — and ends
with a summary of what was recorded and what was already covered.
The hook is safe by default: any error (missing file, malformed JSON, unwritable
state directory) makes it exit cleanly without blocking anything. It never blocks
twice in a row for the same turn (stop_hook_active guard against loops), and it
ignores tool output, isMeta messages, and messages from other agents so it only
reacts to what the user actually typed.
MIT — see LICENSE.