Make your harness Learn From Its Mistakes

Claude Code ships with a set of native building blocks for shaping how the assistant works. Instruction files (CLAUDE.md, AGENTS.md), shareable Skills, deterministic Hooks, and a self-managing Memory. Each one moves knowledge out of the chat window and into something persistent: conventions the model always honors, workflows anyone can invoke, guardrails the harness enforces, and facts that survive across sessions. The first four sections below cover those natives briefly, mostly to set the stage.

The real subject of this article is what sits at the end of that progression: Lessons: a small custom layer I built on top of Memory to turn Claude into something that actively learns from its own mistakes. Native Memory remembers what your project is; Lessons remembers what went wrong and how not to repeat it. Read the natives as context, then linger on Memory and Lessons, where the interesting part lives.

Claude instructions

CLAUDE.md is the native configuration file Claude Code reads first. From the project root, and globally from ~/.claude/CLAUDE.md. It carries persistent context that Claude honors on every request: coding conventions, architecture notes, build/test commands, and hard rules (“always run the linter”, “never commit secrets”). Project and global files stack, so team-wide conventions live in the repo while personal preferences stay in the home directory. Because it loads automatically at session start, you avoid re-explaining the same setup each conversation. Keep it concise and directive, it is instruction, not documentation, and everything in it competes for the model’s attention.

Agents instructions

AGENTS.md is a universal, cross-tool standard for giving AI coding agents project context, supported by Claude Code and other multi-agent platforms. Where CLAUDE.md is Claude-specific, AGENTS.md is vendor-neutral, so a single file works across whatever tools the team uses. In this repo it is the canonical guide, architecture, layout, tests, ops commands, conventions and CLAUDE.md defers to it, covering only Claude-specific tooling. Claude Code reads it as a fallback and merges it with any CLAUDE.md present. This split keeps shared project knowledge in one portable place while tool-specific quirks stay separate.

Skills

Skills package repeatable workflows your team can share and invoke by name, like /review-pr or /deploy-staging. Each skill is a folder with a SKILL.md describing when to use it and the steps to follow, plus any supporting scripts or reference files it needs. Claude loads a skill’s full instructions only when the task matches, so many skills can be available without bloating context. They make expert procedures reusable. One well-written skill lets everyone run the same multi-step process consistently.

Hooks

Hooks let you run shell commands automatically before or after Claude Code actions, auto-formatting after every file edit, running lint before a commit, or blocking edits to protected paths. They are configured in settings.json, not driven by the model, so the behavior is deterministic and always fires regardless of what Claude decides. Common trigger points include pre/post tool use and session lifecycle events, and a hook can inspect the action and even veto it. This is how you enforce guardrails the model can’t skip, versus CLAUDE.md rules which are guidance the model chooses to follow. Use hooks for anything that must happen “every time X”; the guarantee comes from the harness, not from asking nicely.

Read more about the above ones here: https://code.claude.com/docs/en/overview

The concepts are very similar with Copilot, only the main instruction file is copilot-instructions.md instead of CLAUDE.md https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions

Claude Memory – native

Claude has a memory function, which saves learnings like build commands and debugging insights across sessions without you writing anything. It works as a file-based store, a MEMORY.md index plus per-topic fact files, that Claude reads into context automatically at the start of each session, so knowledge accumulates instead of resetting every conversation. Claude decides on its own what is worth keeping: durable, reusable facts about you, the project, and how you like to work, while it discards one-off details that only mattered in the moment. The point is continuity: the more you work together, the less you have to re-explain, because setup steps, gotchas, and preferences persist automatically. Memory is scoped and editable: entries live as plain files you can read, correct, or delete, and a wrong or stale memory is verified against the current code before it’s acted on. In short, it turns Claude from a stateless assistant into one that remembers the shape of your project across time.
It’s project level tool, stored in global .claude directory, and if you want you have the option to redirect it into your project directory the following way (in my case it’s docs/memories):

{project-dir}/.claude/settings.local.json:

"autoMemoryDirectory": "{project-dir}/docs/memories"

more about Claude Memory: https://code.claude.com/docs/en/memory

CoPilot variation of memory documentation: https://docs.github.com/en/copilot/how-tos/use-copilot-agents/copilot-memory

Claude Lessons – custom

Lessons is my own narrower version of Memory, aimed squarely at one goal: self-improvement. Where native Memory captures any durable fact (build commands, project shape, preferences), Lessons captures only learning-worthy moments, the times Claude got something wrong, nearly got it wrong, or discovered a non-obvious truth about how this project behaves.

It’s driven by a rule in my global CLAUDE.md that tells Claude to extend, never overwrite, docs/lessons/lessons.md whenever such a moment occurs, not only when I explicitly correct it. Three triggers qualify: a user correction (record the pattern plus a rule to stop it recurring), a self-caught mistake (same treatment, even if fixed before I noticed), and a notable observation (a gotcha, a dead end, or a confirmed-good approach worth remembering) this is the closest cross-cutting surface with Memories.

The format mirrors Memory: lessons.md is a one-line index — date[link to prose file]description — while each lesson’s detail lives in its own separate file, keeping the index scannable and the prose self-contained. And it closes the loop: at the start of every session on a known project, Claude reviews docs/lessons/lessons.md if it exists, so past mistakes actively shape future behavior instead of quietly repeating.

The core rule, verbatim from my global CLAUDE.md:

Self-improvement

Update docs/lessons/lessons.md whenever something learning-worthy happens, not only when corrected:

  • User correction — pattern + rule to prevent recurrence.
  • Self-caught mistake — same, even if fixed before the user noticed.
  • Notable observation, which would have changed an action — a non-obvious gotcha, dead end, or confirmed-good approach worth remembering.

Structure similarly as Memories (MEMORY.md) formatted, date — [link](file.md) — one clause, ≤200 chars in lessons.md only. Individual lession files separatly stored.
Before being write-only, do a quick sanity check first, a new file requires that no existing lesson states the same rule.
One rule per lesson, per session.
At session start for a known project: review docs/lessons/lessons.md if it exists.

Leave a Reply

Your email address will not be published. Required fields are marked *