Skip to content

Latest commit

 

History

251 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lessons-learned

CI Docs License: MIT Node.js Claude Code Codex CLI Gemini CLI opencode Discord

Stop repeating Claude's mistakes. Every session, automatically.

Animated terminal demo of lessons-learned capturing a mistake and preventing it from repeating

Real /lessons:manage conversation and a real PreToolUse injection, not staged — see website/static/demo.tape to reproduce it.

137 active lessons · 87 eval scenarios measuring whether injection actually changes behavior · 37 pages of docs · 4 platforms (Claude Code, Codex CLI, Gemini CLI, opencode)

# Step 1 — add the marketplace (once per machine)
claude plugin marketplace add joeblackwaslike/agent-marketplace

# Step 2 — install the plugin
claude plugin install lessons-learned@agent-marketplace
  • Captures mistakes from session logs — structured tags and heuristic scanning
  • Injects relevant warnings before tool calls at the exact moment they're needed
  • Compounds — every session adds to a persistent store that follows you across projects

Why this exists

Claude is stateless. Every session forgets every correction, every footgun hit, every git stash that silently dropped untracked files. Over long agentic runs, the same class of mistake appears again and again — because nothing carries forward.

lessons-learned creates a persistent, compounding memory of failure patterns. Mistakes are captured automatically from session logs. A background scanner extracts candidates, you promote the ones worth keeping, and the next time Claude is about to make the same move, a warning surfaces at the exact tool call where it matters.

The feedback loop tightens over time. The more sessions, the stronger the prevention.


See it in action

Step 1 — Claude makes a mistake and emits a lesson tag: this one is real — genuinely emitted mid-session while building the recording below, after Claude Code's own Safety Net guard blocked a cd-then-rm -rf Bash call twice in a row:

#lesson
tool: Bash
trigger: cd <dir> && rm -rf <path>
problem: Combining `cd` into a target directory with `rm -rf` in the same Bash
         call gets blocked by Claude Code's Safety Net guard, even when the
         resulting path is otherwise a legitimate scratch/temp location — the
         guard flags the cd+rm-rf co-occurrence pattern itself, not just
         literal out-of-cwd path resolution.
solution: Never combine `cd` and `rm -rf` in the same Bash invocation. Either
          `cd` first as its own call (the working directory persists across
          Bash calls), then issue `rm -rf` as a separate, later call — or use
          `rm -rf <absolute-or-explicit-relative-path>` directly, no `cd`.
tags: tool:bash, tool:safety-net, severity:blocked-workflow
#/lesson

Step 2 — Next session, discover and promote it — captured live and unstaged (real Claude Code, real plugin, a real scratch database) via /lessons:manage, one of several /lessons:* commands for browsing, promoting, and auditing lessons conversationally, no path to your checkout and no flags to remember:

Live Claude Code session running /lessons:manage, showing the real candidate and its problem/solution text

Reproduce it with vhs website/static/demo-live.tape (requires vhs and a claude login — budget a few minutes; it's a real model call, not a replay, so timing and wording vary between runs).

Equivalent CLI, for local development against a cloned checkout
$ node scripts/lessons.mjs scan --verbose
[scan] New candidates: 1 | Duplicates skipped: 0 | Total in DB: 47

$ node scripts/lessons.mjs review
1 pass, 0 fail

$ node scripts/lessons.mjs promote --ids 01KZHWHQY4MHBKBZR0245NDVV9
Promoted 1 lesson(s). Built manifest: 1 lessons included, 0 excluded.

scripts/lessons.mjs only exists inside a clone of this repo — it's the plugin's own internals, not something an installed plugin exposes a path to. Everyday use is /lessons:*; see Slash Commands for the full set.

Step 3 — Warning fires before the next cd+rm -rf (this is the actual additionalContext a PreToolUse hook injects, extracted with jq):

<details>
<summary>[lessons-learned] 1 lesson matched for `cd /tmp/scratch && rm -rf old-build` — <em>Why am I seeing this?</em></summary>

The **[lessons-learned](https://github.com/joeblackwaslike/lessons-learned)**
plugin matched this tool call against known pitfall patterns and injected
the following warnings for Claude to consider before executing.

---

## Lesson: Combining `cd` into a target directory with `rm -rf` in the same Bash call gets blocked by Claude Code's Safety Net...
Combining `cd` into a target directory with `rm -rf` in the same Bash call
gets blocked by Claude Code's Safety Net guard, even when the resulting path
is otherwise a legitimate scratch/temp location -- the guard flags the
cd+rm-rf co-occurrence pattern itself, not just literal out-of-cwd path
resolution.
**Fix**: Never combine `cd` and `rm -rf` in the same Bash invocation. Either
`cd` first as its own call (the working directory persists across Bash
calls), then issue `rm -rf` as a separate, later call -- or use
`rm -rf <absolute-or-explicit-relative-path>` directly, no `cd`.

</details>

The demo GIF at the top of this page is one continuous real /lessons:manage conversation — discovering and promoting a genuinely captured #lesson tag — then asking that same live session to clean up a scratch build directory. The just-promoted lesson is genuinely active in that session's manifest, so real injected context (not a simulation) steers the agent away from combining cd and rm -rf, the same prevention Step 3 shows the raw injected text for above, demonstrated live instead of extracted. Reproduce it with vhs website/static/demo.tape (requires vhs and a claude login on PATH; budget a few minutes and real API usage — it's a real model session, not a replay, so timing and exact wording vary between runs). For reviewing a full batch of pending candidates one at a time, /lessons:review is the recommended day-to-day command.


Install

Platform Install
Claude Code claude plugin marketplace add joeblackwaslike/agent-marketplace then claude plugin install lessons-learned@agent-marketplace
Codex CLI codex plugin marketplace add joeblackwaslike/agent-marketplace then codex plugin install lessons-learned@agent-marketplace
Gemini CLI Clone repo, run LESSONS_AGENT_PLATFORM=gemini node scripts/lessons.mjs onboard
opencode Same as Claude Code — tool names match
Cursor node scripts/lessons.mjs list --json > .cursorrules
Manual/MCP Coming soon (see Roadmap)

Requirements: Node.js ≥ 22.5

For manual hook wiring and platform-specific config, see Installation.


How it works

graph LR
    subgraph "Session Start"
        SS1["Inject protocol\nand directives"]
        SS2["Background scan\nTier 1/2/3/4"]
        SS3["Reset dedup state"]
    end
    subgraph "Per Tool Call"
        PT["matchLessons()\ntool + pattern + path"]
        PO["Context monitor\nre-inject at 30/52/70%"]
    end
    subgraph "Data"
        DB[(lessons.db)]
        MF["lesson-manifest.json"]
    end
    SS2 --> DB
    DB --> MF
    PT --> MF
    PO --> MF
Loading
  1. Capture — Claude emits #lesson tags in responses; the background scanner processes previous session JSONL files on startup using up to 4 tiers (structured tags, heuristic patterns, structural insights, LLM deep scan)
  2. Review & promote — Candidates land in lessons.db; lessons review validates them (PASS/FAIL, read-only) and lessons promote --ids ... moves the ones worth keeping to active
  3. Buildlessons build pre-compiles regexes into lesson-manifest.json for zero-latency runtime lookup
  4. Inject — At each PreToolUse event, matchLessons() checks tool name + command patterns + file paths; matching lessons prepend as additionalContext before the tool runs

Platforms

Platform Status Notes
Claude Code First-class Bash, Read, Edit, Write, Glob
Codex CLI Supported Same tool names as Claude Code
Gemini CLI Supported Set LESSONS_AGENT_PLATFORM=gemini
opencode Supported Same tool names as Claude Code
Cursor Export only node scripts/lessons.mjs list --json > .cursorrules
MCP Roadmap Universal adapter planned

Features

Feature Status
PreToolUse lesson injection
Session-start protocol injection
Guard lessons (block tool calls)
4-tier background scanning (T1/T2/T3/T4 LLM)
Incremental scanning with byte offsets
Confidence and priority scoring
3-layer atomic dedup
Budget-aware injection (3 lessons / 4 KB)
PostToolUse context re-injection at 30/52/70%
Subagent lesson protocol
Cross-platform (CC / Codex / Gemini / opencode)
MCP server adapter 🗺 Roadmap
LLM-assisted candidate classification 🗺 Roadmap
Project stack auto-detection 🗺 Roadmap

Measuring whether it actually works

Injecting a warning is easy. Knowing whether it changed the agent's behavior is the hard part — so lessons-learned has an eval harness for that, not just for the plugin's plumbing.

87 hand-crafted scenarios in evals/, each graded on 3 tiers:

Tier Checks How
1 Filesystem/command outcome A deterministic hidden-checks/verify.mjs
2 Tool-call sequence Declarative trajectory rules in scenario.json
3 Did the lesson change behavior? An LLM judge compares the agent with vs. without the lesson injected

Every scenario runs a control arm (no lesson) against a treatment arm (lesson injected) so a pass means the lesson caused the fix, not that the model would have gotten it right anyway.

That measurement infrastructure has caught real bugs in itself. The eval provider once silently ran the agent arm on a different, stronger model than the run was labeled and cached under — so a 2026-06 full-suite result reading "~65% of lessons are obsolete" was confounded, and every archive decision from that run had to be treated as provisional until re-validated on a pinned model. That re-validation is now complete. From evals/FINDINGS.md:

30/35 originally-archived lessons reproduced CONTROL_CORRECT on claude-sonnet-4-6 (genuinely obsolete, not an Opus artifact) ... One lesson (H12, bare except) was restored and rewritten — except Exception is still a real hazard on Sonnet, not obsolete.

The fix (pin the agent model, clear the cache, re-validate) is now a documented, repeatable process — see Pruning Obsolete Lessons. Lessons the model has genuinely outgrown are archived, not deleted, into an append-only obsoleted-lessons.json ledger so a future model regression can restore them.


Configuration

Edit data/config.json directly. Every field has a LESSONS_* env var equivalent that takes precedence.

Field Default Description
injectionBudgetBytes 4096 Max bytes per injection payload
maxLessonsPerInjection 3 Max lessons per tool call
minConfidence 0.5 Exclude lessons below this confidence
minPriority 1 Exclude lessons below this priority
compactionReinjectionThreshold 7 Re-inject after N tool calls
scanPaths ~/.claude/projects/ Where to find session JSONL files

Tier 4 LLM deep scan fires automatically at session start when an API key is available:

echo "sk-ant-..." > data/.api-key   # gitignored; scoped to deep scan only

Cost: ~$0.10–0.25/day at Haiku rates. Throttled to once per 24 hours.


Development

npm test                  # 297 tests at time of writing
npm run test:unit         # unit tests only (fast)
npm run test:integration  # integration tests
npm run lint              # eslint
npm run typecheck         # tsc --noEmit

For evals (auth via your claude login session, no env vars required):

cd evals
npx promptfoo eval --config promptfooconfig.yaml --filter-pattern "TC-H1"

See docs for the full reference and CONTRIBUTING.md for the dev workflow.


License

MIT © Joe Black

About

A Claude Code plugin that automatically captures coding mistakes and injects relevant lessons before tool calls — preventing the same mistakes from happening twice.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages