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.
- 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)
This plugin is distributed via the WCK Claude Plugins Marketplace.
- Claude Code CLI installed
- GitHub CLI installed and authenticated (
gh auth login) - Access to WorldCentralKitchen GitHub org (private repos)
# 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# Refresh marketplace catalog
claude plugin marketplace update WorldCentralKitchen
# Reinstall plugin to get latest
claude plugin install python-dev-framework@WorldCentralKitchen --scope projectOptional: 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 |
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
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)
In strict mode, all Python files must include:
from __future__ import annotationsThis enables modern type syntax (str | None, list[int]) across all supported Python versions (3.9+). The plugin blocks writes that omit this import.
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 = falseThe plugin defers to your project's mypy configuration.
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.
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.
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.
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.
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 SequenceNotStrBehavior 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.
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.
Configure VSCode for real-time linting and formatting:
uv run --with "python-dev-framework @ git+https://github.com/WorldCentralKitchen/python-dev-framework" setup-ideThis creates .vscode/settings.json and .vscode/extensions.json with Ruff and Mypy integration. Install the recommended extensions when prompted.
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 |
-
Copy configurations from the pyproject.toml template
-
Install pre-commit hooks:
uv add --dev pre-commit ruff black mypy pytest pre-commit install
-
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.
- uv for Python package management
- Claude Code CLI installed
- ruff globally installed for LSP diagnostics (
brew install ruff)
uv syncFor real-time linting in VSCode, run make setup-ide or see IDE Setup above.
# 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 pytestThis 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
| 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.
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.
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
| Doc | Purpose |
|---|---|
| CLAUDE.md | Claude Code project instructions |
| Architecture Decision Records | Design decisions and rationale (ADR-001 through ADR-013) |
MIT