ai-slop-cleaner
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAI Slop Cleaner
AI Slop Cleaner
AI code generation produces working code. It also produces unnecessary code alongside it. This skill removes the unnecessary parts while keeping everything that matters.
AI代码生成会产出可运行的代码,但同时也会附带不必要的代码。本工具会移除这些不必要的部分,同时保留所有关键功能。
What Is "AI Slop"?
什么是「AI Slop」?
AI slop is code that:
- Works, but shouldn't exist
- Adds complexity without adding value
- Was clearly generated to pad a response rather than solve a problem
- Suggests the author wasn't thinking, just generating
Common slop categories and their signals:
| Category | Signal |
|---|---|
| Dead imports | Imported but never referenced in the file |
| Unused variables | Declared, never read |
| Commented-out code | Blocks of |
| Debug remnants | |
| Obvious comments | |
| Redundant JSDoc | |
| Premature abstractions | A factory that creates exactly one thing |
| One-use helpers | Private function called exactly once, trivially inlinable |
| Overly generic types | |
| Over-parameterized | |
| Unreachable branches | |
| Speculative features | Code paths for requirements that don't exist |
| Copy-paste duplication | Two blocks identical except one variable name |
| Placeholder remnants | |
AI Slop指的是这类代码:
- 可以运行,但本不该存在
- 增加复杂度却没有任何价值
- 明显是为了凑字数而非解决问题生成的
- 表明作者没有思考,只是单纯生成代码
常见冗余代码类别及特征:
| 类别 | 特征 |
|---|---|
| 无用导入 | 已导入但在文件中从未被引用 |
| 未使用变量 | 已声明但从未被读取 |
| 注释掉的代码 | 如 |
| 调试残留 | |
| 冗余注释 | |
| 冗余JSDoc | |
| 过早抽象 | 只创建一个实例的工厂类 |
| 单次使用辅助函数 | 仅被调用一次、可轻松内联的私有函数 |
| 过度泛型类型 | 当 |
| 参数过多 | |
| 不可达分支 | |
| 投机性功能 | 针对不存在的需求编写的代码路径 |
| 复制粘贴重复代码 | 除了一个变量名外完全相同的两个代码块 |
| 占位符残留 | 生产环境中的 |
The Prime Directive
首要原则
Tests are sacred. Never clean test files.
Tests exist to protect behavior. Any cleanup that breaks a test reveals that the "slop" was actually load-bearing. That is good information. The test wins.
测试是神圣不可侵犯的。绝不要清理测试文件。
测试的存在是为了保护功能。任何导致测试失败的清理操作,都说明所谓的“冗余代码”实际上是必要的。这是很重要的信息,测试永远优先。
Regression-Safe Workflow (Non-Negotiable)
回归安全工作流(不可协商)
BEFORE ANYTHING: Run full test suite → all tests must pass (baseline)
FOR EACH PASS:
1. Identify targets for this pass category
2. Apply cleanup
3. Run tests
4. If tests pass: keep cleanup, continue
5. If tests fail: git checkout -- . (revert), skip this pass category
6. Log what was reverted and why
AFTER ALL PASSES: Run full test suite → confirm all tests still pass
Report: lines removed, files touched, passes skipped, reason for each skipNever batch multiple pass categories together. If combined changes break a test, you cannot know which change caused it.
开始前:运行完整测试套件 → 所有测试必须通过(基准线)
每一轮清理:
1. 确定本轮要处理的类别目标
2. 执行清理操作
3. 运行测试
4. 如果测试通过:保留清理结果,继续下一轮
5. 如果测试失败:执行git checkout -- .(回退),跳过本轮类别
6. 记录回退内容及原因
所有轮次完成后:运行完整测试套件 → 确认所有测试仍通过
生成报告:移除的行数、修改的文件数、跳过的轮次、每轮跳过的原因不要将多个类别的清理合并进行。如果组合修改导致测试失败,你将无法确定是哪一项修改引发的问题。
The 7 Cleaning Passes
7轮清理步骤
Pass 1: Dead Imports and Unused Variables
第一轮:无用导入与未使用变量
Risk: Very Low
What to remove:
- Import statements where the imported name never appears in the file body
- Variables declared with /
let/constthat are never read after assignmentvar - Function parameters that are never referenced inside the function body (TypeScript: prefix with )
_
Before:
typescript
import { useState, useEffect, useCallback, useMemo } from 'react'
import { formatDate } from '@/lib/utils'
import { ApiClient } from '@/lib/api'
export function UserCard({ user }) {
const [count, setCount] = useState(0)
const formatted = formatDate(user.createdAt)
return <div>{user.name}</div>
}After:
typescript
import { useState } from 'react'
import { formatDate } from '@/lib/utils'
export function UserCard({ user }) {
const [count, setCount] = useState(0)
const formatted = formatDate(user.createdAt)
return <div>{user.name}</div>
}Note: , , and are still present because they may be used elsewhere in a larger component. Pass 1 only removes imports.
countsetCountformatted风险:极低
需要移除的内容:
- 导入的名称在文件主体中从未出现过的导入语句
- 使用/
let/const声明但赋值后从未被读取的变量var - 函数体内从未被引用的函数参数(TypeScript:可添加前缀标记)
_
之前的代码:
typescript
import { useState, useEffect, useCallback, useMemo } from 'react'
import { formatDate } from '@/lib/utils'
import { ApiClient } from '@/lib/api'
export function UserCard({ user }) {
const [count, setCount] = useState(0)
const formatted = formatDate(user.createdAt)
return <div>{user.name}</div>
}之后的代码:
typescript
import { useState } from 'react'
import { formatDate } from '@/lib/utils'
export function UserCard({ user }) {
const [count, setCount] = useState(0)
const formatted = formatDate(user.createdAt)
return <div>{user.name}</div>
}注意:、和仍然保留,因为它们可能在更大的组件中的其他地方被使用。第一轮仅移除无用导入。
countsetCountformattedPass 2: Commented-Out Code and Debug Statements
第二轮:注释代码与调试语句
Risk: Very Low
What to remove:
- Any block of commented-out code that is not an active TODO or architectural note
- ,
console.log,console.debug(unless it is a legitimate error logger)console.warn - statements
debugger - in Python when not serving as actual program output
print() - in Go debug instrumentation
fmt.Println
Before:
typescript
async function processOrder(orderId: string) {
console.log('processing order', orderId)
const order = await db.orders.findById(orderId)
// const cached = await cache.get(orderId)
// if (cached) return cached
console.log('order fetched:', order)
const result = await payments.charge(order)
// TODO: add retry logic here
// console.log('charge result', result)
return result
}After:
typescript
async function processOrder(orderId: string) {
const order = await db.orders.findById(orderId)
const result = await payments.charge(order)
// TODO: add retry logic here
return result
}Rule: comments are preserved. They are documentation of known gaps, not slop.
// TODO:风险:极低
需要移除的内容:
- 任何非活跃TODO或架构说明的注释代码块
- 、
console.log、console.debug(合法错误日志除外)console.warn - 语句
debugger - Python中不作为实际程序输出的
print() - Go调试工具中的
fmt.Println
之前的代码:
typescript
async function processOrder(orderId: string) {
console.log('processing order', orderId)
const order = await db.orders.findById(orderId)
// const cached = await cache.get(orderId)
// if (cached) return cached
console.log('order fetched:', order)
const result = await payments.charge(order)
// TODO: add retry logic here
// console.log('charge result', result)
return result
}之后的代码:
typescript
async function processOrder(orderId: string) {
const order = await db.orders.findById(orderId)
const result = await payments.charge(order)
// TODO: add retry logic here
return result
}规则:注释会被保留。它们是已知缺口的文档,不属于冗余代码。
// TODO:Pass 3: Obvious Comments and Redundant Documentation
第三轮:冗余注释与多余文档
Risk: Low
What to remove:
- Comments that restate the code in plain English without adding context
- JSDoc blocks that just repeat the parameter name and type (TypeScript already says this)
@param - Section dividers that add no structure ()
// ===== COMPONENT ===== - End-of-block comments (,
} // end if)} // end for
Before:
typescript
/**
* Gets a user by ID.
* @param id - the user ID
* @param db - the database instance
* @returns the user object
*/
async function getUserById(id: string, db: Database): Promise<User> {
// Query the database for the user
const user = await db.users.findById(id)
// Return the user
return user
} // end getUserByIdAfter:
typescript
async function getUserById(id: string, db: Database): Promise<User> {
return db.users.findById(id)
}Keep comments that explain WHY (business rules, performance choices, known gotchas). Remove comments that explain WHAT (the code already says what).
风险:低
需要移除的内容:
- 用直白语言重述代码但未添加上下文的注释
- 仅重复参数名称和类型的JSDoc 块(TypeScript已明确标注)
@param - 未添加结构的分隔符(如)
// ===== COMPONENT ===== - 块结束注释(如、
} // end if)} // end for
之前的代码:
typescript
/**
* Gets a user by ID.
* @param id - the user ID
* @param db - the database instance
* @returns the user object
*/
async function getUserById(id: string, db: Database): Promise<User> {
// Query the database for the user
const user = await db.users.findById(id)
// Return the user
return user
} // end getUserById之后的代码:
typescript
async function getUserById(id: string, db: Database): Promise<User> {
return db.users.findById(id)
}保留解释“为什么”的注释(如业务规则、性能选择、已知陷阱)。移除解释“是什么”的注释(代码本身已经说明)。
Pass 4: Dead Code (Unreachable Branches)
第四轮:无用代码(不可达分支)
Risk: Medium — Run tests immediately after
What to remove:
- Conditions that are always true or always false
- Code after unconditional ,
return, orthrowbreak - Else branches of conditions that always throw in the if block
Before:
typescript
function getStatus(user: User): string {
if (user.role === 'admin' || user.role === 'admin') {
return 'ADMIN'
}
if (user.isActive) {
return 'ACTIVE'
} else {
return 'INACTIVE'
}
// This never runs
return 'UNKNOWN'
}After:
typescript
function getStatus(user: User): string {
if (user.role === 'admin') {
return 'ADMIN'
}
return user.isActive ? 'ACTIVE' : 'INACTIVE'
}Do not remove branches that look unreachable but depend on runtime data you cannot verify statically. When uncertain, leave it.
风险:中等 — 清理后立即运行测试
需要移除的内容:
- 始终为真或始终为假的条件
- 无条件、
return或throw后的代码break - if块中始终抛出错误的else分支
之前的代码:
typescript
function getStatus(user: User): string {
if (user.role === 'admin' || user.role === 'admin') {
return 'ADMIN'
}
if (user.isActive) {
return 'ACTIVE'
} else {
return 'INACTIVE'
}
// This never runs
return 'UNKNOWN'
}之后的代码:
typescript
function getStatus(user: User): string {
if (user.role === 'admin') {
return 'ADMIN'
}
return user.isActive ? 'ACTIVE' : 'INACTIVE'
}不要移除那些看似不可达但依赖你无法静态验证的运行时数据的分支。不确定时,保留该代码。
Pass 5: Premature Abstractions (Inline One-Use Helpers)
第五轮:过早抽象(内联单次使用辅助函数)
Risk: Medium — Run tests immediately after
What to inline:
- Private/internal functions called exactly once
- Wrapper functions that add no logic (just forward all arguments)
- Intermediate variables assigned once and used once on the next line
Before:
typescript
function formatUserDisplayName(user: User): string {
return `${user.firstName} ${user.lastName}`.trim()
}
function renderUserCard(user: User) {
const displayName = formatUserDisplayName(user)
return `<div class="card">${displayName}</div>`
}After (if is only called from ):
formatUserDisplayNamerenderUserCardtypescript
function renderUserCard(user: User) {
const displayName = `${user.firstName} ${user.lastName}`.trim()
return `<div class="card">${displayName}</div>`
}Do NOT inline if:
- The function is exported (public API)
- The function is called from more than one place
- The function name serves as meaningful documentation of intent
- The function contains error handling that would add visual noise when inlined
风险:中等 — 清理后立即运行测试
需要内联的内容:
- 仅被调用一次的私有/内部函数
- 未添加任何逻辑的包装函数(仅转发所有参数)
- 赋值一次且仅在下一行使用的中间变量
之前的代码:
typescript
function formatUserDisplayName(user: User): string {
return `${user.firstName} ${user.lastName}`.trim()
}
function renderUserCard(user: User) {
const displayName = formatUserDisplayName(user)
return `<div class="card">${displayName}</div>`
}之后的代码(如果仅被调用):
formatUserDisplayNamerenderUserCardtypescript
function renderUserCard(user: User) {
const displayName = `${user.firstName} ${user.lastName}`.trim()
return `<div class="card">${displayName}</div>`
}以下情况请勿内联:
- 函数是导出的(公共API)
- 函数被多个地方调用
- 函数名称是对意图的有意义文档
- 函数包含内联后会增加视觉干扰的错误处理
Pass 6: Duplication Consolidation
第六轮:重复代码合并
Risk: Medium-High — Run tests immediately after each consolidation
What to consolidate:
- Two or more blocks with identical structure and only one variable difference
- Repeated conditional checks that could be extracted to a guard function
- Multiple switch/if-else blocks with the same cases in different files
Before:
typescript
// In UserService
async function getActiveUsers() {
const users = await db.query(
'SELECT * FROM users WHERE status = $1 AND deleted_at IS NULL',
['active']
)
return users.rows
}
// In AdminService (same file or different file)
async function getActiveAdmins() {
const admins = await db.query(
'SELECT * FROM users WHERE status = $1 AND deleted_at IS NULL AND role = $2',
['active', 'admin']
)
return admins.rows
}After:
typescript
async function getActiveUsers(role?: string) {
const params: unknown[] = ['active']
let sql = 'SELECT * FROM users WHERE status = $1 AND deleted_at IS NULL'
if (role) {
sql += ' AND role = $2'
params.push(role)
}
const result = await db.query(sql, params)
return result.rows
}Be careful: consolidation that requires complex parameterization may make code harder to understand. If the consolidated version is more complex than the two originals, leave them separate.
风险:中高 — 每次合并后立即运行测试
需要合并的内容:
- 两个或多个结构相同仅一个变量不同的代码块
- 可提取为守卫函数的重复条件检查
- 不同文件中具有相同分支的多个switch/if-else块
之前的代码:
typescript
// In UserService
async function getActiveUsers() {
const users = await db.query(
'SELECT * FROM users WHERE status = $1 AND deleted_at IS NULL',
['active']
)
return users.rows
}
// In AdminService (same file or different file)
async function getActiveAdmins() {
const admins = await db.query(
'SELECT * FROM users WHERE status = $1 AND deleted_at IS NULL AND role = $2',
['active', 'admin']
)
return admins.rows
}之后的代码:
typescript
async function getActiveUsers(role?: string) {
const params: unknown[] = ['active']
let sql = 'SELECT * FROM users WHERE status = $1 AND deleted_at IS NULL'
if (role) {
sql += ' AND role = $2'
params.push(role)
}
const result = await db.query(sql, params)
return result.rows
}注意:需要复杂参数化的合并可能会让代码更难理解。如果合并后的版本比两个原始版本更复杂,保留它们的独立状态。
Pass 7: Over-Engineering Simplification
第七轮:过度工程简化
Risk: High — High scrutiny, run tests after every individual change
What to simplify:
- Factory pattern used to create exactly one concrete type
- Strategy pattern with exactly one strategy
- Abstract base class with exactly one implementation
- Generic type parameter constrained so tightly it could be a concrete type
Before:
typescript
interface DataProcessor<T extends BaseData> {
process(data: T): ProcessedData<T>
validate(data: T): ValidationResult
}
class UserDataProcessorFactory {
create(): DataProcessor<UserData> {
return new UserDataProcessor()
}
}
class UserDataProcessor implements DataProcessor<UserData> {
process(data: UserData): ProcessedData<UserData> {
return { ...data, processed: true }
}
validate(data: UserData): ValidationResult {
return { valid: !!data.id }
}
}After (if only UserData ever flows through this):
typescript
function processUserData(data: UserData) {
if (!data.id) throw new Error('Invalid user data: missing id')
return { ...data, processed: true }
}Rule for Pass 7: If you need more than 2 minutes to understand why an abstraction exists, and there is only one concrete case, remove the abstraction. If you find yourself unsure whether it is load-bearing, leave it. Pass 7 is optional.
风险:高 — 严格审查,每次单独修改后运行测试
需要简化的内容:
- 用于创建唯一具体类型的工厂模式
- 仅有一种策略的策略模式
- 仅有一种实现的抽象基类
- 约束过紧可替换为具体类型的泛型参数
之前的代码:
typescript
interface DataProcessor<T extends BaseData> {
process(data: T): ProcessedData<T>
validate(data: T): ValidationResult
}
class UserDataProcessorFactory {
create(): DataProcessor<UserData> {
return new UserDataProcessor()
}
}
class UserDataProcessor implements DataProcessor<UserData> {
process(data: UserData): ProcessedData<UserData> {
return { ...data, processed: true }
}
validate(data: UserData): ValidationResult {
return { valid: !!data.id }
}
}之后的代码(如果仅有UserData会流经此处):
typescript
function processUserData(data: UserData) {
if (!data.id) throw new Error('Invalid user data: missing id')
return { ...data, processed: true }
}第七轮规则:如果你需要超过2分钟才能理解某个抽象存在的原因,且仅有一个具体案例,移除该抽象。如果你不确定它是否是必要的,保留它。第七轮为可选步骤。
What Is Never Cleaned
绝不清理的内容
| Target | Reason |
|---|---|
Test files ( | Tests are sacred |
| Public API signatures | Breaks callers |
| Error handling at system boundaries (API routes, top-level handlers) | Defense-in-depth |
| Comments explaining regulatory/compliance requirements | Legal context |
| Feature flags | May be toggled at runtime |
Anything marked | Explicit author decision |
| 目标 | 原因 |
|---|---|
测试文件( | 测试是神圣的 |
| 公共API签名 | 会破坏调用方 |
| 系统边界处的错误处理(API路由、顶级处理器) | 深度防御需求 |
| 解释监管/合规要求的注释 | 法律上下文需求 |
| 功能开关 | 可能在运行时切换 |
标记为 | 作者明确的决策 |
.slopignore File
.slopignore 文件
Place at project root to exclude paths:
undefined放置在项目根目录以排除指定路径:
undefined.slopignore
.slopignore
src/legacy/ # Old code being migrated, don't touch
src/generated/ # Auto-generated, cleaned by generator
vendor/ # Third-party code
undefinedsrc/legacy/ # 正在迁移的旧代码,请勿触碰
src/generated/ # 自动生成的代码,由生成器负责清理
vendor/ # 第三方代码
undefinedMetrics Report
指标报告
After all passes complete, output:
AI Slop Cleaner Report
======================
Files touched: 12
Lines removed: 147
Lines remaining: 1,843
Reduction: 7.4%
Pass results:
Pass 1 (Dead imports): DONE — 23 lines removed
Pass 2 (Debug code): DONE — 18 lines removed
Pass 3 (Obvious comments): DONE — 41 lines removed
Pass 4 (Dead code): DONE — 12 lines removed
Pass 5 (One-use helpers): DONE — 31 lines removed
Pass 6 (Duplication): SKIPPED — test failed after consolidation (UserService)
Pass 7 (Over-engineering): DONE — 22 lines removed
Skipped details:
Pass 6 reverted: UserService query consolidation broke getUsersByStatus test.
Root cause: test was asserting on the exact SQL string. Left original.
Test status: ALL PASSING (127/127)所有轮次完成后,输出如下报告:
AI Slop Cleaner Report
======================
Files touched: 12
Lines removed: 147
Lines remaining: 1,843
Reduction: 7.4%
Pass results:
Pass 1 (Dead imports): DONE — 23 lines removed
Pass 2 (Debug code): DONE — 18 lines removed
Pass 3 (Obvious comments): DONE — 41 lines removed
Pass 4 (Dead code): DONE — 12 lines removed
Pass 5 (One-use helpers): DONE — 31 lines removed
Pass 6 (Duplication): SKIPPED — test failed after consolidation (UserService)
Pass 7 (Over-engineering): DONE — 22 lines removed
Skipped details:
Pass 6 reverted: UserService query consolidation broke getUsersByStatus test.
Root cause: test was asserting on the exact SQL string. Left original.
Test status: ALL PASSING (127/127)Integration with refactor-cleaner Agent
与refactor-cleaner Agent的集成
AI slop cleaner runs at the code level (syntactic cleanup). The refactor-cleaner agent runs at the architecture level (structural refactoring). Run this skill first, then refactor-cleaner if structural improvement is needed.
Order:
1. ai-slop-cleaner (remove the noise)
2. code-reviewer (verify quality after cleanup)
3. refactor-cleaner (structural improvements if needed)
4. verifier (final gate)AI Slop Cleaner在代码层面运行(语法清理)。refactor-cleaner Agent在架构层面运行(结构重构)。先运行本工具,若需要结构改进再运行refactor-cleaner。
顺序:
1. ai-slop-cleaner(移除冗余代码)
2. code-reviewer(验证清理后的代码质量)
3. refactor-cleaner(如需结构改进)
4. verifier(最终验证)Automatic Trigger
自动触发
This skill is automatically triggered after:
- kraken agent completes a feature implementation
- spark agent completes a fix
- Any agent produces more than 200 new lines of code
The trigger runs Pass 1 and Pass 2 only by default (very low risk). Passes 3-7 require explicit activation or a command.
/cleanRemember: The goal is not minimum lines of code. The goal is maximum clarity per line. If removing something makes the code harder to understand, put it back.
本工具会在以下场景自动触发:
- kraken Agent完成功能实现后
- spark Agent完成修复后
- 任何Agent生成超过200行新代码后
默认仅自动运行第一轮和第二轮(风险极低)。第三至第七轮需要显式激活或使用命令。
/clean提醒:目标并非最小化代码行数,而是最大化每行代码的清晰度。如果移除某部分内容会让代码更难理解,请恢复它。