hunter-party-go/simplicity-hunter-go/SKILL.md
Audit Go code for unnecessary structural complexity — duplication, avoidable abstractions, dead logic paths, over-parameterized APIs, deep nesting, interface pollution, channel misuse, and mixed concerns. Recommends the simplest shape that preserves intended behavior. Use when: reviewing Go code for over-engineering, reducing complexity after prototyping, enforcing reuse over addition, or simplifying before a refactor.
npx skillsauth add skyosev/agent-skills simplicity-hunter-goInstall 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.
Audit Go code for structural complexity — places where logic is duplicated, abstractions don't earn their keep, control flow is deeper than it needs to be, or concerns are mixed. The goal: the simplest code that preserves intended behavior.
Default to delete. The best simplification is removal. If code can be deleted without changing behavior, delete it. If it can be replaced by an existing function, replace it.
One canonical path. When two implementations do the same thing, pick one and remove the other. Avoid "shared helper + keep both paths" unless required by genuinely different consumers.
Abstractions must earn their place. Reject new wrappers, managers, and factories unless they reduce total complexity through reuse. An interface that serves one call site and has one implementation is indirection, not simplification.
Flags are complexity multipliers. Each boolean parameter doubles the logic paths. Prefer one linear flow; if a flag is unavoidable, require sharp naming and a removal plan.
Inline the trivial. Pass-through wrappers, single-use helpers, and indirection layers that add no logic should be inlined. Measure value by what the wrapper adds, not by what it hides.
Separate concerns, don't mix them. A function that fetches data AND transforms it AND logs errors has three reasons to change. Split into focused functions with intent-revealing names.
Flatten, don't nest. Deep nesting (3+ levels) signals mixed concerns or missing early returns. Use guard clauses and early returns to keep the main path at low indentation.
Channels are not always the answer. A mutex protecting a map is simpler than a channel-based worker pattern for simple state. Use channels for communication, mutexes for state protection.
Repeated logic across functions, packages, or tests.
Signals:
Action: Choose one canonical implementation; delete the rest; extract shared logic only if it serves 2+ genuine consumers.
Wrappers, managers, registries, or factories that serve a single call site or add no logic.
Signals:
Action: Inline the abstraction. If it exists for testability, note that and keep if justified.
Unreachable branches, unused internal functions, stale feature flags, and leftover alternate implementations.
Signals:
if branches that can never be true given the input types or call sitesdefault cases in type switches that can never trigger (all types handled)Action: Delete. If uncertain, flag with evidence of zero usage.
Functions with many parameters, boolean flags, or option structs that create a combinatorial explosion.
Signals:
if opts.X branches for most fieldsWith* functions) applied to functions with 1-2 optionsDo not flag:
Action: Split into focused functions per use case, or reduce to the parameters actually used by callers. Reserve functional options for truly variadic configuration.
Interfaces created for theoretical extensibility rather than actual need.
Signals:
Action: Remove the interface and use the concrete type. Introduce the interface when a second implementation or test double is actually needed.
Single functions or types that handle multiple unrelated responsibilities.
Signals:
Do not flag:
Action: Extract each concern into a named function. The parent function becomes a coordinator.
Deep nesting, nested conditionals, and convoluted loops.
Signals:
if/else if chains with 4+ branches (consider a switch or map lookup)if err != nil { return } guard clauses are idiomatic
Go, not a nesting problem — flag only when error handling creates genuinely deep indentation)Action: Flatten with guard clauses and early returns. Replace nested conditionals with switch statements or map lookups. Extract loop bodies into named functions when complex.
Concurrency patterns more complex than the problem requires.
Signals:
select with a single case and no timeoutAction: Use the simplest concurrency primitive that works. Mutex for state, channel for communication, goroutine for actual parallelism.
main/master)BASE=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo main)
SCOPE=$(git diff --name-only $(git merge-base HEAD $BASE)...HEAD)
Constrain all subsequent scans to the resolved surface.EXCLUDE='--glob !**/vendor/** --glob !**/testdata/**'
# Deep nesting (4+ indentation levels, tab-indented)
rg '^\t{4,}\S' --type go $EXCLUDE
# Boolean parameters
rg --pcre2 '\w+\s+bool[,)]' --type go $EXCLUDE --glob '!**/*_test.go'
# Functions with many parameters
rg --pcre2 'func\s+(\(\w+\s+\*?\w+\)\s+)?\w+\([^)]{80,}\)' --type go $EXCLUDE
# Interfaces with single implementation
rg 'type\s+\w+\s+interface' --type go $EXCLUDE
# Unused unexported functions (candidates)
rg 'func\s+[a-z]\w+\(' --type go $EXCLUDE --glob '!**/*_test.go'
# Channel complexity
rg 'chan\s+chan|<-\s*<-' --type go $EXCLUDE
# Goroutine launches
rg 'go\s+func|go\s+\w+\(' --type go $EXCLUDE
For each complexity signal, determine:
Save as YYYY-MM-DD-simplicity-hunter-audit-{$LLM-name}.md in the project's docs folder (or project root if no docs folder exists).
# Simplicity Hunter Audit — {date}
## Scope
- Surface: {diff / path / codebase}
- Files: {count or list}
- Exclusions: {list}
## Findings
### Duplication
| # | Locations | Description | Action |
| - | --------- | ----------- | ------ |
| 1 | file:line, file:line | Near-identical validation logic | Deduplicate into shared function |
### Unnecessary Abstractions
| # | Location | Abstraction | Consumers | Action |
| - | -------- | ----------- | --------- | ------ |
| 1 | file:line | `ConfigManager` struct | 1 | Inline |
### Dead Code Paths
| # | Location | Code | Evidence | Action |
| - | -------- | ---- | -------- | ------ |
| 1 | file:line | `legacyHandler()` | 0 internal call sites | Delete |
### Over-Parameterized APIs
| # | Location | Function | Params | Action |
| - | -------- | -------- | ------ | ------ |
| 1 | file:line | `Render(a, b, c, d, e bool)` | 5 booleans | Split by use case |
### Interface Pollution
| # | Location | Interface | Implementations | Action |
| - | -------- | --------- | --------------- | ------ |
| 1 | file:line | `Processor` | 1 (no test doubles) | Remove, use concrete type |
### Mixed Concerns
| # | Location | Function | Concerns | Action |
| - | -------- | -------- | -------- | ------ |
| 1 | file:line | `ProcessOrder()` | fetch + transform + log | Extract into 3 functions |
### Complex Control Flow
| # | Location | Pattern | Depth | Action |
| - | -------- | ------- | ----- | ------ |
| 1 | file:line | Nested if/else | 4 | Flatten with guard clauses |
### Channel/Goroutine Overuse
| # | Location | Pattern | Simpler Alternative | Action |
| - | -------- | ------- | ------------------- | ------ |
| 1 | file:line | Channel for shared counter | `sync/atomic` | Replace |
## Recommendations (Priority Order)
1. **Must-fix**: {high-impact duplication, dead code with confidence}
2. **Should-fix**: {unnecessary abstractions, over-parameterized APIs, interface pollution}
3. **Consider**: {control flow improvements, concern separation, channel simplification}
file/path.go:line with the exact code.if err != nil { return err } as complexity — flag it only when the error handling is genuinely doing
different things that could be unified.development
Transforms vague feature ideas into precise, codebase-grounded technical requirements. Use when requirements are ambiguous/incomplete, the user struggles to describe behavior, terminology is unclear, or multiple concepts are mixed. Output is a requirements spec—NOT an implementation plan.
tools
Audit TypeScript type definitions for design debt — duplicated shapes, missing derivations, over-engineered generics, under-constrained type parameters, reinvented utility types, and disorganized type architecture. Type structure and maintainability, not type enforcement. Use when: reviewing type definitions for maintainability, reducing type duplication, simplifying over-engineered type-level logic, or reorganizing type architecture after growth.
development
Audit TypeScript test code for quality gaps — missing coverage on critical paths, brittle tests coupled to implementation, over-mocking, assertion-free tests, missing edge cases, and duplicated test setup. Focuses on test effectiveness, not production code structure. Use when: reviewing TypeScript test suites for reliability, reducing false-positive test failures, improving coverage of critical business logic, or cleaning up test debt.
tools
Audit TypeScript class and interface design for SOLID violations — god classes, rigid extension points, broken substitutability, fat interfaces, and concrete dependency chains. Focuses on responsibility assignment and abstraction fitness. Use when: reviewing class hierarchies, preparing for extension with new variants, reducing coupling between services, or improving testability of class-heavy code.