From holistic-linting
Provides workflows for sub-agents to resolve Python linting errors from ruff, mypy, pyright, and basedpyright via root-cause analysis, suppression gates, and verification steps.
npx claudepluginhub jamie-bitflight/claude_skills --plugin holistic-lintingThis skill uses the workspace's default tool permissions.
This skill provides systematic resolution procedures for Python linting tools. Sub-agents executing linting resolution tasks MUST follow the appropriate workflow based on the linter reporting issues.
Automates format-lint-resolve pipelines for code editing tasks. Discovers linters from pyproject.toml/.pre-commit-config.yaml/package.json, fixes ruff/mypy/bandit issues, ensures quality before completion.
Lints Python code with ruff: fast checks, rule selection, auto-fixing, output formats, configuration. Use for code quality, bug detection, standards enforcement.
Improves Python code quality with static analysis (ruff/mypy), Any type elimination, modernization plans (Protocols/Generics/Pydantic), plan review, and test-driven refactoring.
Share bugs, ideas, or general feedback.
This skill provides systematic resolution procedures for Python linting tools. Sub-agents executing linting resolution tasks MUST follow the appropriate workflow based on the linter reporting issues.
Use this skill when you are a sub-agent assigned to resolve linting issues in a specific file. This skill provides detailed workflows for:
Do NOT use this skill if you are an orchestrator. Orchestrators should use the holistic-linting-orchestrator skill for delegation workflows.
All linter-specific workflows share these common steps. Apply them in order before the linter-specific procedures.
Before implementing any fixes:
Skill(skill: "python3-development:python3-development")
Motivation: Ensures fixes follow Python 3.11+ standards, modern typing patterns, and project conventions.
Before implementing any fix, verify it is a code change — not suppression. Each category below is an immediate STOP:
Inline suppression comments:
# noqa, # type: ignore, # pyright: ignore, # pylint: disable, or any suppression commentConfiguration-level suppression (equally forbidden):
[tool.ruff.lint] ignore = [...] in pyproject.toml[tool.ruff.lint.per-file-ignores][tool.pyright] reportX = "warning" or any other severity downgradedisable_error_code = [...] to [tool.mypy]pyproject.toml, ruff.toml, mypy.ini, .flake8, setup.cfg) to reduce the scope, severity, or applicability of a ruleReason: A pyproject.toml severity downgrade achieves the same silencing effect as # type: ignore but at project scope, affecting all future code. Both are standards degradation. Neither is a code fix.
Deletion-as-resolution (equally forbidden):
If any proposed fix falls into these categories: STOP.
When no code restructuring works (minimum 2 approaches attempted), document the constraint and return UNRESOLVED:
sys.platform branches")Return this as an UNRESOLVED item in your resolution report. The orchestrator will surface it to the user for a human decision on whether to suppress, reconfigure, or accept the limitation.
Examine how this code fits into the broader system:
Use Grep to find usage patterns:
uv run rg "function_name" --type py
After implementing fixes, rerun the appropriate linter on the primary file:
# For Ruff:
uv run ruff check /path/to/file.py
# For Mypy:
uv run mypy /path/to/file.py
# For Pyright/Basedpyright:
uv run pyright /path/to/file.py
# or
uv run basedpyright /path/to/file.py
Verify incidentally modified files: If you touched any file other than the primary target during the fix (e.g., added an import to a utility module, moved a function, updated a type alias), run the linter on those files too:
uv run ruff check /path/to/incidentally/modified/file.py
uv run mypy /path/to/incidentally/modified/file.py
All incidentally modified files must also produce zero errors before resolution is complete.
Record the before and after issue counts in the resolution report header:
**Issues before resolution:** N (from initial linter run)
**Issues after resolution:** 0 (from final linter run — must be 0 for all touched files)
**UNRESOLVED items:** N (must be explicitly listed even if 0)
Pre-existing issues detected: If the initial linter run reveals issues in files you did not touch — see Pre-Existing Issues Protocol. Every detected issue gets recorded. Silence is not permitted.
When to use: Linting errors with ruff rule codes (E, F, W, B, S, I, UP, C90, N, etc.)
Resolution Process:
Research the Rule
Use ruff's built-in documentation system:
ruff rule {RULE_CODE}
Examples:
ruff rule F401 # unused-import
ruff rule E501 # line-too-long
ruff rule B006 # mutable-default-argument
This command provides:
Read Rule Documentation Output
The ruff rule output contains critical information:
Motivation: Understanding the principle prevents similar issues in other locations.
Read the Affected Code
Read the complete file containing the linting error:
Read("/path/to/file.py")
Focus on:
Apply Common Methodology
Follow steps 1-4 in the Common Resolution Methodology section above:
Implement Elegant Fix
Apply the fix following these principles:
When to use: Type checking errors with mypy error codes (attr-defined, arg-type, return-value, etc.)
Resolution Process:
Research the Error Code
Mypy errors contain error codes in brackets like [attr-defined] or [arg-type].
Look up the error code in locally-cached documentation:
Read("./references/mypy-docs/error_code_list.rst")
Read("./references/mypy-docs/error_code_list2.rst")
Search for the error code:
grep -n "error-code-{CODE}" ./references/mypy-docs/*.rst
Motivation: Mypy error codes map to specific type safety principles. Understanding the principle prevents misunderstanding type relationships.
Read Error Code Documentation
The mypy documentation explains:
Key insight: Mypy errors often indicate misunderstanding about what types a function accepts or returns.
Trace Type Flow
Follow the data flow to understand type relationships:
a. Read the error location:
Read("/path/to/file.py")
b. Identify the type mismatch:
c. Trace upstream:
d. Check library type stubs:
python -c "import library; print(library.__file__)" to locate.pyi stub files or py.typed markerApply Common Methodology
Follow steps 1-4 in the Common Resolution Methodology section above:
Implement Elegant Fix
Choose the appropriate fix strategy:
Strategy A: Fix the type annotation (if annotation is wrong)
# Before: Function returns dict but annotated as returning Response
def get_data() -> Response:
return {"key": "value"} # mypy error: Incompatible return value type
# After: Correct annotation to match actual return
def get_data() -> dict[str, str]:
return {"key": "value"}
Strategy B: Fix the implementation (if annotation is correct)
# Before: Function should return Response but returns dict
def get_data() -> Response:
return {"key": "value"} # mypy error: Incompatible return value type
# After: Fix implementation to return correct type
def get_data() -> Response:
return Response(data={"key": "value"})
Strategy C: Add type narrowing (if type is conditional)
# Before: Mypy can't prove value is not None
def process(value: str | None) -> str:
return value.upper() # mypy error: Item "None" has no attribute "upper"
# After: Add type guard
def process(value: str | None) -> str:
if value is None:
raise ValueError("value cannot be None")
return value.upper()
Strategy D: Use TypeGuard for complex narrowing
from typing import TypeGuard
def is_valid_response(data: dict[str, Any]) -> TypeGuard[dict[str, str]]:
return all(isinstance(v, str) for v in data.values())
def process(data: dict[str, Any]) -> dict[str, str]:
if not is_valid_response(data):
raise ValueError("Invalid data format")
return data # mypy now knows this is dict[str, str]
When to use: Type checking errors with pyright diagnostic rules (reportGeneralTypeIssues, reportOptionalMemberAccess, reportUnknownVariableType, etc.)
Resolution Process:
Research the Diagnostic Rule
Pyright errors reference diagnostic rule names like reportOptionalMemberAccess or reportGeneralTypeIssues.
Look up the rule in basedpyright documentation:
For rule settings and descriptions:
Use MCP tools for documentation lookup (in order of preference):
# Option 1 (Preferred): Use Ref MCP for high-fidelity documentation
mcp__Ref__ref_search_documentation(query="basedpyright {RULE_NAME} diagnostic rule configuration")
# Then read the URL from results:
mcp__Ref__ref_read_url(url="<exact_url_from_search_results>")
# Option 2: Use exa for code context if Ref doesn't have it
mcp__exa__get_code_context_exa(query="basedpyright {RULE_NAME} diagnostic rule examples")
# Fallback: Use WebFetch only if MCP tools don't work
WebFetch(url="https://docs.basedpyright.com/latest/configuration/config-files/",
prompt="Find documentation for diagnostic rule {RULE_NAME}")
For features and PEP support:
# Option 1 (Preferred): Use Ref MCP for high-fidelity documentation
mcp__Ref__ref_search_documentation(query="basedpyright Python typing features PEP {RULE_NAME}")
mcp__Ref__ref_read_url(url="<exact_url_from_search_results>")
# Fallback: Use WebFetch only if MCP tools don't work
WebFetch(url="https://docs.basedpyright.com/latest/getting_started/features/",
prompt="Explain what Python typing features and PEPs are covered related to {RULE_NAME}")
Motivation: Pyright is more strict than mypy in many areas. Understanding what the rule enforces helps identify whether the issue is a genuine type safety problem or overly strict checking.
Read Diagnostic Rule Documentation
The basedpyright documentation explains:
Read the Affected Code
Read the complete file containing the type error:
Read("/path/to/file.py")
Focus on:
Understand the Type Inference Issue
Pyright has sophisticated type inference. Common issues:
Optional member access:
# Error: reportOptionalMemberAccess
value: str | None = get_value()
result = value.upper() # Error: 'value' could be 'None'
Unknown variable type:
# Error: reportUnknownVariableType
result = some_function() # some_function has no return type annotation
Type narrowing not recognized:
# Error: pyright doesn't recognize the narrowing
value: int | str = get_value()
if type(value) == int: # Use isinstance() instead
result = value + 1
Apply Common Methodology
Follow steps 1-4 in the Common Resolution Methodology section above:
Implement Elegant Fix
Choose the appropriate fix strategy:
Strategy A: Add type narrowing guards
# Before:
def process(value: str | None) -> str:
return value.upper() # reportOptionalMemberAccess
# After:
def process(value: str | None) -> str:
if value is None:
raise ValueError("value is required")
return value.upper() # pyright knows value is str here
Strategy B: Add missing type annotations
# Before:
def fetch_data(): # reportUnknownVariableType on callers
return {"key": "value"}
# After:
def fetch_data() -> dict[str, str]:
return {"key": "value"}
Strategy C: Use assert for type narrowing
# Before:
value: int | str = get_value()
result = value + 1 # reportGeneralTypeIssues
# After:
value: int | str = get_value()
assert isinstance(value, int), "Expected int"
result = value + 1 # pyright knows value is int
Strategy D: Use typing.cast for complex cases
from typing import cast
# Before:
data: dict[str, Any] = get_data()
name: str = data["name"] # reportUnknownVariableType
# After (if you've validated data structure):
from typing import TypedDict
class UserData(TypedDict):
name: str
age: int
data = cast(UserData, get_data())
name: str = data["name"] # pyright knows this is str
When all strategies fail: Apply the Suppression Gate — document approaches tried and fundamental constraint, then return UNRESOLVED to the orchestrator. The pyproject.toml severity level is a project configuration decision, not a linting resolution action. Config changes require explicit user approval via the UNRESOLVED escalation path, not autonomous agent action.
All linter resolution workflows integrate with the python3-development skill at the implementation stage. This integration ensures:
Modern Python Patterns: Fixes use Python 3.11+ syntax
list[str] not List[str])str | None not Optional[str])Idiomatic Code: Solutions follow Python best practices
Type Safety: Type annotations are complete and accurate
Project Consistency: Fixes align with existing codebase patterns
Activation pattern:
[Identify linting issue] → [Research rule] → [Read code] → [Check architecture]
→ [Load python3-development skill] → [Implement elegant fix] → [Verify]