Skip to content

WorldCentralKitchen/python-dev-framework

Repository files navigation

Python Development Framework Plugin

Guardrails for LLM-assisted Python development with Claude Code.

This plugin guides Claude toward production-quality code by enforcing type safety, formatting standards, and git conventions in real-time. When Claude writes code that doesn't meet standards, it gets immediate feedback and can self-correct.

Features

  • Real-time diagnostics: LSP integration with Ruff for instant feedback
  • Type enforcement: mypy --strict catches missing annotations as Claude codes
  • Auto-formatting: ruff + black applied on every file write
  • Git conventions: Branch names, commit messages, and protected branch push validation
  • Push protection: Blocks direct pushes to main/master, enforcing PR workflows
  • Python version aware: Detects target Python version and adjusts rules accordingly
  • __future__ enforcement: Requires from __future__ import annotations in strict mode
  • Configurable strictness: strict (block - default), moderate (warn), or minimal (format only)

Installation

This plugin is distributed via the WCK Claude Plugins Marketplace.

Prerequisites

  • Claude Code CLI installed
  • GitHub CLI installed and authenticated (gh auth login)
  • Access to WorldCentralKitchen GitHub org (private repos)

Install Plugin

# Add WCK marketplace (one-time)
claude plugin marketplace add "https://oauth:$(gh auth token)@github.com/WorldCentralKitchen/wck-claude-plugins.git"

# Install plugin (project scope recommended)
claude plugin install python-dev-framework@WorldCentralKitchen --scope project

# Verify
claude plugin list

Update to Latest Version

# Refresh marketplace catalog
claude plugin marketplace update WorldCentralKitchen

# Reinstall plugin to get latest
claude plugin install python-dev-framework@WorldCentralKitchen --scope project

Configuration

Optional: Create .claude/settings.json to customize:

{
  "plugins": {
    "python-dev-framework": {
      "level": "strict"
    }
  }
}
Level Formatting Type Checking Git Validation
strict ruff + black mypy --strict Block invalid
moderate ruff + black Disabled Warn only
minimal black only Disabled Disabled

Python Version Detection

The plugin automatically detects your target Python version from pyproject.toml:

  1. tool.ruff.target-version (e.g., "py39") — highest priority
  2. project.requires-python (e.g., ">=3.9") — parsed to extract version
  3. Default: py312

Version-specific behavior:

Version __future__ Check FA Rules UP036 Ignore
py39 ✓ (strict) ✓ (no match)
py310 ✓ (strict)
py311+ ✓ (strict)
  • FA rules: flake8-future-annotations catches missing __future__ imports
  • UP036: Ignored for py39 since match statements aren't available

Consumer Setup

Projects using this plugin need:

  1. pyproject.toml with tool configurations
  2. .pre-commit-config.yaml for git hooks
  3. Dev dependencies: pytest, mypy, ruff, black, pre-commit
  4. from __future__ import annotations at the top of all Python files (strict mode)
  5. IDE setup for real-time feedback (see IDE Setup below)

Required: __future__ Annotations

In strict mode, all Python files must include:

from __future__ import annotations

This enables modern type syntax (str | None, list[int]) across all supported Python versions (3.9+). The plugin blocks writes that omit this import.

Type Checking Configuration

In strict mode, mypy runs on every Python file after Write/Edit. The plugin passes --python-version based on your detected target version.

Configure exclusions in your pyproject.toml:

[project]
requires-python = ">=3.9"

[tool.ruff]
target-version = "py39"  # Must match requires-python

[tool.mypy]
strict = true
python_version = "3.9"   # Must match requires-python

[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
disallow_incomplete_defs = false

The plugin defers to your project's mypy configuration.

Ruff Rules

The plugin enables comprehensive linting via Ruff:

Category Prefix Purpose
Pycodestyle E, W PEP 8 style
Pyflakes F Logic errors, unused imports
isort I Import sorting
Bugbear B Common bugs, mutable defaults
Comprehensions C4 List/dict comprehension style
Pyupgrade UP Python version upgrades
Unused args ARG Unused function arguments
Simplify SIM Code simplification
flake8-print T Bans print() in src/ (use structlog)
flake8-future FA __future__ annotations (py39/py310)
Type checking TCH TYPE_CHECKING block usage
Pathlib PTH pathlib over os.path
Eradicate ERA Commented-out code
Pylint PL Additional checks
Ruff RUF Ruff-specific rules

See ADR-008 for expanded rules including security (S), async (ASYNC), and pytest (PT) categories.

Print Ban (T201)

In strict mode, print() is banned in src/ directories via Ruff T201. Use structlog instead:

import structlog
log = structlog.get_logger()
log.info("event_name", user_id=123)

Exempt locations (via per-file-ignores):

  • tests/**/*.py — print allowed in tests
  • hooks/scripts/*.py — hooks use print for stdout protocol

See TDD-002 for structlog configuration patterns.

Type Import Enforcement

The plugin auto-fixes deprecated type imports via Ruff pyupgrade (UP) rules:

Before After Rule
List[str] list[str] UP006
Dict[str, int] dict[str, int] UP006
Union[str, int] str | int UP007
Optional[str] str | None UP007
typing.Callable collections.abc.Callable UP035

Behavior by strictness level:

Level UP Rules TCH Rules
strict Fix + Check Fix + Check
moderate Fix only Disabled
minimal Disabled Disabled

See TDD-004 for implementation details and ADR-011 for rationale.

Directory Layout & Private Access

The plugin enforces private attribute access via Ruff SLF001 (flake8-self):

Pattern Enforcement Rule
obj._private_attr Blocked SLF001
obj._private_method() Blocked SLF001
from pkg._internal import x Guidance only

Note: SLF001 catches attribute/method access on objects, not module imports. The _internal/ naming convention is documented guidance.

Exempt locations (via per-file-ignores):

  • tests/**/*.py — Tests can access private members
  • src/*/_internal/*.py — Internal modules can access each other

Behavior by strictness level:

Level SLF001
strict Block violations
moderate Disabled
minimal Disabled

See TDD-005 for templates and ADR-012 for rationale.

Immutability Pattern Enforcement

The plugin enforces immutability patterns via Ruff rules:

Rule Pattern Action
B006 Mutable argument defaults def f(x=[]) Auto-fix
B039 Mutable contextvar defaults Block
RUF008 Mutable defaults in @dataclass Block
RUF012 Mutable class attribute defaults Block

Additionally, mypy catches Sequence[str] footguns via useful-types:

from useful_types import SequenceNotStr

def process(tags: SequenceNotStr[str]) -> None:
    pass

process("hello")  # Type error! str is not SequenceNotStr

Behavior by strictness level:

Level B006/B039/RUF008/RUF012 mypy (SequenceNotStr)
strict Block Block
moderate Fix + Warn Skip
minimal Skip Skip

See TDD-006 for implementation details and ADR-013 for rationale.

See TDD-001 for complete templates.

Push Protection

The plugin prevents direct pushes to protected branches (main/master), enforcing PR workflows:

Command Action
git push origin main Block
git push origin master Block
git push -u origin main Block
git push --force origin main Block
git push origin feature/foo Allow
git push origin v1.0.0 Allow (tag)

Behavior by strictness level:

Level Push to main/master
strict Block with error
moderate Warn, allow push
minimal No validation

See ADR-015 for rationale.

IDE Setup (VSCode)

Configure VSCode for real-time linting and formatting:

uv run --with "python-dev-framework @ git+https://github.com/WorldCentralKitchen/python-dev-framework" setup-ide

This creates .vscode/settings.json and .vscode/extensions.json with Ruff and Mypy integration. Install the recommended extensions when prompted.

Using Without Claude Code

This framework works without Claude Code. The enforcement layers:

Layer Claude Code Standalone
Real-time linting Plugin hooks VSCode + Ruff extension
Type checking Plugin hooks VSCode + Mypy extension
Git-level gate Pre-commit hooks Pre-commit hooks

Standalone Setup

  1. Copy configurations from the pyproject.toml template

  2. Install pre-commit hooks:

    uv add --dev pre-commit ruff black mypy pytest
    pre-commit install
  3. Set up VSCode for real-time feedback:

    uv run --with "python-dev-framework @ git+https://github.com/WorldCentralKitchen/python-dev-framework" setup-ide

Pre-commit provides the same enforcement as Claude Code hooks, but at commit time rather than during editing. The VSCode extensions provide real-time feedback equivalent to Claude Code's PostToolUse hooks.


Development

Prerequisites

  • uv for Python package management
  • Claude Code CLI installed
  • ruff globally installed for LSP diagnostics (brew install ruff)

Install Dependencies

uv sync

IDE Setup

For real-time linting in VSCode, run make setup-ide or see IDE Setup above.

Run Tests

# Unit tests only
uv run pytest tests/test_*.py

# E2E tests (requires Claude CLI + API key)
uv run pytest -m e2e

# All tests
uv run pytest

Use the Plugin During Development

This plugin should be used during its own development. Choose the approach based on your workflow:

Method Command Use When
Install from marketplace claude plugin install python-dev-framework@WorldCentralKitchen --scope project Day-to-day development with stable version
Load from source claude --plugin-dir . Testing unreleased changes before release

Both methods enable:

  • LSP diagnostics: Real-time linting feedback from Ruff
  • PostToolUse hook: Auto-formats Python files on Write/Edit
  • PreToolUse hook: Validates git branch names and commit messages

Escape Hatches

Problem Solution
Hook blocks your work Restart Claude without --plugin-dir
Can't commit git commit --no-verify
Need to debug Run hook script manually

See ADR-007 for rationale.

Release & Distribution

When a new version is tagged, the GitHub Action:

  1. Creates a GitHub Release
  2. Syncs plugin essentials to the marketplace repo:
    • .claude-plugin/, hooks/, skills/, CLAUDE.md, .lsp.json
  3. Updates version in marketplace.json
  4. Opens a PR for review

Users install the bundled copy from the marketplace, not directly from this repo. See the plugin-versioning skill for release procedures.

Repository Structure

python-dev-framework/
├── .claude-plugin/
│   └── plugin.json              # Plugin manifest
├── .lsp.json                    # LSP server configuration
├── hooks/
│   ├── hooks.json               # Hook definitions
│   └── scripts/
│       ├── config.py            # Shared configuration loader
│       ├── format_python.py     # PostToolUse: formats .py files
│       └── validate_git.py      # PreToolUse: validates git commands
├── skills/
│   ├── python-standards/        # Python standards skill
│   └── plugin-versioning/       # Plugin versioning guidance
├── tests/                       # Unit and E2E tests
└── docs/                        # ADRs and TDDs

Documentation

Doc Purpose
CLAUDE.md Claude Code project instructions
Architecture Decision Records Design decisions and rationale (ADR-001 through ADR-013)

License

MIT

About

Opinionated Python development enforcement for Claude Code

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors