AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Code Simplification

skill-celestialdust-achilles-skills-code-simplification · by celestialdust

Reduce code complexity without changing behavior — the Review-stage QUALITY axis. Use the moment a slice''s code is green but reads heavier than it should: deep nesting, nested ternaries, dead code, generic names, copy-paste duplication, speculative abstractions. Apply Chesterton''s Fence (understand before you cut) and stay scoped to what changed. Quality only — it does NOT hunt for bugs (that i…

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add skill-celestialdust-achilles-skills-code-simplification

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-celestialdust-achilles-skills-code-simplification)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Code Simplification? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Code Simplification

> Inspired by the Claude Code Simplifier plugin. Adapted here as a model-agnostic, process-driven skill for any AI coding agent.

Overview

Simplify code by reducing complexity while preserving exact behavior. The goal is not fewer lines — it's code that is easier to read, understand, modify, and debug. Every simplification must pass a simple test: "Would a new team member understand this faster than the original?"

When to Use

  • After a feature is working and tests pass, but the implementation feels heavier than it needs to be
  • During code review when readability or complexity issues are flagged
  • When you encounter deeply nested logic, long functions, or unclear names
  • When refactoring code written under time pressure
  • When consolidating related logic scattered across files
  • After merging changes that introduced duplication or inconsistency

When NOT to use:

  • Code is already clean and readable — don't simplify for the sake of it
  • You don't understand what the code does yet — comprehend before you simplify
  • The code is performance-critical and the "simpler" version would be measurably slower
  • You're about to rewrite the module entirely — simplifying throwaway code wastes effort

Inputs

Stage: Review — one axis of the parallel fan-out. The orchestrator dispatches this as a fresh, code-cold subagent on the simplification axis (maker≠checker; parallelism.md mech f). It applies its fixes; it does not just report.

Refuse to run unless ALL of these resolve:

  • The slice diff — the changed code for the slice under review (the working-tree diff / the files

the slice touched). This is the only material in scope. No diff → nothing to simplify → exit clean.

  • A green test suite for those files — the behavior oracle. Behavior-preservation is the entire

contract (Principle 1); if you cannot run the tests that pin the changed code, you cannot prove you preserved behavior → refuse rather than guess.

  • The slice's declared Regression surface — the file set you are allowed to touch. Simplify

NEVER edits a file outside it (Principle 5: Scope to What Changed).

  • Project conventionsCLAUDE.md / CONTEXT.md and the neighboring code, so simplification

converges on the house style instead of imposing a foreign one (Principle 2). Simplification that breaks project consistency is churn, not simplification.

Frozen under this skill (silent-false-green invariant): acceptance.md, the RED/passing tests, and the declared Regression surface are IMMUTABLE here. A "simplification" that edits a test, weakens an assertion, or widens/narrows the surface is gate-erosion → HALT: stop, flip the slice's gate column to you, and surface it. The whole point of this skill is to make the code simpler until the frozen tests still pass — never to change the tests until the simpler code passes.

The Five Principles

1. Preserve Behavior Exactly

Don't change what the code does — only how it expresses it. All inputs, outputs, side effects, error behavior, and edge cases must remain identical. If you're not sure a simplification preserves behavior, don't make it.

ASK BEFORE EVERY CHANGE:
→ Does this produce the same output for every input?
→ Does this maintain the same error behavior?
→ Does this preserve the same side effects and ordering?
→ Do all existing tests still pass without modification?

2. Follow Project Conventions

Simplification means making code more consistent with the codebase, not imposing external preferences. Before simplifying:

1. Read CLAUDE.md / project conventions
2. Study how neighboring code handles similar patterns
3. Match the project's style for:
   - Import ordering and module system
   - Function declaration style
   - Naming conventions
   - Error handling patterns
   - Type annotation depth

Simplification that breaks project consistency is not simplification — it's churn.

3. Prefer Clarity Over Cleverness

Explicit code is better than compact code when the compact version requires a mental pause to parse.

// UNCLEAR: Dense ternary chain
const label = isNew ? 'New' : isUpdated ? 'Updated' : isArchived ? 'Archived' : 'Active';

// CLEAR: Readable mapping
function getStatusLabel(item: Item): string {
  if (item.isNew) return 'New';
  if (item.isUpdated) return 'Updated';
  if (item.isArchived) return 'Archived';
  return 'Active';
}
// UNCLEAR: Chained reduces with inline logic
const result = items.reduce((acc, item) => ({
  ...acc,
  [item.id]: { ...acc[item.id], count: (acc[item.id]?.count ?? 0) + 1 }
}), {});

// CLEAR: Named intermediate step
const countById = new Map();
for (const item of items) {
  countById.set(item.id, (countById.get(item.id) ?? 0) + 1);
}

4. Maintain Balance

Simplification has a failure mode: over-simplification. Watch for these traps:

  • Inlining too aggressively — removing a helper that gave a concept a name makes the call site harder to read
  • Combining unrelated logic — two simple functions merged into one complex function is not simpler
  • Removing "unnecessary" abstraction — some abstractions exist for extensibility or testability, not complexity
  • Optimizing for line count — fewer lines is not the goal; easier comprehension is

5. Scope to What Changed

Default to simplifying recently modified code. Avoid drive-by refactors of unrelated code unless explicitly asked to broaden scope. Unscoped simplification creates noise in diffs and risks unintended regressions.

The Simplification Process

Step 1: Understand Before Touching (Chesterton's Fence)

Before changing or removing anything, understand why it exists. This is Chesterton's Fence: if you see a fence across a road and don't understand why it's there, don't tear it down. First understand the reason, then decide if the reason still applies.

BEFORE SIMPLIFYING, ANSWER:
- What is this code's responsibility?
- What calls it? What does it call?
- What are the edge cases and error paths?
- Are there tests that define the expected behavior?
- Why might it have been written this way? (Performance? Platform constraint? Historical reason?)
- Check git blame: what was the original context for this code?

If you can't answer these, you're not ready to simplify. Read more context first.

Step 2: Identify Simplification Opportunities

Scan for these patterns — each one is a concrete signal, not a vague smell:

Structural complexity:

| Pattern | Signal | Simplification | |---------|--------|----------------| | Deep nesting (3+ levels) | Hard to follow control flow | Extract conditions into guard clauses or helper functions | | Long functions (50+ lines) | Multiple responsibilities | Split into focused functions with descriptive names | | Nested ternaries | Requires mental stack to parse | Replace with if/else chains, switch, or lookup objects | | Boolean parameter flags | doThing(true, false, true) | Replace with options objects or separate functions | | Repeated conditionals | Same if check in multiple places | Extract to a well-named predicate function |

Naming and readability:

| Pattern | Signal | Simplification | |---------|--------|----------------| | Generic names | data, result, temp, val, item | Rename to describe the content: userProfile, validationErrors | | Abbreviated names | usr, cfg, btn, evt | Use full words unless the abbreviation is universal (id, url, api) | | Misleading names | Function named get that also mutates state | Rename to reflect actual behavior | | Comments explaining "what" | // increment counter above count++ | Delete the comment — the code is clear enough | | Comments explaining "why" | // Retry because the API is flaky under load | Keep these — they carry intent the code can't express |

Redundancy:

| Pattern | Signal | Simplification | |---------|--------|----------------| | Duplicated logic | Same 5+ lines in multiple places | Extract to a shared function | | Dead code | Unreachable branches, unused variables, commented-out blocks | Remove (after confirming it's truly dead) | | Unnecessary abstractions | Wrapper that adds no value | Inline the wrapper, call the underlying function directly | | Over-engineered patterns | Factory-for-a-factory, strategy-with-one-strategy | Replace with the simple direct approach | | Redundant type assertions | Casting to a type that's already inferred | Remove the assertion |

Step 3: Apply Changes Incrementally

Make one simplification at a time. Run tests after each change. Submit refactoring changes separately from feature or bug fix changes. A PR that refactors and adds a feature is two PRs — split them.

FOR EACH SIMPLIFICATION:
1. Make the change
2. Run the test suite
3. If tests pass → commit (or continue to next simplification)
4. If tests fail → revert and reconsider

Avoid batching multiple simplifications into a single untested change. If something breaks, you need to know which simplification caused it.

The Rule of 500: If a refactoring would touch more than 500 lines, invest in automation (codemods, sed scripts, AST transforms) rather than making the changes by hand. Manual edits at that scale are error-prone and exhausting to review.

Step 4: Verify the Result

After all simplifications, step back and evaluate the whole:

COMPARE BEFORE AND AFTER:
- Is the simplified version genuinely easier to understand?
- Did you introduce any new patterns inconsistent with the codebase?
- Is the diff clean and reviewable?
- Would a teammate approve this change?

If the "simplified" version is harder to understand or review, revert. Not every simplification attempt succeeds.

Language-Specific Guidance

TypeScript / JavaScript

// SIMPLIFY: Unnecessary async wrapper
// Before
async function getUser(id: string): Promise {
  return await userService.findById(id);
}
// After
function getUser(id: string): Promise {
  return userService.findById(id);
}

// SIMPLIFY: Verbose conditional assignment
// Before
let displayName: string;
if (user.nickname) {
  displayName = user.nickname;
} else {
  displayName = user.fullName;
}
// After
const displayName = user.nickname || user.fullName;

// SIMPLIFY: Manual array building
// Before
const activeUsers: User[] = [];
for (const user of users) {
  if (user.isActive) {
    activeUsers.push(user);
  }
}
// After
const activeUsers = users.filter((user) => user.isActive);

// SIMPLIFY: Redundant boolean return
// Before
function isValid(input: string): boolean {
  if (input.length > 0 && input.length  0 && input.length Admin;
  } else {
    return User;
  }
}
// After
function UserBadge({ user }: Props) {
  const variant = user.isAdmin ? 'admin' : 'default';
  const label = user.isAdmin ? 'Admin' : 'User';
  return {label};
}

// SIMPLIFY: Prop drilling through intermediate components
// Before — consider whether context or composition solves this better.
// This is a judgment call — flag it, don't auto-refactor.

Common Rationalizations

| Rationalization | Reality | |---|---| | "It's working, no need to touch it" | Working code that's hard to read will be hard to fix when it breaks. Simplifying now saves time on every future change. | | "Fewer lines is always simpler" | A 1-line nested ternary is not simpler than a 5-line if/else. Simplicity is about comprehension speed, not line count. | | "I'll just quickly simplify this unrelated code too" | Unscoped simplification creates noisy diffs and risks regressions in code you didn't intend to change. Stay focused. | | "The types make it self-documenting" | Types document structure, not intent. A well-named function explains why better than a type signature explains what. | | "This abstraction might be useful later" | Don't preserve speculative abstractions. If it's not used now, it's complexity without value. Remove it and re-add when needed. | | "The original author must have had a reason" | Maybe. Check git blame — apply Chesterton's Fence. But accumulated complexity often has no reason; it's just the residue of iteration under pressure. | | "I'll refactor while adding this feature" | Separate refactoring from feature work. Mixed changes are harder to review, revert, and understand in history. |

Red Flags

  • Simplification that requires modifying tests to pass (you likely changed behavior)
  • "Simplified" code that is longer and harder to follow than the original
  • Renaming things to match your preferences rather than project conventions
  • Removing error handling because "it makes the code cleaner"
  • Simplifying code you don't fully understand
  • Batching many simplifications into one large, hard-to-review commit
  • Refactoring code outside the scope of the current task without being asked

Verification

After completing a simplification pass:

  • [ ] All existing tests pass without modification
  • [ ] Build succeeds with no new warnings
  • [ ] Linter/formatter passes (no style regressions)
  • [ ] Each simplification is a reviewable, incremental change
  • [ ] The diff is clean — no unrelated changes mixed in
  • [ ] Simplified code follows project conventions (checked against CLAUDE.md or equivalent)
  • [ ] No error handling was removed or weakened
  • [ ] No dead code was left behind (unused imports, unreachable branches)
  • [ ] A teammate or review agent would approve the change as a net improvement

Outputs & handoff contract

Emits: diff — a behavior-preserving simplification of the same changed files, applied to the working tree as a separate refactor: commit, never folded into feature work (Principle 5 / Process Step 3: "Submit refactoring changes separately"). If nothing warrants simplifying, emit no diff and report clean — don't simplify for the sake of it.

Return to the orchestrator (Review fan-out aggregation) exactly one verdict:

  • applied — the refactor diff + a one-line summary per simplification, with proof that every

existing test passes WITHOUT modification (attach the suite's exit status).

  • clean — code is already readable; no change warranted.
  • halt — a worthwhile simplification could not be made without changing behavior, OR a frozen

artifact would have had to move. Name the file:line and why; do not ship the change.

Invariants on the emitted diff: stays inside the slice's Regression surface; zero test files changed; no error handling removed or weakened; the "after" is genuinely easier to read than the "before" (if not, revert — not every attempt succeeds, per Process Step 4).

STATE.md: this skill writes no STATE.md row of its own. The orchestrator owns the slice's review state and advances it only when every review axis (this skill, code-review, security-and-hardening, performance-optimization) returns non-blocking; a halt from this axis bounces the slice back to Implement (bounded rounds). Stable sections other skills depend on: none beyond the ## Verification checklist below, which is the done-predicate.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.