TL;DR: I’ve been using Claude Code since last July and spent most of that time correcting the same behaviours every session. Auto-memory hasn’t fixed that, but it has taken some of the edge off: when I say “next time, do X” in conversation, Claude saves it as a feedback memory and pre-empts me more often than not on the next run. Below is a snapshot of the rules I’ve been carrying around.

Motivation Link to heading

Saying you use Claude Code in 2026 is about as distinguishing as saying you use VS Code. I picked it up in July 2025 and spent most of the time since then having the same small arguments with it. I’d ask it to make a PR. It would push three messy commits. I’d say “squash to one before opening”. Two days later, three messy commits again.

Auto-memory has helped. It shipped in Claude Code v2.1.59 in late February 2026: persistent notes saved as small markdown files in ~/.claude/memory/, with a feedback type that captures behavioural rules. Each one has a rule, a Why, and a How to apply. You tell Claude “from now on, when X happens, do Y” in conversation, and it writes the file itself. The next session, the file is in context. Some of the time it sticks, some of the time I’m reminding it again, and the failure modes are still part of the deal. The rules below are what I’m running with right now, not a finished system.

Below are ten I’ve ended up with. They’re shaped to my workflow and won’t all transfer, but the pattern of writing them might.

Squash before the PR Link to heading

I’d review a PR I’d asked Claude to open and find three commits: “wip”, “fix tests”, “address review”. I said “squash these and force-push” so often it became a tic.

The memory:

Always squash to a single commit before creating a PR. If the work serves different purposes, split into separate PRs rather than bundling.

Most sessions now, Claude squashes before gh pr create without me asking. I still see the occasional three-commit PR when something has thrown the model off, but it’s the exception.

Keep the PR description honest after each amend Link to heading

The follow-on problem: once a PR is one commit, every fix becomes an amend plus a force-push. The diff changes, and the title and description drift until the PR page lies about what’s in the branch.

After any amend that changes scope, refresh the commit message, the PR title, and the PR description in the same turn as the force-push. Use --force-with-lease, never plain --force.

The first version of this memory said “update the PR description” and nothing more. I had to add “and the title” after Claude left a stale title on a PR whose scope had tripled. I’ve since come to think the Why line is the part that prevents this kind of half-fix, since it gives Claude enough context to extend the rule to the title without me spelling it out. That might be wishful pattern-matching on my part, but the rules with a clear Why do seem to generalise better.

Wait for the full CI surface before fixing Link to heading

One PR had eight pipelines. The first one failed on a missing secret. Claude pushed a fix two seconds later. While that fix was running, three more pipelines completed with unrelated failures. By the time I caught up, four CI cycles had run for what should have been one commit.

When a PR has checks in progress, do not push fixes after every individual failure. Wait for the full cycle to finish, then triage the whole failure surface at once. Exceptions: hard blockers like a broken workflow file, since those gate every subsequent push.

This one needs the exception clause. Without it, Claude waits while a syntax error in ci.yml blocks every other check.

Treat unreplied review comments as unfixed Link to heading

I asked Claude to “address the bot comments”. It posted polite replies on every thread saying the issue was fixed. The issues were not fixed. Claude had read the comments, decided they sounded reasonable, and replied without checking the code.

If a PR review comment has no reply, assume the issue has not been dealt with. Read the comment, check the current code, fix if needed, then reply.

I phrased the rule as a sequence: read, check the code, fix, then reply. The earlier wording I tried, something like “be careful with bot threads”, did nothing for me, but a sequence I can mentally tick off seems to land.

Verify before declaring done Link to heading

Type-checking and unit tests prove the code compiles and passes its own tests. They prove nothing about whether the feature works.

Before reporting a task complete, run the test, execute the script, hit the endpoint, view the page in a browser. If verification isn’t possible, say so rather than claiming success.

UI changes are the worst offenders. Claude can refactor a React component, type-check it clean, and report success without rendering the page. With this memory in place I see Claude open the browser more often before saying done, though not always.

Report failures plainly, report passes plainly Link to heading

Claude once told me “tests are mostly passing, there may be some flakiness around the auth suite”. The truth was three failures in auth.test.ts. A vague status update like that costs more than either a clean pass or a clean fail, because I have to re-run the suite to find out what actually happened. The other half of the rule matters too: when something passes, say it passed. Don’t hedge a green result into “looks fine” or downgrade finished work to “partial” out of caution.

Report outcomes accurately. State failures with the relevant output. State passes plainly. Don’t claim success when output shows failures, and don’t hedge confirmed results with disclaimers.

Default to no comments Link to heading

This one was already in my system prompt, but Claude kept adding // loop through users above a for (const user of users). The memory makes it stick:

Default to writing no comments. Add one only when the WHY is non-obvious: a hidden constraint, a workaround for a specific bug, behaviour that would surprise a reader. If removing the comment wouldn’t confuse a future reader, don’t write it.

The cousin rule: don’t reference the current task in comments. // added for the OAuth migration rots the moment the migration ships.

Challenge the premise Link to heading

Sometimes I ask for a thing that doesn’t make sense. The code does the opposite of what I think it does, or the bug I’m chasing is in a different file. A compliant assistant implements the wrong thing and we both lose an hour.

If the user’s request is based on a misconception, or there’s a bug adjacent to what they asked about, say so. Read the request, then the relevant code. If the request doesn’t match what the code actually does, raise it before implementing.

I get fewer “why didn’t this work” sessions now because Claude flags the bad premise up front instead of grinding through the wrong implementation.

Use a language server, not grep, for code questions Link to heading

Grep finds text. It doesn’t know the difference between import { foo } from "bar" and a comment that says foo. For “where is X defined” or “what calls this function”, a real language server gives a precise answer.

For symbol-aware navigation, use Serena MCP over grep plus Read. Serena drives a real language server (pyright, gopls, ts-server) and returns scope-aware results. Stick with grep for plain-text searches: config strings, log lines, comments, TODOs.

After installing Serena I had to write this memory because Claude kept reaching for grep out of habit.

Make file references clickable Link to heading

A small one with high frequency. Plain paths in terminal output aren’t clickable in most setups. Markdown links with file:/// URLs and percent-encoded spaces are.

When referencing local files, use markdown link syntax: [name](file:///path/with%20spaces). Plain paths and bare URLs aren’t clickable in most terminals.

I click these dozens of times a day.

How memories get written Link to heading

I don’t write these by hand. When Claude does something I want it to keep doing, or stops doing something I want it to drop, I say so in conversation: “next time, squash before opening the PR”, “stop asking me before monitoring”, “from now on, prefer Serena for symbol search”. Claude saves the memory itself with this structure:

---
name: feedback_short_descriptive_name
description: one-line description used to decide relevance later
type: feedback
---

The rule, stated plainly.

**Why:** the reason the rule exists. Often a past incident or a strong preference.

**How to apply:** when and where this kicks in. Concrete triggers, banned phrasings, exceptions.

The Why line has mattered more than I expected. Without it, my rules turned brittle on edge cases. With it, Claude seemed to extend the rule into adjacent situations on its own. Anthropic published some research on teaching Claude why that I found reassuring after the fact: training on principles outperforms training on demonstrations, because the model can generalise the principle to situations the demonstrations never covered. I read that and felt less silly about writing little “because” clauses for myself.

The other thing I’ve found helps: capture confirmations as well as corrections. If Claude takes an unusual approach and you accept it without pushback, telling it to remember that seems to keep the memory file from drifting into a list of past mistakes that makes the assistant timid.

Further reading Link to heading