Learnings Loop for Claude Code — persistent cross-session memory via a
learnings.mdfile. Each session starts with accumulated knowledge auto-injected, and ends with new insights captured. Over time the file compounds into a field notebook that survives session boundaries.
Inspired by the MindStudio blog post How to Build a Learnings Loop for Self-Improving Claude Code Skills.
Claude Code sessions start fresh. Without persistence, every session re-explains the same context, re-discovers the same failure modes, and re-derives the same decisions. The Learnings Loop gives you a small curated file that is:
- Read at session start (auto-injected as additional context).
- Updated during and after sessions via slash commands.
- Consolidated periodically into distilled standing principles.
The result: each session leaves the next one better prepared, without replaying the prior conversation.
Inside Claude Code:
/plugin marketplace add huketo/levelup-skill
/plugin install levelup-skill@levelup-skill
Then restart Claude Code — the SessionStart hook only loads on
session start.
git clone https://github.com/huketo/levelup-skill.git
claude --plugin-dir /path/to/levelup-skill-
In a project directory, run:
/levelup-skill:init-learningsThis creates
learnings.mdfrom the template and wires a Learnings Loop section intoCLAUDE.md(asking first ifCLAUDE.mddoes not exist). -
Work as usual. When something non-obvious happens (a solved bug, a surprising API behavior, a correction from you), run:
/levelup-skill:update-learnings -
At the end of a session, run
/levelup-skill:update-learningsone more time as a final sweep. -
Weekly, or when the file crosses ~80–100 bullets, run:
/levelup-skill:consolidate-learningsThis prunes stale entries, merges duplicates, and promotes recurring patterns into the Consolidated Principles section — the step that makes the loop compound.
-
Whenever you want to inspect the state of the loop:
/levelup-skill:review-learnings
| Command | Purpose |
|---|---|
/levelup-skill:init-learnings |
Scaffold learnings.md from the template and optionally update CLAUDE.md. --global targets ~/.claude/learnings.md. --force overwrites an existing file after confirmation. |
/levelup-skill:update-learnings |
Review the current session and append dated, atomic entries. --note "…" appends one verbatim. --global targets the global file. |
/levelup-skill:consolidate-learnings |
Prune, merge, and distill into Consolidated Principles. --dry-run previews without writing. |
/levelup-skill:review-learnings |
Read-only summary and health check. --focus "topic" filters to relevant entries. |
An additional auto-triggered skill, learnings-loop, loads into context
when you ask about the methodology itself ("how does this work", "should
I save this as a learning", "global vs project learnings", etc.) — no
slash command required.
The plugin installs a SessionStart hook. On every session start (fresh,
cleared, or compacted), the hook:
- Looks for
learnings.md(orLEARNINGS.md) at the current project root. - Looks for
~/.claude/learnings.mdfor global learnings. - Injects whichever files exist into the session as additional context, together with a short directive telling the assistant to apply the Consolidated Principles as standing rules.
- Emits JSON in the format the host expects (Claude Code's
hookSpecificOutput.additionalContext, or the equivalent for Cursor and Copilot CLI).
If no learnings file exists yet, the hook instead injects a one-line
pointer to /levelup-skill:init-learnings so you know the plugin is
active.
Hook changes only take effect on session restart — exit Claude Code and start a new session after installing the plugin.
A learnings.md created by this plugin has five sections:
- Consolidated Principles — standing rules (no dates). Applied as hard rules for the session.
- Patterns That Work — dated bullets, validated approaches.
- Mistakes to Avoid — dated bullets, concrete failures to not repeat.
- Domain Knowledge — dated bullets, non-obvious facts about this project.
- Open Questions — dated bullets, unverified assumptions.
The consolidate-learnings command depends on these exact headings.
Do not rename them.
- Project (
./learnings.md) — commit it. This is team memory. Team members' Claude Code sessions all start with the same accumulated knowledge. - Global (
~/.claude/learnings.md) — cross-project preferences, personal conventions (preferred tools, output style, workflow habits).
When in doubt, record at the project level. Promoting a project entry to global later is easy; extracting project-specific noise out of a polluted global file is not.
The file is easy. The discipline is what makes it compound:
- Inclusion Bar — for every candidate entry, ask "Would a future session behave meaningfully differently if it knew this?" If no, leave it out. Restraint keeps the file useful.
- Atomic bullets — one insight per line. Paragraphs get skipped.
- Consolidate regularly — without pruning, the file becomes noise.
A bloated
learnings.mdis worse than none at all; it crowds the context window. - Verify before acting on stale-looking memory — a claim was true when written; reality may have moved. Check current state before acting on a specific file path, function name, or flag named in the file.
See the learnings-loop skill for the full methodology.
levelup-skill/
├── .claude-plugin/
│ ├── plugin.json
│ └── marketplace.json
├── commands/
│ ├── init-learnings.md
│ ├── update-learnings.md
│ ├── consolidate-learnings.md
│ └── review-learnings.md
├── hooks/
│ ├── hooks.json
│ └── inject-learnings.sh
├── skills/
│ └── learnings-loop/SKILL.md
├── templates/
│ └── learnings-template.md
├── LICENSE
├── README.md
└── README.ko.md
The four user-invoked slash commands live in commands/. The
auto-triggered methodology skill (learnings-loop) lives in skills/
so it loads into context whenever the user asks about the loop, not
only when they invoke a command.
Test the hook script without running the full plugin:
CLAUDE_PLUGIN_ROOT=/path/to/levelup-skill \
CLAUDE_PROJECT_DIR=/tmp/test-project \
bash /path/to/levelup-skill/hooks/inject-learnings.sh | jq .This prints the JSON the SessionStart hook would emit. Confirm the
hookSpecificOutput.additionalContext value contains your project's
learnings.md content (or the bootstrap hint if none exists yet).
Issues and PRs welcome. Before opening a PR:
- Run the local hook test above across at least the "no files" / "project only" / "both files" scenarios.
- Update the command markdown files in
commands/if you change semantics; descriptions are user-visible. - Do not rename the five section headings in
templates/learnings-template.md— the plugin depends on them.
MIT — see LICENSE.