From taches-principled
Refactors complex code to reduce cognitive load. Use when user says 'simplify this', 'clean up this code', 'reduce complexity', or 'this is too nested'.
How this skill is triggered — by the user, by Claude, or both
Slash command
/taches-principled:code-simplifyWhen to use
Use when the user says "simplify this", "clean up this code", "reduce complexity", or "this is too nested". IMMEDIATELY when encountering functions over 40 lines, nesting beyond 3 levels, or duplicated code blocks. Do NOT use when code is correct but needs review for bugs (use code-review), for greenfield architecture (use create-plans), or when nesting is intentional for performance.
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Read this section first. It determines whether and how to proceed.
Read this section first. It determines whether and how to proceed.
IF the code compiles and passes tests: -> Proceed with simplification. You have a safety net. IF there are NO tests: -> Read the "Simplify Without Tests" section below. Do NOT refactor without reading it. IF you are refactoring risky code (state machines, async chains, crypto, parsing): -> Use Opus via the agent template below. Default is Sonnet. IF the code is in active development by others: -> Stop. Simplification conflicts with churn. Note the tech debt and move on. IF this is a one-person project or abandoned code: -> Full speed. Simplify aggressively as long as readability improves.
Claude already refactors on request. This skill changes when and how it simplifies, targeting the specific failure modes that make codebases hard to maintain over time.
| Default Claude Behavior | This Skill's Behavior |
|---|---|
| Refactors when asked, limited by conversation context | Actively seeks simplification opportunities during any code visit |
| Treats all code equally | Applies numeric thresholds to target only high-cognitive-load code |
| May introduce abstractions prematurely | Bias toward monoliths — extract only when proven necessary |
| No systematic pipeline — simplifies opportunistically | 5-stage pipeline guarantees consistent output |
| No guardrails for untested code | Exception rules for untested code with safety-first defaults |
Simplification is refactoring that reduces cognitive load. If the change does not make the code easier to hold in working memory, it is not simplification — it is rearrangement. Judge every transformation against this single criterion.
Run these stages in order. Each stage feeds the next. Stop when the code meets the thresholds in the table below.
Identify anonymous blocks, magic values, inline conditionals, and bare literals. Give each a name that captures intent.
# Before
if x > 86400: process_later()
# After
SECONDS_IN_DAY = 86400
if elapsed > SECONDS_IN_DAY: process_later()
Rule of thumb: If you have to read the body to understand a value or block, extract and name it.
Flatten conditionals with early returns, guard clauses, and inversion. Max 3 levels of nesting (see Thresholds table).
# Before
if user:
if user.is_active:
if user.has_permission("edit"):
do_edit()
# After
if not user or not user.is_active:
return
if not user.has_permission("edit"):
return
do_edit()
Consolidate repeated patterns. Extract to a named function or data-driven loop. Do NOT extract when the duplication is coincidental (same text, different semantics).
Remove commented-out code, unreachable branches, unused variables, unused imports, and unreachable functions. Commenting-out is not version control — git handles history.
When a chain of if/elif or match/case branches over a single enum or string, replace with a lookup table (dict, map, configuration object). If the branching involves side effects, extract the side effects into functions stored in the table.
| Situation | Decision | Rationale |
|---|---|---|
| Function >40 lines | Simplify | Exceeds working-memory capacity; extract cohesive subgroups |
| Nesting >3 levels | Simplify | Each level adds a mental stack frame |
| Duplication >3 copies | Simplify | Maintainability debt; extract or parameterize |
| Active development churn | Leave alone | Simplification conflicts with ongoing edits |
| Serialization / data mapping | Leave alone | Often necessarily verbose; clarity suffers from extraction |
| Hot path / tight loop | Simplify carefully | Keep extracted, but verify no perf regression |
| Code you don't fully understand | Investigate first | Simplifying misunderstood code creates bugs |
| Single-use glue / adapter code | Leave alone | Indirection for its own sake increases cognitive load |
When a project has no tests, simplification carries risk. Follow these rules in order:
# SIMPLIFY: <reason> so the next reader (or a test-writer) can verify intent.Thresholds are guides, not laws. If a function serves as a crucial business-rule with high complexity that is inherent, document the decision and leave it. If the complexity is accidental, simplify.
| Metric | Threshold | Action |
|---|---|---|
| Function length | >40 lines | Extract cohesive subgroups |
| Nesting depth | >3 levels | Guard clauses, early returns |
| Parameters | >5 | Bundle into config object |
| Boolean flags in params | >=2 | Split function or use enum |
| Duplicate blocks | >=3 occurrences | Extract or parameterize |
| Comments explaining "what" (not "why") | Any | Extract to named function; the name replaces the comment |
| Variables reassigned | >3 times in same scope | Split into smaller functions |
| Chained method calls | >4 | Extract intermediates with named variables |
Each anti-pattern shows the wrong approach, the right approach, and the consequence of getting it wrong.
Wrong: Splitting a 50-line function into 5 ten-line functions, each called once. Right: Extract only when the extracted block has a clear identity and can be named. Consequence: Indirection without abstraction. The reader must jump between files to trace logic. Cognitive load increases.
Wrong: Renaming variables, extracting functions, and changing control flow in the same pass. Right: One transformation per commit. Extract first, rename in a separate change. Consequence: Bugs become untraceable. If a test fails, you cannot tell which transformation caused it.
Wrong: Removing a null check because "the caller never passes null." Right: Keep defensive checks unless you can prove the type system enforces the invariant. If the language lacks non-null types, keep the check. Consequence: Latent production bugs. The null check existed because someone — maybe the original author — learned the hard way.
Wrong: Replacing a readable single-use loop with itertools.groupby, functools.reduce, or a chain of list comprehensions.
Right: Use comprehensions for simple maps/filters. Leave loops for complex multi-step transformations. Readability is the metric.
Consequence: The simplification becomes harder to read than the original. You have introduced a puzzle, not a solution.
Wrong: Replacing nested conditionals with a single flat block gated by should_process = all(conditions) — the flags now encode the original nesting implicitly.
Right: Early returns for each condition. Each guard is self-documenting.
Consequence: Debugging requires evaluating the boolean composition mentally. The work of understanding the nesting is replaced by the work of understanding the boolean algebra.
Wrong: Inlining a helper that is called in 3 places but has different semantics in each call site. The duplication was coincidental, not structural. Right: Only inline when the extracted code is called in one place or the call sites are semantically identical. Consequence: A seemingly safe refactor introduces subtle semantic differences. The code passes tests but fails at runtime under edge cases.
Wrong: Replacing a naive loop with a cached/generator/deferred version during the simplification pass. Right: Simplify first. Profile second. Optimize third. Only if the profile says it matters. Consequence: Premature optimization creates complex code that is harder to simplify later. You have increased cognitive load for hypothetical performance gains.
Wrong: Keeping commented-out blocks "in case someone needs to see the old version." Right: Git history is the record. Delete commented-out code unconditionally. Consequence: Readers waste mental cycles determining whether commented code is relevant. The file grows without benefit. Signal-to-noise ratio degrades over time.
Use this template when delegating simplification to a subagent. Copy the full block and fill in the bracketed fields.
You are a code simplification agent. Your sole purpose is to reduce cognitive load in the target code — not add features, not optimize performance, not fix bugs (unless a bug is blocking simplification).
Apply the 5-stage Simplification Pipeline in order: Extract and Name, Reduce Nesting, Remove Duplication, Eliminate Dead Code, Replace State Machines with Data. Do not skip stages. Do not reorder them. Do not combine stages in a single pass.
You must produce exactly one file per modified source file: a diff in unified format. Place each diff in .claude/artifacts/{task_id}-{filename}.diff. Do not apply changes directly unless the orchestrator explicitly approves.
For each diff, include a summary line:
Switch models by re-spawning the subagent with the appropriate model pin. Do not downgrade mid-task.
Append this to every subagent prompt:
You are a subagent executing a delegated simplification task. Your context starts fresh — you have no access to prior conversation or other subagents' outputs. When complete, return your full results (file paths, diffs, and findings) to the orchestrator in structured form. If you encounter anything unexpected or have any question or doubt, stop and report back with what you found and what is unclear. Do not proceed silently on assumptions.
If the subagent encounters any of these conditions, it must stop and report immediately — do not attempt recovery:
This skill applies to any code file you read or edit, regardless of language. Simplification is a cross-cutting concern — it is not restricted to a specific directory or module. When you encounter code exceeding any numeric threshold, evaluate whether to simplify now or leave a marker.
The scope expands to imported dependencies only when tracing call paths. You may read a dependency's source to understand a function, but you must NOT modify it.
Do NOT simplify:
A simplification pass is complete when ALL of the following are true:
A /code-simplify command exists in this project that wraps this skill for quick invocation. Running it loads this skill and prompts for the target code.
Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub git-fg/taches-principled