
Deslop
- 2 installs
- 35 repo stars
- Updated April 29, 2026
- spences10/claude-code-toolkit
Scans staged or recent-commit code for AI-generated verbosity patterns and proposes removals one finding at a time for the user to approve.
About
Detects AI-generated code slop such as obvious comments and over-engineered error handling in staged or recent changes, then presents removals for approval. A developer uses it after generating code to strip filler before committing.
- Targets only staged changes or recent commits, never the whole codebase
- Classifies findings by severity and never auto-fixes without approval
Deslop by the numbers
- 2 all-time installs (skills.sh)
- Ranked #947 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/spences10/claude-code-toolkit --skill deslopAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 35 |
| Last updated | April 29, 2026 |
| Repository | spences10/claude-code-toolkit ↗ |
What it does
Scans staged or recent-commit code for AI-generated verbosity patterns and proposes removals one finding at a time for the user to approve.
Files
Deslop
Identify and remove AI-generated verbosity patterns from code.
Trigger Patterns
- "/deslop"
- "clean up AI-generated code"
- "remove slop"
- "too much AI verbosity"
- "remove unnecessary comments"
What This Is NOT
- Not techdebt-finder — techdebt finds structural issues to refactor. Deslop finds AI verbosity to delete.
- Not simplify — simplify reviews code for reuse/quality. Deslop targets specific AI generation patterns.
Scope
Target recent or staged changes only, not the whole codebase:
# Check staged changes
git diff --cached --name-only
# Check recent commits (default: last commit)
git diff HEAD~1 --name-onlyIf the user doesn't specify scope, ask: staged changes or last N commits?
Workflow
1. Determine Scope
Identify which files to scan:
- Staged files (
git diff --cached) - Recent commits (
git diff HEAD~N) - Specific files if user provides them
Only scan code files. Skip markdown, docs, and config files.
2. Scan for Slop Patterns
Read each file in scope. Apply the 10 detection patterns from slop-patterns.md.
For each match, record:
- File and line number
- Pattern type
- The offending code
- Suggested removal/replacement
3. Classify Findings
Group by severity:
| Severity | Description | Examples |
|---|---|---|
| High | Pure noise, safe to remove | Obvious comments, filler summaries |
| Medium | Likely unnecessary, review | Over-engineered error handling, verbose docstrings |
| Low | Possibly intentional, confirm | Extra validation, type annotations |
4. Present Findings
Show each finding one at a time for user review. Follow the workflow in review-workflow.md.
Format:
## Finding 1/N — [pattern-type] (severity)
File: src/utils.ts:23-25
Current:
// This function adds two numbers together and returns the result
function add(a: number, b: number): number {
Suggested:
function add(a: number, b: number): number {
Remove? [y/n/skip-all-of-type]5. Apply Approved Removals
Only apply changes the user explicitly approves. Never auto-fix.
After all findings reviewed, show summary:
## Deslop Summary
- Reviewed: 15 findings
- Removed: 10
- Skipped: 5
- Lines removed: 34Anti-patterns
- Never auto-fix without user approval
- Never scan entire codebase unprompted
- Never remove comments that explain non-obvious logic
- Never touch markdown or documentation files
- Never remove license headers or legal comments
References
- slop-patterns.md - The 10 AI slop detection patterns
- review-workflow.md - Interactive review workflow
Review Workflow
How to present deslop findings interactively.
Pre-Review Summary
Before presenting individual findings, show an overview:
## Deslop Scan Results
Scoped to: staged changes (or: last 2 commits, specific files)
Files scanned: 8
Findings: 15
By severity:
High: 7 (safe to remove)
Medium: 5 (likely unnecessary)
Low: 3 (confirm with user)
By pattern:
Unnecessary comments: 5
Verbose docstrings: 3
Redundant type annotations: 3
Over-engineered errors: 2
Filler summaries: 2
Proceed with review? [y/n]Presentation Order
Present findings grouped by file, ordered by severity within each file:
1. High severity first — builds trust by showing clear wins 2. Medium severity — user sees the value, more willing to review 3. Low severity last — requires most judgment
Within the same file, present findings in line-number order so the user can follow the code flow.
Individual Finding Format
Each finding must include:
## Finding 3/15 — Unnecessary Comment (High)
File: src/services/auth.ts:42
Current (lines 42-43):
│ // Check if the user is authenticated
│ if (!req.user) {
Suggested:
│ if (!req.user) {
Remove? [y/n/skip-type]Required elements:
- Counter (3/15) — progress indicator
- Pattern name — which slop pattern matched
- Severity — High/Medium/Low
- File and line — exact location
- Current code — the slop in context (show 1-2 surrounding lines)
- Suggested code — what it looks like after removal
- Action prompt — user chooses what to do
User Actions
| Input | Meaning |
|---|---|
| y | Remove this instance |
| n | Keep this instance |
| skip-type | Skip all remaining findings of this pattern type |
| stop | End review, apply approved changes so far |
Context Rules
Show enough context
Always show at least 1 line above and below the slop so the user can judge whether the comment/code is actually unnecessary in context.
Borderline cases
For Medium and Low severity findings, add a brief note explaining why it was flagged:
## Finding 8/15 — Excessive Validation (Medium)
File: src/handlers/order.ts:15-22
Note: This validation duplicates the schema check in middleware (line 8).
Current (lines 15-22):
│ if (!order.id) {
│ throw new Error("Order ID required");
│ }
│ if (!order.items?.length) {
│ throw new Error("Order must have items");
│ }
Suggested:
│ (remove — validated by orderSchema middleware)
Remove? [y/n/skip-type]Multi-line removals
For findings spanning multiple lines (verbose docstrings, error handling blocks), show the full block being removed and the simplified replacement.
Applying Changes
After review completes (or user says "stop"):
1. Apply all approved removals in reverse line-number order (bottom-up) to avoid line number shifts 2. Show summary of what was changed
Post-Review Summary
## Deslop Complete
Files modified: 5
Findings reviewed: 15
Approved: 10
Skipped: 3
Skip-type: 2 (redundant type annotations)
Lines removed: 34
Modified files:
src/services/auth.ts (-8 lines)
src/handlers/order.ts (-12 lines)
src/utils/format.ts (-6 lines)
src/models/user.ts (-4 lines)
src/config/database.ts (-4 lines)Language-Agnostic Approach
The patterns apply across languages. When scanning:
- Adapt comment syntax detection to the file's language (// vs # vs / / vs --)
- Adapt type annotation detection to the language's type system
- Adapt docstring detection to language conventions (JSDoc, Python docstrings, Go doc comments, Javadoc)
- Don't flag patterns that are idiomatic in a specific language (e.g., Go error handling is verbose by design, not slop)
Slop Patterns
The 10 AI-generated code patterns to detect and remove. Language-agnostic.
1. Unnecessary Comments Explaining Obvious Code
Comments that restate what the code already says.
Bad:
# Increment the counter
counter += 1
# Return the result
return resultGood:
counter += 1
return resultWhy it's slop: The code is self-documenting. The comment adds zero information and doubles the visual noise.
2. Over-Engineered Error Handling for Impossible Cases
Try/catch or error handling around operations that cannot fail in context, or catching errors that are already handled upstream.
Bad:
function add(a: number, b: number): number {
try {
if (typeof a !== "number" || typeof b !== "number") {
throw new TypeError("Arguments must be numbers");
}
const result = a + b;
if (!Number.isFinite(result)) {
throw new RangeError("Result is not finite");
}
return result;
} catch (error) {
console.error("Error in add function:", error);
throw error;
}
}Good:
function add(a: number, b: number): number {
return a + b;
}Why it's slop: TypeScript already enforces the types. Internal pure functions don't need try/catch. The validation guards against scenarios the type system prevents.
3. Verbose Docstrings on Simple Functions
Multi-line doc comments on functions whose name and signature already explain everything.
Bad:
def get_user_by_id(user_id: int) -> User:
"""
Get a user by their ID.
This function retrieves a user from the database using
their unique identifier.
Args:
user_id: The unique identifier of the user to retrieve.
Returns:
User: The user object corresponding to the given ID.
Raises:
UserNotFoundError: If no user with the given ID exists.
"""
return self.db.users.get(user_id)Good:
def get_user_by_id(user_id: int) -> User:
"""Raises UserNotFoundError if not found."""
return self.db.users.get(user_id)Why it's slop: The function name says "get user by id". The type hints say it takes an int and returns a User. The only non-obvious info is the exception behavior.
4. "Just in Case" Abstractions
Premature helpers, utilities, or wrapper functions used exactly once. Created for hypothetical reuse that never happens.
Bad:
// utils/stringHelpers.js
export function formatUserName(first, last) {
return `${first} ${last}`;
}
// component.js
import { formatUserName } from "./utils/stringHelpers";
const name = formatUserName(user.first, user.last);Good:
// component.js
const name = `${user.first} ${user.last}`;Why it's slop: A one-liner used once doesn't need its own function. The abstraction adds indirection without value.
5. Redundant Type Annotations That Add No Clarity
Type annotations where the type is already obvious from the value or context.
Bad:
const name: string = "Alice";
const count: number = 0;
const items: string[] = ["a", "b", "c"];
const isReady: boolean = false;Good:
const name = "Alice";
const count = 0;
const items = ["a", "b", "c"];
const isReady = false;Why it's slop: Type inference handles these. The annotations are visual noise that repeat what the literal values already tell you.
6. "Removed" or "Previously" Comments
Comments marking where code used to be, instead of just deleting it.
Bad:
# Previously handled authentication here
# Removed: old_auth_check()
class UserService:
# removed legacy validation
passGood:
class UserService:
passWhy it's slop: Git history tracks what was removed. These comments are dead weight that accumulates over time.
7. Backwards-Compatibility Shims for Unused Code
Re-exports, aliases, or compatibility layers for code that nothing uses anymore.
Bad:
// Keep old name for backwards compatibility
export const fetchUserData = getUserById;
// Legacy alias
export type UserRecord = User;
// Renamed but keeping old export
const _unusedOldHelper = newHelper;Good:
// (just delete them — nothing uses the old names)Why it's slop: If nothing imports the old name, the shim is dead code. If something does, rename it at the call site.
8. Excessive Internal Validation
Validating inputs from trusted internal sources where the contract is already guaranteed by the caller or type system.
Bad:
func (s *Service) processOrder(order Order) error {
if order.ID == "" {
return fmt.Errorf("order ID cannot be empty")
}
if order.Items == nil {
return fmt.Errorf("order items cannot be nil")
}
if len(order.Items) == 0 {
return fmt.Errorf("order must have at least one item")
}
// ... actual logic
}Good:
func (s *Service) processOrder(order Order) error {
// order is validated at API boundary in handleCreateOrder
// ... actual logic
}Why it's slop: Internal functions called from code you control don't need to re-validate what the caller already guarantees. Validate at system boundaries (user input, external APIs), not between your own functions.
9. Unnecessary Emoji in Code Comments
Emoji used as decoration in code comments rather than conveying meaning.
Bad:
# 🚀 Initialize the application
app = Flask(__name__)
# ✨ Create the database connection
db = Database(config.db_url)
# 🔥 Start processing
process_queue()Good:
app = Flask(__name__)
db = Database(config.db_url)
process_queue()Why it's slop: Emoji in code comments are visual noise. They don't convey technical information and make code harder to grep.
10. Filler Summary Comments at End of Functions or Files
Comments that summarize what the function/block just did, restating the code above.
Bad:
function processUsers(users) {
const active = users.filter((u) => u.active);
const sorted = active.sort((a, b) => a.name.localeCompare(b.name));
const mapped = sorted.map((u) => ({ id: u.id, name: u.name }));
return mapped;
// End of processUsers - filters active users, sorts by name, and maps to simplified objects
}Good:
function processUsers(users) {
const active = users.filter((u) => u.active);
const sorted = active.sort((a, b) => a.name.localeCompare(b.name));
return sorted.map((u) => ({ id: u.id, name: u.name }));
}Why it's slop: The code is right there. A trailing summary adds nothing except maintenance burden when the logic changes.
Detection Priority
When scanning, check patterns in this order (highest signal first):
1. Unnecessary comments (most common, easiest to spot) 2. "Removed"/"previously" comments (pure noise) 3. Filler summary comments (pure noise) 4. Emoji in comments (pure noise) 5. Verbose docstrings (common, usually safe to trim) 6. Redundant type annotations (common, language-dependent) 7. Over-engineered error handling (needs context) 8. Excessive internal validation (needs context) 9. Backwards-compatibility shims (needs usage check) 10. "Just in case" abstractions (needs usage check)