# Tuning Claude Code Itself

How to run a session whose job is configuring Claude Code, so the improvements apply to every future session instead of evaporating when you close the terminal.

**Provenance.** My working notes, published as-is. Every documented feature named below was checked against the official docs before publishing; a few things I originally had in here could not be verified and were cut rather than softened. Where that happened I say so.

**Last verified: 28 July 2026.**

---

## The rule that decides everything

**Tune from evidence, not from introspection.**

If you open a session and ask "what rules should you have?", you get plausible generic advice. Write clean code. Test your changes. Consider edge cases. It sounds right and it does nothing, because the model has no visibility into where it actually failed you last week.

If you hand it five real moments where you corrected it and ask what rule would have prevented each, you get rules that bite.

So the whole system reduces to two habits. Capture friction when it happens. Convert it in batches later. Everything below is machinery for those two things.

---

## Know which tier you are writing into

The most common self-configuration mistake is putting something in the wrong scope, then being confused when it does not apply, or applies everywhere and should not.

| Tier | Location | Applies to | Use for |
|---|---|---|---|
| Machine wide | `~/.claude/CLAUDE.md` | Every project on this machine | Your voice, your defaults, your anti-patterns |
| Machine wide, scoped | `~/.claude/rules/*.md` with `paths:` | Files matching a glob, any project | "In TypeScript files, never use `any`" |
| Machine wide, on demand | `~/.claude/skills/*/SKILL.md` | Invoked, or matched by description | Repeatable workflows like `/research` |
| Machine wide, enforced | `~/.claude/settings.json` | Every session | Permissions, hooks, denies |
| Project | `<repo>/CLAUDE.md`, `.claude/` | That repo, shared via git | Stack, commands, gotchas, team conventions |
| Project, private | `CLAUDE.local.md` (gitignored) | That repo, just you | Your sandbox URLs, test data |
| Automatic | `~/.claude/projects/<project>/memory/` | Per repo, written by the agent | Things it noticed. You audit, you do not write |

Two things worth knowing about that last row. Auto memory is on by default. It is machine-local, so it does not sync to your teammates, and only the first 200 lines or 25KB of its `MEMORY.md` index, whichever comes first, load per session. Topic files load on demand. Run `/memory` occasionally and actually read what it saved. It is plain markdown and you can delete anything wrong.

One detail that trips people up: the `<project>` path is derived from the git repository, so all worktrees and subdirectories of the same repo share one auto memory directory.

**Everything above the last row should be in git.** Make `~/.claude/` a dotfiles repo today. It gives you rollback when a rule turns out to be bad, and portability when you switch machines. Exclude `projects/` since that is the machine-local memory and session state.

---

## Step 1. Capture friction, cheaply

The reason people's config stays bad is that the moment you notice a problem, you are mid task and do not want to stop and write a rule. So you do not, and by the tuning session you have forgotten.

Fix it with the smallest possible mechanism.

**`~/.claude/skills/oops/SKILL.md`**

```markdown
---
name: oops
description: Log what just went wrong so it can be fixed in config later
disable-model-invocation: true
---

Append one entry to `~/.claude/friction.md`:

## <date> <repo name>
- **What happened:** <one line, what you did that I did not want>
- **What I wanted:** <one line>
- **Likely tier:** <user CLAUDE.md | project CLAUDE.md | rule | skill | hook | none>

If $ARGUMENTS is present, use it as the description. Otherwise infer from
the last few turns.

Do not propose a fix. Do not edit any config file. Just log it and continue
with what we were doing.
```

Now when it adds three files you did not ask for, you type `/oops` and keep working. Two seconds.

If you want it hands off later, a `Stop` hook can scan the finished session for correction patterns and append to the same file while the gap is fresh. Worth doing once the manual version proves it earns its keep, not before.

---

## Step 2. Run the tuning session

Monthly, or after any week that felt like a grind. Thirty minutes. Open it in a repo you actually work in, not an empty folder, so `/context` and `/doctor` have something real to look at.

**`~/.claude/skills/tune/SKILL.md`**

```markdown
---
name: tune
description: Audit and improve my Claude Code configuration from logged friction
disable-model-invocation: true
---

You are auditing my Claude Code setup. Work through this in order.
Propose everything, change nothing until I approve.

## 1. Read the evidence
Read `~/.claude/friction.md`. Group entries by underlying cause, not by
wording. Count occurrences per group.

## 2. Measure what is loaded
Run `/context` and report: which memory files loaded, and roughly what
share of the window the configuration is consuming before we do any work.
Flag anything over 10%.

## 3. Audit for rot
Read `~/.claude/CLAUDE.md`, `~/.claude/rules/`, and this repo's CLAUDE.md.
For each instruction, sort into:
- **Load bearing.** Removing it would cause a real mistake.
- **Derivable.** I could work this out by reading the code.
- **Stale.** It works around a model limitation that may no longer exist.
- **Contradicted.** It conflicts with another instruction somewhere.

List the derivable, stale, and contradicted ones as deletion candidates.
Be aggressive. A long instruction file makes you follow instructions worse,
not better.

## 4. Audit the skills
List every skill available at user and project level. For each, say whether
it has plausibly fired in the last month based on the friction log and what
I actually do. Flag overlap where two descriptions would compete.

## 5. Propose
For each friction group with 2 or more occurrences, propose exactly one change
and name the tier. Prefer, in this order:
1. A hook or lint, if the rule must hold every time and needs no judgment
2. A path-scoped rule, if it only applies to certain files
3. A skill, if it is a procedure I invoke
4. A CLAUDE.md line, only if it must be true in every session

Groups with 1 occurrence: log them, do not act. Once is noise.

## 6. Present
Give me a table: change, tier, file, what it replaces or deletes, one line
of rationale. Then stop and wait.

After I approve, apply the changes, then move handled entries in
friction.md under a `## Resolved` heading with the date.
```

Then run the built-in checks alongside it:

- **`/doctor`** proposes trims for a checked-in CLAUDE.md. Per the docs, it "cuts content Claude can derive from the codebase, such as directory layouts, dependency lists, and architecture overviews, and keeps pitfalls, rationale, and conventions that differ from tool defaults." Good second opinion on step 3.
- **`/memory`** to browse and prune what auto memory has accumulated.
- **`/context`** after the changes, to confirm the files you edited actually load.

### The question that saves you most

For any rule older than about three months, ask: **is this still compensating for something the model cannot do?**

Instruction files quietly become archaeology. Rules written for a weaker model keep costing context and diluting the rules that still matter. Anthropic's own harness team deleted whole components of their system when a better model landed and performance held. Do the same to your config. Delete the rule, work for a week, and see if the problem comes back. If it does not, it was never load bearing.

Anthropic's docs make the same point from the other direction: if the agent keeps doing something you do not want despite having a rule against it, the file is probably too long and the rule is getting lost.

### One thing I cut from this section

I originally had a step here about measuring which skills actually fire, using OpenTelemetry log export to record skill invocations and what triggered them. `OTEL_LOG_TOOL_DETAILS=1` is real and documented, and it does enable logging of skill names among other tool details. But the specific event and attribute names I had written down are not in the monitoring docs, so I have removed the recipe rather than publish something you would try and find missing. If you want this, start from the monitoring documentation and read the event list yourself.

At a small number of skills, gut feel is fine anyway. The useful principle survives regardless: a skill the model never picks on its own has a description problem, not a usefulness problem. Descriptions get shortened when there are many skills, so lead with words a real request would contain.

---

## On plugins generally

Plugins bundle skills, hooks, subagents, and MCP servers into a single installable unit. Some of them bundle a whole methodology: brainstorm, spec, isolated worktrees, plans broken into small tasks, strict TDD, staged review gates.

**Roughly half of that kind of bundle matches what the evidence supports, and half is exactly the ceremony worth cutting.** The brainstorm and spec discipline is the part that consistently earns its keep. The micro task decomposition and worktree ritual is the part that existed to compensate for older models and will feel like drag on small work.

So do not install one wholesale and do not dismiss it either. The right move is to cherry pick:

1. Install it in a throwaway project. Read the skills it ships. They are just markdown.
2. Steal the two or three prompts that are genuinely better than yours.
3. Either uninstall and keep your own copies, or keep it installed and disable the parts you do not want.

This generalises. **Treat every plugin as a source of ideas first and a dependency second.** A plugin is a bundle of assumptions about what the model cannot do alone, written at some point in the past, and you inherit all of them at once including the stale ones.

---

## Safety rails for self-configuration

A bad config change is the most expensive kind of mistake here, because it degrades every future session slightly and you will not attribute the degradation to it. You will just think the tool got worse.

Four rules:

1. **Version control `~/.claude/`.** Commit before every tuning session. This is the whole rollback story.
2. **Change one thing at a time when you are unsure.** If you rewrite your user CLAUDE.md and three skills in one sitting and things get worse, you have no idea which one did it.
3. **Never let the agent edit config as a side effect of another task.** Config changes happen in a session dedicated to config. Otherwise you get silent drift you never reviewed.
4. **Watch for the ratchet.** Every tuning session adds rules and none removes them, unless you make removal an explicit step. That is why step 3 above comes before step 5. Audit for deletion before you propose additions.

---

## The maintenance loop, compressed

- Friction happens, type `/oops`, keep working.
- Monthly, run `/tune`, plus `/doctor` and `/memory`.
- Delete before you add. Anything derivable from the code goes.
- Anything that must hold every time becomes a hook or a lint, not a sentence.
- When a new model ships, re-read your rules and ask which ones it no longer needs.
- Keep `~/.claude/` in git so a bad month is one `git revert` away.

Two signals tell you the config is working. You stop repeating yourself in chat, and your instruction files get shorter over time rather than longer.

---

## Sources

- [How Claude remembers your project](https://code.claude.com/docs/en/memory)
- [Best practices for Claude Code](https://code.claude.com/docs/en/best-practices)
- [Monitoring and usage](https://code.claude.com/docs/en/monitoring-usage)
- [Harness design for long-running application development](https://www.anthropic.com/engineering/harness-design-long-running-apps), Anthropic
