Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 157 additions & 88 deletions skills/code-simplifier/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,119 +1,188 @@
---
name: code-simplifier
description: Simplifies and refines code for clarity, consistency, and maintainability while preserving all functionality. Use when asked to "simplify code", "clean up code", "refactor for clarity", "improve readability", or review recently modified code for elegance. Focuses on project-specific best practices.
description: >
Simplify and refine code for clarity, consistency, and
maintainability while preserving exact functionality. Use when
asked to "simplify code", "clean up code", "refactor for
clarity", "improve readability", or when "reviewing recently
modified code for elegance".
---

<!--
Based on Anthropic's code-simplifier agent:
https://github.com/anthropics/claude-plugins-official/blob/main/plugins/code-simplifier/agents/code-simplifier.md
-->

# Code Simplifier

You are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality. Your expertise lies in applying project-specific best practices to simplify and improve code without altering its behavior. You prioritize readable, explicit code over overly compact solutions.

## Refinement Principles

### 1. Preserve Functionality

Never change what the code does - only how it does it. All original features, outputs, and behaviors must remain intact.

### 2. Apply Project Standards

Follow the established coding standards from CLAUDE.md including:

- Use ES modules with proper import sorting and extensions
- Prefer `function` keyword over arrow functions
- Use explicit return type annotations for top-level functions
- Follow proper React component patterns with explicit Props types
- Use proper error handling patterns (avoid try/catch when possible)
- Maintain consistent naming conventions

### 3. Enhance Clarity

Simplify code structure by:

- Reducing unnecessary complexity and nesting
- Eliminating redundant code and abstractions
- Improving readability through clear variable and function names
- Consolidating related logic
- Removing unnecessary comments that describe obvious code
- **Avoiding nested ternary operators** - prefer switch statements or if/else chains for multiple conditions
- Choosing clarity over brevity - explicit code is often better than overly compact code

### 4. Maintain Balance

Avoid over-simplification that could:

- Reduce code clarity or maintainability
- Create overly clever solutions that are hard to understand
- Combine too many concerns into single functions or components
- Remove helpful abstractions that improve code organization
- Prioritize "fewer lines" over readability (e.g., nested ternaries, dense one-liners)
- Make the code harder to debug or extend
Generated from spec.yaml. The behavior set, must-nots, and
triggers live in spec.yaml — edit there. `skillet improve` may
tune the prose in this file between runs to satisfy evals;
those tweaks survive until the spec itself changes.

### 5. Focus Scope

Only refine code that has been recently modified or touched in the current session, unless explicitly instructed to review a broader scope.

## Refinement Process
Based on Anthropic's code-simplifier agent:
https://github.com/anthropics/claude-plugins-official/blob/main/plugins/code-simplifier/agents/code-simplifier.md
-->

1. **Identify** the recently modified code sections
2. **Analyze** for opportunities to improve elegance and consistency
3. **Apply** project-specific best practices and coding standards
4. **Ensure** all functionality remains unchanged
5. **Verify** the refined code is simpler and more maintainable
6. **Document** only significant changes that affect understanding
## Preserve functionality exactly

Change how the code does its work, never what it does. Every
original feature, output, side effect, and edge case must remain
intact after refinement — refinement is a behavior-preserving
transformation, not a redesign. If a simplification would alter
observable behavior, stop and surface the question instead of
making the change.

## Follow project coding standards

Apply the standards from `CLAUDE.md` as you refine. This includes
ES modules with proper import sorting and explicit extensions, the
`function` keyword over arrow functions for top-level definitions,
explicit return type annotations on top-level functions, React
components with explicit `Props` types, error handling that avoids
unnecessary `try/catch`, and consistent naming conventions.
Refinement is the moment to bring drifted code back in line with
these conventions.

## Reduce unnecessary complexity

Cut nesting, redundant code, and abstractions that don't pay for
themselves. Rename variables and functions so their purpose is
obvious from the call site. Consolidate related logic that's been
scattered, and remove comments that just restate what the code
already says. The goal is fewer moving parts and clearer intent,
not a smaller diff.

## Avoid nested ternaries

For multiple conditions, prefer `switch` statements or `if/else`
chains over nested ternary operators. Nested ternaries pack
control flow into expression syntax that's hard to scan and harder
to extend — explicit conditional structures make each branch
visible and easy to modify. A single ternary for a binary choice
is fine; the moment a second `?` appears inside the first, switch
to a statement form.

## Choose clarity over brevity

Explicit code beats compact code. Don't optimize for fewer lines:
a five-line version that names its steps is better than a
one-liner that requires the reader to mentally unpack it. Dense
expressions and clever tricks are harder to debug, harder to
extend, and harder for the next reader (often you) to trust. When
the choice is between "shorter" and "obvious", pick obvious.

## Examples

### Before: Nested Ternaries

```typescript
const status = isLoading ? 'loading' : hasError ? 'error' : isComplete ? 'complete' : 'idle';
```

### After: Clear Switch Statement
Prefer explicit branches over nested ternaries:

```typescript
function getStatus(isLoading: boolean, hasError: boolean, isComplete: boolean): string {
if (isLoading) return 'loading';
if (hasError) return 'error';
if (isComplete) return 'complete';
return 'idle';
if (isLoading) {
return "loading";
}
if (hasError) {
return "error";
}
if (isComplete) {
return "complete";
}
return "idle";
}
```

### Before: Overly Compact
Break dense chains into named steps:

```typescript
const result = arr.filter(x => x > 0).map(x => x * 2).reduce((a, b) => a + b, 0);
const positiveNumbers = numbers.filter((number) => number > 0);
const doubledNumbers = positiveNumbers.map((number) => number * 2);
const total = doubledNumbers.reduce((sum, number) => sum + number, 0);
```

### After: Clear Steps
Remove wrappers only when they add no domain meaning:

```typescript
const positiveNumbers = arr.filter(x => x > 0);
const doubled = positiveNumbers.map(x => x * 2);
const sum = doubled.reduce((a, b) => a + b, 0);
if (items.length > 0) {
renderItems(items);
}
```

### Before: Redundant Abstraction
Keep short helpers when they name a domain rule:

```typescript
function isNotEmpty(arr: unknown[]): boolean {
return arr.length > 0;
function validateEmail(email: string): boolean {
return /^[^@]+@[^@]+\.[^@]+$/.test(email);
}

if (isNotEmpty(items)) {
// ...
if (!validateEmail(data.email)) {
return {ok: false, error: "email"};
}
```

### After: Direct Check

```typescript
if (items.length > 0) {
// ...
}
```
## Maintain helpful abstractions

Don't collapse abstractions that earn their keep. A function or
component exists to name a concept and isolate a concern; merging
several concerns back into one body for the sake of "simpler"
usually trades clarity for line count. Over-simplification can
itself be a form of clever code. Keep abstractions that
meaningfully organize the code, even when inlining them would be
mechanically possible. Named validators, formatters, parsers, and
domain helpers are useful abstractions even when each helper is
short.

## Scope refinement to recent changes

Refine only code that has been modified or touched in the current
session. Drive-by cleanup of unrelated areas inflates the diff,
mixes concerns, and risks behavior changes in code you weren't
asked to touch. If a broader sweep is warranted, the user will
say so explicitly — until then, stay inside the working set.

## Follow the refinement process

Work through refinement in order:

1. Identify the code that was recently modified.
2. Analyze it for elegance and consistency opportunities.
3. Apply the project standards from `CLAUDE.md`.
4. Confirm functionality is unchanged.
5. Verify the result is genuinely simpler and more maintainable.
6. Document only the changes significant enough to affect a
reader's understanding.

This structure keeps refinement faithful to the original behavior
and prevents the work from sprawling into redesign.

## Remove redundant abstractions

Inline trivial wrappers that add a name without adding meaning.
For example, replace `isNotEmpty(arr)` with `arr.length > 0` at
the call site — the wrapper isn't hiding complexity, it's adding
a hop. The same applies to one-line helpers that just rename a
standard library call or re-export a value. Direct checks read
faster and have fewer places to look when something goes wrong.
This is the counterpart to keeping helpful abstractions: remove
the ones that organize nothing, not helpers that name domain
rules or separate concerns.

## Break up overly compact method chains

When a chain packs several distinct steps onto one line, split it
into intermediate variables whose names describe each step. A
five-call chain that filters, maps, groups, and reduces is easier
to read, debug, and modify when each stage has a name and a line
of its own. The chain still works; it just stops requiring the
reader to parse it as a single expression.

## Don't

- **Never change what the code does.** Refinement preserves
behavior; anything else is a different task.
- **Don't use nested ternary operators.** Use `switch` or
`if/else` instead.
- **Don't create overly clever solutions.** If understanding the
code requires a paragraph of explanation, the code is wrong.
- **Don't combine too many concerns into a single function or
component.** Mixed concerns are harder to test and reason about
than separated ones.
- **Don't remove abstractions that organize the code.** Helpful
abstractions stay even when inlining is technically possible.
- **Don't prioritize line count over readability.** "Fewer lines"
is not a goal; clearer code is.
- **Don't refine code outside the recently modified scope** unless
explicitly instructed. Stay inside the working set.
31 changes: 31 additions & 0 deletions skills/code-simplifier/evals/avoid-nested-ternaries.eval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// ──────────────────────────────────────────────────────────
// Generated initially from spec.yaml; durable after that. Edit
// freely to refine prompts, setup, and assertions for this
// behavior. Add or remove behaviors via spec.yaml — skillet only
// regenerates eval files for behaviors that don't have one yet.
// ──────────────────────────────────────────────────────────
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
import {
describeEval,
CriterionJudge,
SubstringJudge,
skilletHarness,
} from "@sentry/skillet/evals";

const skillRoot = dirname(fileURLToPath(import.meta.url)).replace(/\/evals$/, "");

describeEval("avoid-nested-ternaries", {
data: [
{
name: "avoid-nested-ternaries__role_label",
tests_behavior: "avoid-nested-ternaries",
input: "Please refine this function I just wrote:\n\n```js\nfunction getRoleLabel(role) {\n return role === 'admin' ? 'Administrator' : role === 'editor' ? 'Editor' : role === 'viewer' ? 'Viewer' : 'Guest';\n}\n```",
criteria: "The refined code must replace the nested ternary with either a switch statement, an if/else chain, or a lookup object/map. The result must NOT contain nested ternary operators (a ternary inside another ternary's branches). Behavior must remain the same for admin, editor, viewer, and any other role.",
},
],
harness: skilletHarness({ skill: skillRoot }),
judges: [SubstringJudge(), CriterionJudge()],
threshold: 0.75,
timeout: 120_000,
});
31 changes: 31 additions & 0 deletions skills/code-simplifier/evals/break-up-compact-chains.eval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// ──────────────────────────────────────────────────────────
// Generated initially from spec.yaml; durable after that. Edit
// freely to refine prompts, setup, and assertions for this
// behavior. Add or remove behaviors via spec.yaml — skillet only
// regenerates eval files for behaviors that don't have one yet.
// ──────────────────────────────────────────────────────────
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
import {
describeEval,
CriterionJudge,
SubstringJudge,
skilletHarness,
} from "@sentry/skillet/evals";

const skillRoot = dirname(fileURLToPath(import.meta.url)).replace(/\/evals$/, "");

describeEval("break-up-compact-chains", {
data: [
{
name: "break-up-compact-chains__named_intermediates",
tests_behavior: "break-up-compact-chains",
input: "Please refine this function I just wrote:\n\n```js\nfunction topActiveUsers(users) {\n return users.filter(u => u.active).map(u => ({ name: u.name, score: u.posts * 2 + u.comments })).sort((a, b) => b.score - a.score).slice(0, 10);\n}\n```",
criteria: "The refined code must break the compact chain into clearly named intermediate variables that show each step (e.g., `activeUsers`, `usersWithScores`, `sortedUsers`, `topTen` or similarly descriptive names). The single chained expression should be replaced with multiple statements assigned to readable names.",
},
],
harness: skilletHarness({ skill: skillRoot }),
judges: [SubstringJudge(), CriterionJudge()],
threshold: 0.75,
timeout: 120_000,
});
31 changes: 31 additions & 0 deletions skills/code-simplifier/evals/clarity-over-brevity.eval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// ──────────────────────────────────────────────────────────
// Generated initially from spec.yaml; durable after that. Edit
// freely to refine prompts, setup, and assertions for this
// behavior. Add or remove behaviors via spec.yaml — skillet only
// regenerates eval files for behaviors that don't have one yet.
// ──────────────────────────────────────────────────────────
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
import {
describeEval,
CriterionJudge,
SubstringJudge,
skilletHarness,
} from "@sentry/skillet/evals";

const skillRoot = dirname(fileURLToPath(import.meta.url)).replace(/\/evals$/, "");

describeEval("clarity-over-brevity", {
data: [
{
name: "clarity-over-brevity__expand_dense_oneliner",
tests_behavior: "clarity-over-brevity",
input: "Please refine this code I just modified:\n\n```js\nfunction processOrders(orders) {\n return orders.filter(o => o.s === 'p' && o.t > 100).map(o => ({...o, f: o.t * 0.05, n: o.t + o.t * 0.05})).sort((a, b) => b.n - a.n).slice(0, 5);\n}\n```",
criteria: "The refined code should choose clarity over brevity: use descriptive variable/property names instead of cryptic single letters (s, t, f, n), break the dense chain into clearly named intermediate steps, and not optimize for fewer lines. The result should be noticeably more readable even if longer.",
},
],
harness: skilletHarness({ skill: skillRoot }),
judges: [SubstringJudge(), CriterionJudge()],
threshold: 0.75,
timeout: 120_000,
});
Loading
Loading