plugins/holistic-linting/skills/holistic-linting-resolver/SKILL.md
Linter-specific resolution workflows for ruff, mypy, pyright, and basedpyright. Provides systematic root-cause analysis procedures, suppression gates, and verification steps. Use when resolving linting errors as a sub-agent, implementing fixes systematically, or conducting type flow analysis.
npx skillsauth add jamie-bitflight/claude_skills holistic-linting-resolverInstall 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.
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]
development
When an application needs to store config, data, cache, or state files. When designing where user-specific files should live. When code writes to ~/.appname or hardcoded home paths. When implementing cross-platform file storage with platformdirs.
testing
Enforce mandatory pre-action verification checkpoints to prevent pattern-matching from overriding explicit reasoning. Use this skill when about to execute implementation actions (Bash, Write, Edit) to verify hypothesis-action alignment. Blocks execution when hypothesis unverified or action targets different system than hypothesis identified. Critical for preventing cognitive dissonance where correct diagnosis leads to wrong implementation.
tools
Reference guide for the Twelve-Factor App methodology — 15 principles (12 original + 3 modern extensions) for building portable, resilient, cloud-native applications. Use when evaluating application architecture, designing cloud-native services, reviewing codebases for methodology compliance, advising on configuration, scaling, observability, security, and deployment patterns. Incorporates the 2025 open-source community evolution and cloud-native reinterpretations of each factor.
tools
Converts user-facing documentation (how-to guides, tutorials, API references, examples) in any format — Markdown, PDF, DOCX, PPTX, XLSX, AsciiDoc, RST, HTML, Jupyter notebooks, man pages, TOML/YAML/JSON configs, and plain text — into Claude Code skill directories with SKILL.md plus thematically grouped references/*.md files. Use when given a docs directory or mixed-format documentation to transform into an AI skill. Uses MCP file-reader server for binary formats.