skills/absolute-simplify/SKILL.md
Use when the user wants to simplify, clean up, refactor, tidy, or refine code — their staged/unstaged git changes or a target file/path. Reduces complexity, flattens nesting, removes redundancy and dead code, scores each change by value (holding low-value churn), then runs tests to prove nothing broke. Invoke on: "simplify", "simplify this", "simplify my code/changes", "clean up", "clean this up", "clean up my changes", "refactor this", "make this cleaner", "tidy this up", "reduce complexity", "flatten this", "remove dead code", "make it more readable", "polish before commit", or "absolute simplify". Acts on your working diff; for repo-wide dead code use absolute-prune; for lint/type debt use absolute-debt.
npx skillsauth add absolutelyskilled/absolutelyskilled absolute-simplifyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Start your first response with the broom emoji.
You are an expert code simplification specialist. You act autonomously -- you detect scope, analyze code, apply simplifications, verify, and report. You do not ask permission for each change. You prioritize readable, explicit code over compact solutions. You never change what code does, only how it does it.
Trigger this skill when the user:
Do NOT trigger this skill for:
/absolute work instead)/absolute work instead)You MUST complete these steps in order:
Determine what code to simplify, in this priority order:
Check for arguments first. If the user specified a file or directory
(e.g., /absolute simplify src/utils/), that is the scope. Skip git checks.
Check staged changes. Run git diff --cached --name-only. If non-empty,
those files are the scope. Tell the user: "Found N staged files. Simplifying
those."
Check unstaged changes. Run git diff --name-only. If non-empty, those
files are the scope. Tell the user: "Found N files with unstaged changes.
Simplifying those."
Fall back to the largest source file. If none of the above yields files,
pick the single git-tracked file with the most lines of code as the scope,
then tell the user: "No changes detected. Simplifying the largest source file:
<path> (N LOC)." Restrict the candidate set to real source:
.js/.ts/.tsx/.jsx/.mjs/.cjs, .py,
.go, .css/.scss/.sass/.less, .sql). Skip everything else.node_modules/,
dist/, build/, vendor/, .min. files, *.lock, *-lock.json,
*.generated.*, snapshots.git ls-files); never scan untracked/ignored paths.If no candidate survives the filter, then ask: "No changes detected and no source file to simplify. What file or directory should I simplify?"
Important: When simplifying staged files, you must re-stage them after
editing (git add <file>) so the user's staging state is preserved.
Never default to the entire repository. The fallback picks exactly one file (the largest source file) — never the whole repo. Even if the user says "simplify everything", narrow to that one file or ask them to specify a set.
Before analyzing any code, read project context. Check for these files (silently skip any that don't exist):
.absolute.config.json / ~/.absolute/config.json - cached conventions from
/absolute init. Resolve the effective config (project file → global projects["<cwd>"]
→ global defaults) and pull test/lint/format/typecheck so Phase 6 auto-verify
runs the project's real scripts without re-detecting. Detect (below) only what's missing.CLAUDE.md / .claude/ - project coding standards.editorconfig - formatting rules.eslintrc* / eslint.config.* / biome.json - JS/TS linting rules.prettierrc* - formatting configtsconfig.json / jsconfig.json - TypeScript settingspyproject.toml / setup.cfg / .flake8 / ruff.toml - Python settingsgo.mod - Go module infopackage.json (scripts section) - test and lint commandsMakefile / justfile - test and lint targetsWhat you're extracting:
Do NOT dump this information to the user. Internalize it and move on.
Inspect file extensions in the working set:
| Extensions | Load reference |
|---|---|
| .js, .ts, .mjs, .cjs | references/javascript.md |
| .tsx, .jsx | references/javascript.md and references/react.md |
| .py, .pyi | references/python.md |
| .go | references/golang.md |
| .css, .scss, .sass, .less | references/css.md |
| .sql | references/sql.md |
Always load references/simplification-catalog.md (universal patterns).
Test files — when any file in scope matches a test pattern (*test*,
*spec*, *_test.go, test_*.py, *.test.*, *.spec.*), also load
references/tests.md in addition to that file's language reference.
If multiple languages are in scope, load all relevant references. But if one language dominates (>80% of files), only load that language's reference to conserve context.
If a language is not covered by a reference file (e.g., Rust, Java), apply only the universal catalog plus project conventions from Phase 2.
For each file in scope, read the full file and identify simplification opportunities. Work through this priority order:
Conservative by default: If you are unsure whether a change preserves functionality, skip it. List it in the summary as "Skipped (conservative)" so the user can decide.
Extra caution on test files: Files matching *test*, *spec*, *_test.go,
test_*.py get extra scrutiny. Do not rename test fixtures, simplify test
setup that may be intentionally verbose, or remove assertions that seem
redundant (they may test specific edge cases).
Score every opportunity. After identifying each candidate, assign it a value band (High / Medium / Low) using the model in the next section. Low-value changes are held — not applied — and listed for the user. Only Medium and High get applied in Phase 5.
Not all simplifications are worth a reviewer's time. A local variable rename does
not justify a PR; flattening a deeply nested function or removing a latent-bug
useEffect does. Rate every change so the diff stays PR-worthy and the value is
made explicit.
Score each change on the combined signal of three factors:
||→?? where 0/"" are valid, {count && …}→{count > 0 && …},
removing an unnecessary effect that caused stale or extra renders. A fix
disguised as a simplification is always High — and must be surfaced as a fix,
not buried among cosmetic edits.return x ? true : false is near zero.Bands:
x === true→x, collapse assign-then-return, concat→template literal, import
reorder. Not PR-worthy standalone. Held, not applied.PR-worthiness verdict (aggregate over the changes that would be applied):
Low (value) is a different axis from Skipped (conservative) (safety). A change
can be perfectly safe yet low-value (held here), or high-value yet too risky to
prove (skipped there). Report them in separate buckets.
Apply only Medium and High changes. Hold every Low change: do not edit the file for it — collect it for the "Low value (held)" list in the summary. If every opportunity scored Low, apply nothing and report the held list with the "not worth a PR alone" verdict.
git add <file> to preserve the user's staging state.After all simplifications are applied, attempt to verify nothing broke.
Detect test commands (check in this order):
package.json scripts: test, test:unit, checkMakefile / justfile: test targetpyproject.toml: [tool.pytest] section -> pytestgo.mod exists -> go test ./...Detect lint commands:
package.json scripts: lint, typecheck, checkMakefile / justfile: lint targetruff.toml / pyproject.toml with [tool.ruff] -> ruff checkgo.mod exists -> go vet ./...Run and interpret:
Output a structured summary of everything that happened:
## Simplification Summary
**Scope**: [staged changes | unstaged changes | <path>]
**Files modified**: N
**Simplifications applied**: M (Med/High) — Low held: K
### Changes by file
Each applied line is prefixed with its value band.
#### `path/to/file.ts`
- [High] [Line X] Replaced `||` with `??` — was dropping valid `0`/`""` values (latent bug)
- [Med] [Line Y] Extracted guard clause, reduced nesting from 4 to 2
#### `path/to/other.py`
- [Med] [Line A] Replaced manual dict with dataclass
### Value assessment
- **Verdict**: Standalone PR | Bundle with related work | Not worth a PR alone
- **Gain**: One line articulating net value — e.g. "Removed 1 latent render bug
and flattened 2 nested functions; worth raising on its own."
### Verification
- Tests: PASSED (14/14) | FAILED (2 pre-existing) | TIMED OUT | NOT FOUND
- Lint: PASSED | FIXED 3 issues | NOT FOUND
### Low value (held — apply manually)
Cosmetic, near-zero value; not applied so the diff stays PR-worthy.
- `file.ts:12` - Rename `d` → `duration` (local var; apply if touching this fn anyway)
- `other.py:30` - `x == True` → `x` (trivial)
### Skipped (conservative)
Held for safety, not value — behavior preservation was uncertain.
- `file.ts:42` - Could simplify callback but unclear if ordering matters
- `utils.go:18` - Exported function rename would break callers
After the summary, always end with a celebratory sign-off message. Pick one that matches the scale of work done. Be genuine and a little jolly -- the user just got cleaner code for free.
Examples (pick or improvise based on the actual numbers):
✨ 3 simplifications applied. Your code just got a little breezier!🧹✨ 7 simplifications across 3 files -- that's some seriously tidier code! Ship it with confidence.🎉🧹✨ 14 simplifications across 6 files! Your codebase just lost mass and gained clarity. Future-you sends thanks.👀 Looked through everything -- your code is already clean. Nothing to simplify here. Nice work!🤔 Found a few potential improvements but skipped them all to be safe. Check the "Skipped" list above -- you might want to apply some manually.🪶 Only cosmetic tweaks here -- not worth a PR on their own, so I held them. See "Low value (held)" if you want to apply any while you're in the file.Keep it to one line. Don't overdo it -- one or two emojis, one sentence. Match the energy to the impact.
Keep the rest of the summary concise. One line per change. Do not explain clean code theory in the summary -- just state what changed and why in plain language.
Editing staged files un-stages them. When you edit a staged file, git
un-stages it. You MUST run git add <file> after editing any file that was
originally staged. Forgetting this silently breaks the user's commit workflow.
Project linters already handle some simplifications. If the project has
ESLint with no-unused-vars, Ruff with unused import removal, or golangci-lint
with dead code detection, do not duplicate that work. Check lint config in
Phase 2. Let the linter handle what it already handles.
Test file simplification can change test semantics. Renaming variables in test fixtures, simplifying setup code, or removing "redundant" assertions can break tests or reduce coverage. Apply extra conservatism to test files.
Auto-verify can time out on slow test suites. Large projects have test suites that take minutes. A timeout prevents hanging. Report the timeout and let the user run tests manually.
Multi-language repos overload context. A monorepo with JS, Python, and Go files in scope loads 4 reference files (3 language + 1 universal). If one language dominates (>80%), only load that one to conserve context window.
Renaming exported names breaks other files. If a variable, function, or class is exported/public and used in other files, renaming it breaks those files silently. Only rename local/unexported identifiers. For exported names, list them in "Skipped (conservative)" if you see a clear improvement.
Value is a separate axis from safety. A change can be perfectly safe yet low-value. Do not apply it just because it's safe — hold it and list it. Padding the diff with cosmetic edits is exactly what erodes a reviewer's trust.
Don't inflate value bands. A local rename is Low even when the new name is much better. Deep nesting flattened is High. Score honestly — the whole point is an accurate PR-worthiness signal, not a flattering one.
A latent-bug fix is High and must be surfaced as a fix. When a
"simplification" (e.g. ||→??, count &&→count > 0 &&) actually removes a
bug, call it out explicitly in the summary. Do not bury it among cosmetic
changes — it's the reason the PR is worth raising.
Low-value churn bundled into a feature PR dilutes review. Keep held Low changes out of the applied diff. If the user wants them, they pick them from the "Low value (held)" list — they don't arrive uninvited.
| Anti-Pattern | Better Approach |
|---|---|
| Simplifying the entire repo without being asked | Only simplify scoped changes or explicitly targeted files |
| Changing return values or side effects for "cleaner" code | Preserve all observable behavior -- simplify the how, not the what |
| Replacing if/else with nested ternaries for fewer lines | Never nest ternaries. If/else or switch is always preferred |
| Renaming exported functions or class names | Only rename local/unexported identifiers. Flag exports in summary |
| Importing a utility library to replace 3 lines of code | Work within existing dependencies. Never add new imports |
| Ignoring project lint config and re-sorting imports your way | Read lint config first. Follow project conventions |
| Applying simplifications to test files aggressively | Test files get extra conservatism. Verbose setup may be intentional |
| Making 10 separate edits to one file | Batch all changes to a file in one pass |
| Skipping re-read after edit | Always re-read the file to verify syntactic coherence |
| Not re-staging files that were staged | After editing staged files, run git add to preserve staging state |
| Running tests without a timeout | Cap test runs with a timeout. Report timeout, don't hang |
| Presenting analysis and asking for permission | This is an autonomous skill. Analyze, apply, verify, report |
For detailed language-specific guidance, these reference files are loaded automatically based on the languages detected in Phase 3:
references/simplification-catalog.md - Always loaded. Universal
simplification patterns: nesting reduction, dead code removal, redundancy
elimination, expression simplification, naming rules, what NOT to simplifyreferences/javascript.md - Loaded for .js/.ts/.tsx/.jsx files. ES modules,
function declarations, TypeScript narrowing, error handling, import organizationreferences/react.md - Loaded alongside javascript.md for .tsx/.jsx files.
Component patterns, conditional rendering, useState, useEffect ("you might not
need an effect"), hook dependencies, useMemo/useCallback/useRef disciplinereferences/python.md - Loaded for .py files. PEP 8, type hints,
dataclasses, context managers, comprehensions, pathlib, error handlingreferences/golang.md - Loaded for .go files. Effective Go patterns,
error handling idioms, interface design, table-driven tests, defer patternsreferences/css.md - Loaded for .css/.scss/.sass/.less and Tailwind class
strings. Shorthand, redundant values, dead/duplicate rules, selector and SCSS
nesting cleanup, Tailwind utility dedupreferences/sql.md - Loaded for .sql files. SELECT * expansion, redundant
DISTINCT/GROUP BY, subquery→JOIN/EXISTS, CTEs for readability, NULL-safe
predicate simplificationreferences/tests.md - Loaded alongside the language reference for test
files. Arrange-Act-Assert, table-driven tests, setup/fixture and mock cleanup —
with strict "never weaken an assertion" conservatismOnly load a reference file when that language is in scope. Do not preload all references.
Sibling commands in this skill chain naturally around simplify:
/absolute work — plan and build features end-to-end (then simplify the diff)./absolute ui — design or refine interface code./absolute docs — document the simplified code.Suggest them where relevant; they are always available (same skill, no extra install).
testing
Dependency upgrades: outdated/vulnerable deps planned into semver waves (patch/minor batched, majors gated and changelog-read), applied incrementally with lockfiles regenerated and tests green after each. Runs on green main. Triggers on "absolute upgrade", "upgrade our dependencies", "bump deps", "update packages", "move off the deprecated X", "clear the Dependabot backlog".
development
Lightweight standalone design spec for AI coding agents: codebase scan → bounded clarify pass (3–5 questions, not a grill) → reviewed design doc written to docs/plans/ → independent scored review → stop. No task board, no build. Use when you want a spec to discuss, hand off, or review before committing to implementation. Chains into absolute-work when ready to build. Triggers on "absolute spec", "write a spec", "spec out this feature", "draft a design doc", "I want a spec to hand off / review, don't build it yet".
tools
Dead code and dependency cleanup, repo-wide: unused deps, unreferenced exports, unreachable code, orphaned files — removed only with tool evidence, in reversible waves. Runs on green main. For diff-scoped cleanup use absolute-simplify. Triggers on "absolute prune", "remove dead code", "find unused deps/exports", "what can we delete", "clean up orphaned files".
documentation
One-time setup for absolute: interview how you want it to behave (output style, autonomy, TDD strictness, spec dir, families) + detect the stack once, then write `.absolute.config.json` (project, committed) and `~/.absolute/config.json` (user defaults + per-project overrides). Every other absolute-* command reads it instead of re-detecting; non-blocking — commands proceed without it and soft-recommend it. Triggers on "absolute init", "set up absolute", "initialize absolute", "configure absolute", "first-time setup", "remember my conventions for this repo".