Claude Code /simplify cleans up your diff with four parallel agents — and /code-review checks it after
The Claude Code /simplify skill runs four parallel cleanup reviews on a diff and applies the fixes, then /code-review checks the result for bugs.

On this page
Introduction
I had been running /simplify, a skill bundled with Claude Code, for weeks without knowing what it did. I only knew it had a twin, /code-review, and that many people recommend using the two together. The two looked alike to me, and I could not have said how they split the work.
/simplify is a cleanup-only review. Four agents read the diff in parallel, each from one angle: reuse, simplification, efficiency, and altitude, meaning whether a change sits at the right layer. Their fixes go straight into the working tree, with no list of proposed changes for you to pick from first.
/simplify never looks for correctness bugs, so /code-review runs after it, on the code /simplify leaves behind. I ran both on a real commit from this blog to see what each one catches.
What /simplify runs
/simplify is a bundled skill, a prompt built into Claude Code that tells the model how to carry out the review and the fixes with its own tools. The commands reference describes it in one entry:
Review the changed code for cleanup opportunities and apply the fixes. Four review agents run in parallel, covering reuse of existing helpers, simplification, efficiency, and whether the change is at the right level of abstraction. The review doesn’t look for correctness bugs. Use
/code-reviewto find bugs.
The prompt /simplify loads runs in three phases:
- Gather the diff.
git diffagainst the upstream branch, plus uncommitted changes, or the path or pull request passed as an argument. - Review. Four agents start at the same time, each handed the diff from step 1 and the angle it reviews from.
- Apply. Findings that point at the same line are merged into one, then each is fixed in the working tree.
Each agent gets one brief from the prompt:
| Agent | What the prompt tells it to look for | Example from the run below |
|---|---|---|
| Reuse | New code that re-implements a helper the codebase already has, found by searching shared and nearby modules | new URL(SITE) is also built in scripts/indexnow.ts, but nothing exports a parsed copy the new code could import |
| Simplification | Redundant or derivable state, copy-paste with small variations, deep nesting, dead code left behind | resolveMark built an object that its only caller immediately took apart |
| Efficiency | Repeated computation or I/O, independent steps run one after another, work added to a hot path | luminance(DARK_BACKGROUND) is recomputed for every icon on every page, when it could be computed once at module load |
| Altitude | A symptom patched in place when the root cause sits one layer deeper, or a special case layered on shared code | The blog’s old hostname was hardcoded in the marks table instead of living in site.ts |
The apply phase, run by the main agent rather than the four reviewers, has one escape hatch, quoted from the prompt:
Skip any finding whose fix would change intended behavior, require changes well outside the reviewed diff, or that you judge to be a false positive — note the skip rather than arguing with it.
Finding bugs is the job of the other bundled skill, /code-review:
/simplify | /code-review | |
|---|---|---|
| Looks for | Reuse, simplification, efficiency, altitude | Correctness bugs, plus cleanups depending on model and effort level |
| Edits files | Always applies its fixes | Reports only, unless --fix is passed |
| Runs as | Four review agents in parallel | A background subagent with its own context window |
| Takes | A path or pull request reference | An effort level from low to max or ultra, --fix, --comment, --max-findings, and a pull request, branch, or path |
That March write-up is by Bozhidar Batsov, the author of RuboCop, a static code analyzer and formatter for Ruby, who calls /simplify “the skill I use most often” and runs it “right after a larger refactoring or after accepting a batch of AI-generated code.”
/simplify on a real diff
The diff I picked had already shipped. It taught rehype-link-icons.ts, this blog’s rehype plugin (a step that edits the HTML at build time) that draws a brand mark beside a link, four new marks: Qiita, Zenn, DevelopersIO, and this blog’s own seal for links back here.
I replayed the past commit as uncommitted changes in a separate worktree, so /simplify could edit freely without touching the real checkout or work in progress:
git worktree add --detach ../simplify-trial <commit>^git -C ../simplify-trial cherry-pick -n <commit>Then, from inside that worktree, on Claude Code 2.1.310:
/simplify src/lib/rehype-link-icons.tsThe four agents returned nine findings, and /simplify applied three of them:
| Agent | Findings | Applied |
|---|---|---|
| Reuse | 0 | 0 |
| Simplification | 3 | 2 |
| Efficiency | 0 | 0 |
| Altitude | 6 | 1 |
Reuse and efficiency show 0 because both agents reported only observations, like the examples in the earlier table, and nothing the diff needed to change.
The three fixes it applied
The largest one is the simplification example from the table: it removed MarkSymbol, a type whose only job was to carry the id field from resolveMark to its single caller. That caller, the code that builds the sprite (one hidden <svg> holding every mark), took the result apart the moment it arrived:
function resolveMark(key: MarkKey): MarkSymbol { if (isLocal(key)) return { id: symbolId(key), ...LOCAL_MARKS[key]() }; return { id: symbolId(key), viewBox: "0 0 24 24", children: [markPath(key)] };}// …children: [...used].map((key) => { const { id, viewBox, children } = resolveMark(key); return element("symbol", { id, viewBox }, children);}),/simplify replaced resolveMark with symbol(), which returns the <symbol> node itself, and the MarkSymbol type went away:
function symbol(key: MarkKey): HastNode { const { viewBox, children } = isLocal(key) ? LOCAL_MARKS[key]() : { viewBox: "0 0 24 24", children: [markPath(key)] }; return element("symbol", { id: symbolId(key), viewBox }, children);}// …children: [...used].map(symbol),The other two were smaller:
- How the favicon is read. The plugin reads the seal’s shape from the favicon. The
<svg>tag was read on a line of its own while<circle>,<g>and<path>shared one.map; now all four go through the same.map, with the same result. - The old hostname. The blog’s old address,
oharu-tech-blog.vercel.app, was typed straight into the marks table, though the site’s addresses belong insite.ts. This is the altitude example from the table. It now lives insite.tsasLEGACY_HOSTS, so a change of address means editing that one file.
The six it skipped
The six findings /simplify skipped, and why:
| Suggestion | Why it was skipped |
|---|---|
| Run the contrast check over the self-drawn marks (DevelopersIO and the seal) too | Would change behavior: both marks would be recoloured in dark mode |
Classify links after parsing them, so a ./other/ link also gets the seal | Would change behavior: links with no icon today would gain the seal |
Drop the 24×24 viewBox from each icon’s outer <svg> | Would change behavior: the icons’ displayed size could change |
Have the brand generator emit the seal geometry as a module instead of regex-parsing public/favicon.svg | Outside the diff: the change belongs in the separate script that generates the favicon |
Use the new element() helper in the older node builders | Outside the diff: it touches code this commit never changed |
One uniform mark object in place of the isLocal branch | Partly covered: the symbol() change already removed one place the branch appears |
/simplify does not run the code it edits. So Claude Code checked separately that the three fixes changed nothing on the page. It fed six kinds of link (GitHub, root-relative, the old host, DevelopersIO, Zenn and a footnote) through the plugin before and after, and the outputs were identical.
Running /code-review on what /simplify left
/code-review on rehype-link-icons.ts and site.ts, the two files /simplify had edited, returned ten findings.
Nine of them were in the commit as it shipped. Three of them reproduce directly:
| Input | What the plugin does | Why |
|---|---|---|
href="/\github.com/x" | Draws the GitHub mark | The root-relative test excludes // but not /\, and URL parsing reads the backslash as a slash |
href="http://constructor/" | Throws TypeError: key.slice is not a function, failing the build | The marks table is a plain object, so the hostname finds Object.prototype.constructor |
DevelopersIO’s #cbd31e segment | Renders at 1.63:1 against the light theme’s white, under WCAG’s 3:1 floor | Self-drawn marks skip the contrast check |
The altitude agent had read the root-relative regex in markFor too, but only said the check sat at the wrong layer. Whether the regex lets a malformed href through is a correctness question, outside its angle, so the backslash case waited for /code-review.
When do /simplify and /code-review run?
Run /simplify first and /code-review last. /simplify writes to the working tree, and a review only sees the code that exists when it runs, so in the other order /simplify’s edits get committed without any review.
Batsov’s March workflow ran the other way: “make changes, run /review to catch issues, fix anything it flags, then run /simplify to clean things up.”
Summary
/simplify sends a diff to four parallel agents for reuse, simplification, efficiency, and altitude, applies their fixes, and skips any fix that would change behavior or reach outside the diff. It never looks for bugs and never runs the code it edits.
Run /code-review after it, on the code /simplify leaves behind. To try both on a commit that has already shipped, replay it into a separate worktree with git cherry-pick -n and run them there.

