claude/skills/cleanup/SKILL.md
This skill should be used when the user asks to "clean up the code", "remove unnecessary comments", "simplify docstrings", "parameterize tests", or wants to review and clean up code.
npx skillsauth add tbroadley/dotfiles cleanupInstall 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.
Review and clean up code, removing unwanted patterns and improving test structure.
By default, only clean up code that was changed on the current branch (i.e., changes not yet on main). Use git diff main...HEAD to identify which files and lines were modified.
Do NOT clean up anti-patterns in code that was already on main unless the user explicitly requests a broader cleanup scope.
Before applying the hardcoded patterns below, also check the changed code against rules from:
CLAUDE.md (if it exists) for project-specific style rules, conventions, and patterns~/.claude/CLAUDE.md (if it exists) for global coding style rulesScan the changed code for violations of any rules in these files. Common things to catch:
.get() in assertions, mocking internals)CLAUDE.md rules take equal priority to the hardcoded patterns below — violations of CLAUDE.md rules are just as important to fix.
Remove explanatory comments that state the obvious or describe what code does line-by-line. Remove comments that:
Keep comments that:
Example - Before:
# Get the user from the database
user = db.get_user(user_id)
# Check if user exists
if user is None:
# Raise an error if user not found
raise UserNotFoundError(user_id)
# Return the user's email address
return user.email
Example - After:
user = db.get_user(user_id)
if user is None:
raise UserNotFoundError(user_id)
return user.email
Remove verbose docstrings that repeat parameter names and types already visible in type annotations, or describe obvious behavior. Clean up docstrings by:
Example - Before:
def get_user_email(user_id: int) -> str:
"""
Get the email address for a user.
This function retrieves the email address associated with the given user ID
from the database.
Args:
user_id: The unique identifier of the user whose email should be retrieved.
Returns:
The email address of the user as a string.
Raises:
UserNotFoundError: If no user exists with the given ID.
"""
user = db.get_user(user_id)
if user is None:
raise UserNotFoundError(user_id)
return user.email
Example - After:
def get_user_email(user_id: int) -> str:
"""Raises UserNotFoundError if user doesn't exist."""
user = db.get_user(user_id)
if user is None:
raise UserNotFoundError(user_id)
return user.email
Or if the function name and signature are completely self-explanatory:
def get_user_email(user_id: int) -> str:
user = db.get_user(user_id)
if user is None:
raise UserNotFoundError(user_id)
return user.email
Consolidate separate test functions that should be parameterized. Look for:
Consolidate using @pytest.mark.parametrize:
Example - Before:
def test_validate_email_valid():
assert validate_email("[email protected]") is True
def test_validate_email_valid_with_subdomain():
assert validate_email("[email protected]") is True
def test_validate_email_invalid_no_at():
assert validate_email("userexample.com") is False
def test_validate_email_invalid_no_domain():
assert validate_email("user@") is False
def test_validate_email_invalid_empty():
assert validate_email("") is False
Example - After:
@pytest.mark.parametrize(
("email", "expected"),
[
("[email protected]", True),
("[email protected]", True),
("userexample.com", False),
("user@", False),
("", False),
],
)
def test_validate_email(email: str, expected: bool):
assert validate_email(email) is expected
When NOT to parameterize:
HIGHEST PRIORITY: Remove unnecessary defensive programming that hides bugs instead of failing loudly.
.get() CallsReplace .get() with default values on internal data structures with direct access. Let KeyError propagate.
Before:
user_id = data.get("user_id", None)
if user_id is None:
return
After:
user_id = data["user_id"] # Let KeyError propagate if missing
Remove try-except blocks that catch exceptions without specific handling logic.
Before:
try:
result = parse_data(input)
except Exception as e:
logger.warning(f"Parse failed: {e}")
result = None
After:
result = parse_data(input) # Let exceptions propagate
Remove None checks on fields that should always exist in internal data structures.
Before:
if score.metadata is not None and "error" in score.metadata:
error = score.metadata.get("error", "unknown")
After:
if "error" in score.metadata:
error = score.metadata["error"]
Remove validation that checks internal invariants. Trust internal code.
Before:
def process_user(user: User) -> str:
if not isinstance(user, User):
raise TypeError("Expected User instance")
if user.email is None:
raise ValueError("User email is required")
return user.email
After:
def process_user(user: User) -> str:
return user.email
Replace type: ignore comments with proper type narrowing.
Before:
result = some_function() # type: ignore
After (Option 1 - Assert isinstance):
result = some_function()
assert isinstance(result, ExpectedType)
After (Option 2 - Assert not None):
result = some_optional_function()
assert result is not None
Keep type: ignore only for legitimate library limitations:
# pandas groupby has incomplete type stubs
grouped = df.groupby("column") # pyright: ignore[reportUnknownMemberType]
Make code fail early and loudly instead of continuing with invalid state.
Before:
try:
data = json.loads(raw_data)
except json.JSONDecodeError:
logger.warning("Invalid JSON, using empty dict")
data = {}
After:
data = json.loads(raw_data) # Let JSONDecodeError propagate
Add newlines after raise statements:
# Before
if value < 0:
raise ValueError("Value must be positive")
return value * 2
# After
if value < 0:
raise ValueError("Value must be positive")
return value * 2
Import modules, not individual items:
# Before
from mypackage.module import FunctionA, FunctionB, ClassC
# After
from mypackage import module
# Use as: module.FunctionA(), module.ClassC()
Move imports to top level:
# Before
def some_function():
import expensive_module
return expensive_module.do_work()
# After
import expensive_module
def some_function():
return expensive_module.do_work()
Exception: TYPE_CHECKING guard for type-only imports:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from mypackage import SomeType
Beyond parameterization, also look for:
Using real instances instead of MagicMock:
# Before
mock_target = MagicMock(spec=Target)
mock_target.name = "test"
# After
target = Target(name="test") # Use real instance of simple class
Direct assertions instead of defensive ones:
# Before (defensive)
result = some_function()
assert result.get("value") == expected
# After (direct)
result = some_function()
assert result["value"] == expected # Let KeyError fail the test
Mock only at boundaries:
# Mock external APIs, not internal code
mocker.patch("requests.get") # Good - external boundary
mocker.patch("myapp.internal_helper") # Bad - internal code
CLAUDE.md and ~/.claude/CLAUDE.md (if they exist) to understand all applicable style rules and conventionsgit diff main...HEAD --name-only to find files changed on this branch, then focus cleanup on only the changed portions of those files (not pre-existing code)tools
Add words to the Wispr Flow dictionary. Use when the user wants to add a word, phrase, or snippet to Wispr Flow for voice dictation.
documentation
Upload images to a GitHub PR description or comment using a shared gist as image hosting. Use when the user wants to add plots, screenshots, or other images to a PR.
testing
Manage tasks, projects, and productivity in Todoist. View tasks, add new items, check completed work, and organize projects.
data-ai
Use when working with stacked diffs (branch B based on branch A, which is based on main).