# 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.

- Source: https://oharu121.com/blog/claude-code-simplify-parallel-cleanup-agents-code-review/
- Published: 2026-10-27T00:43:04+09:00
- Tags: Claude Code, Claude

---
## 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](https://code.claude.com/docs/en/commands) 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-review` to find bugs.

The prompt `/simplify` loads runs in three phases:

1. **Gather the diff.** `git diff` against the upstream branch, plus uncommitted changes, or the path or pull request passed as an argument.
2. **Review.** Four agents start at the same time, each handed the diff from step 1 and the angle it reviews from.
3. **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 |

> **CAREFUL**
>
> **Older posts describe a different /simplify**
>
> `/simplify` has [changed behavior several times](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md):
>
> 1. 2.1.63: `/simplify` added.
> 2. 2.1.147: renamed to `/code-review`, with the cleanup behavior removed.
> 3. 2.1.152: `/simplify` returns, calling `/code-review --fix`.
> 4. 2.1.154: a cleanup-only review again.
>
> **So older posts may describe it differently.** [A write-up from March 2026](https://batsov.com/articles/2026/03/11/essential-claude-code-skills-and-commands/) counts three agents, not four.

[That March write-up](https://batsov.com/articles/2026/03/11/essential-claude-code-skills-and-commands/) 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](/blog/astro-rehype-plugin-link-brand-icons-svg-sprite-csp/) 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:

```bash
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:

```text
/simplify src/lib/rehype-link-icons.ts
```

The 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:

```ts title="src/lib/rehype-link-icons.ts (before)"
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:

```ts title="src/lib/rehype-link-icons.ts (after)"
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 in `site.ts`. This is the altitude example from the table. It now lives in `site.ts` as `LEGACY_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.

*Figure — Workflow: /simplify edits the diff, so /code-review reads its output rather than the other way round.*

Batsov's [March workflow](https://batsov.com/articles/2026/03/11/essential-claude-code-skills-and-commands/) 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.

## References

- [Claude Code commands reference, with the `/simplify` and `/code-review` entries](https://code.claude.com/docs/en/commands)
- [Review locally with /code-review, including how it relates to /simplify](https://code.claude.com/docs/en/code-review-local)
- [Claude Code changelog, versions 2.1.63 through 2.1.154 for the /simplify history](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md)
- [Bozhidar Batsov: Essential Claude Code skills and commands](https://batsov.com/articles/2026/03/11/essential-claude-code-skills-and-commands/)
