原始内容
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: Requiresfrom __future__ import annotationsin 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:
tool.ruff.target-version(e.g.,"py39") — highest priorityproject.requires-python(e.g.,">=3.9") — parsed to extract version- Default:
py312
Version-specific behavior:
| Version | __future__ Check |
FA Rules | UP036 Ignore |
|---|---|---|---|
| py39 | ✓ (strict) | ✓ | ✓ (no match) |
| py310 | ✓ (strict) | ✓ | — |
| py311+ | ✓ (strict) | — | — |
- FA rules:
flake8-future-annotationscatches missing__future__imports - UP036: Ignored for py39 since
matchstatements aren't available
Consumer Setup
Projects using this plugin need:
pyproject.tomlwith tool configurations.pre-commit-config.yamlfor git hooks- Dev dependencies: pytest, mypy, ruff, black, pre-commit
from __future__ import annotationsat the top of all Python files (strict mode)- 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 testshooks/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 memberssrc/*/_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, 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) |
Default protected branches: main, master (always protected)
Configure additional protected branches in pyproject.toml:
[tool.python-dev-framework]
protected-branches = ["staging", "sandbox"]
This adds staging and sandbox to the protected list. The main and master branches cannot be removed from protection.
Behavior by strictness level:
| Level | Push to protected branches |
|---|---|
| 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
Copy configurations from the pyproject.toml template
Install pre-commit hooks:
uv add --dev pre-commit ruff black mypy pytest pre-commit installSet 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:
- Creates a GitHub Release
- Syncs plugin essentials to the marketplace repo:
.claude-plugin/,hooks/,skills/,CLAUDE.md,.lsp.json
- Updates version in
marketplace.json - 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