Skip to main content

modern-python-guidance

CI PyPI version Python License

Stop your AI from writing typing.List, @validator, and setup.py. 41 version-aware BAD/GOOD pattern guides that teach AI coding agents to write modern Python — delivered via MCP, CLI, or Agent Skills.

Highlights

  • Evidence status: Historical V5 content-efficacy evidence is documented with its model, prompt, sample, metric, and delivery scope; it is not a product-wide effectiveness claim (V5 benchmark details)
  • 41 guides across stdlib, Pydantic, FastAPI, Django, SQLAlchemy, pytest, and toolchain
  • Version- and dependency-aware: filters Python-version-incompatible guidance and qualifies framework/tool guidance from project evidence
  • 4 delivery methods: MCP server, CLI, Agent Skills, and Rules (auto-injects on .py file touch)
  • Not Ruff: Ruff auto-fixes syntax (Listlist). mpg guides design decisions that Ruff can't touch — TaskGroup over gather, Pydantic V2 migration, SQLAlchemy 2.0 style

Benchmark evidence status: historical V5 cells remain documented for audit, but no traceable numeric product claim is currently promoted. Default mpg setup end-to-end effectiveness has not yet been measured.

Note: The tool itself requires Python 3.11+ to run. Guides cover patterns from Python 3.9 onward, and --python-version filters guides for your target environment.

Quick start

Claude Code (recommended)

pip install modern-python-guidance
mpg setup

This registers the MCP server, links Agent Skills, creates a Rules file (.claude/rules/modern-python.md), and registers a PostToolUse hook in one command. The Rules file auto-injects modern Python guidance whenever you touch Python-related files, and the hook checks each edited .py file against the guides with a detector applicable to the target project (see PostToolUse hook below). Advisory-only gaps are disclosed through CLI/MCP metadata. Start a new Claude Code session afterwards — newly registered MCP servers, skills, rules, and hooks take effect on the next launch.

CLI

pip install modern-python-guidance
mpg search "pydantic validator"
mpg retrieve pydantic-v2-validators

mpg is the short alias for modern-python-guidance. Both work.

Manual setup / other agents

MCP registration (Claude Code):

# uv tool / pipx installs (mpg is on PATH):
claude mcp add mpg -- mpg mcp

# venv installs — Claude Code spawns MCP servers outside your venv, so register
# the interpreter's absolute path (`mpg setup` does this automatically):
claude mcp add mpg -- "$(python -c 'import sys; print(sys.executable)')" -m modern_python_guidance mcp

Other MCP-compatible agents (Cursor, Windsurf, etc.) — add to your MCP config:

{
  "mcpServers": {
    "mpg": {
      "command": "mpg",
      "args": ["mcp"]
    }
  }
}

For venv installs, set "command" to your interpreter's absolute path and "args" to ["-m", "modern_python_guidance", "mcp"] for the same reason as above.

Agent Skills + Rules only (Claude Code):

mpg setup --skills-only

mpg setup flags:

Flag Purpose
--mcp-only MCP registration only
--skills-only Project-local artifacts only (Skills + Rules)
--scope {user,local} MCP scope (default: user)
--project-dir PATH Target project for local MCP and project artifacts
--dry-run Show what would be done
--no-hook Don't register the PostToolUse hook (removes it if already present)
--with-hook Register the hook even if this project already has mpg artifacts

If this project already has mpg's Skills or Rules symlinks from a previous mpg setup, the hook is not silently enabled — you'll see a note instead (New: mpg can auto-check Python files after every edit. / Enable: mpg setup --with-hook). A fresh project gets the hook by default.

After registering, mpg setup checks whether a same-name registration in a higher-precedence scope (local > project > user) would shadow the one it just wrote, and prints a warning with the exact claude mcp remove command if so.

Uninstall — reverse mpg setup (deregister the MCP server and unlink Agent Skills + Rules):

mpg uninstall            # remove all
mpg uninstall --dry-run  # preview what would be removed
Flag Purpose
--mcp-only MCP deregistration only
--skills-only Project-local artifacts only (Skills + Rules)
--project-dir PATH Target project for local MCP and project artifacts
--dry-run Show what would be done

mpg uninstall clears the MCP registration from every scope setup can write to (user and local), removes only the symlinks mpg created (never their targets or other files), removes mpg's PostToolUse hook entry from .claude/settings.local.json (leaving any other tools' hooks untouched), and is idempotent — running it on an already-clean state is a harmless no-op.

When --scope local is used, --project-dir is also the cwd for every MCP add, replacement, health-check, and removal operation. A missing target is created before local setup; uninstall fails closed for a missing explicit target instead of touching the caller's local registration. User-scope MCP operations remain global and do not use this path.

CLI usage

# Search guides by keyword
mpg search "pydantic validator"

# Retrieve a specific guide (full BAD/GOOD content)
mpg retrieve use-builtin-generics

# List all guides compatible with your Python version
mpg list --python-version 3.11

# Auto-detect project Python version from pyproject.toml / .python-version
mpg detect-version

# Filter by category
mpg search "timeout" --category async

# Filter by layer (1 stdlib, 2 frameworks, 3 toolchain) or by how often the pattern is missed
mpg list --layer 2
mpg list --frequency high

# Filters combine — this is the intersection, not the union
mpg list --layer 1 --frequency high

# Emit the selected guides with their full bodies, for building a system prompt
mpg list --layer 2 --frequency high --with-content --format json > guidance.json

# Scan a file for outdated patterns
mpg check app.py
mpg check app.py --format json | jq '.summary.guide_ids'
mpg check app.py --exit-zero  # always exit 0

# JSON output (default when piped, explicit with --format)
mpg search "typing" --format json | jq '.[0].id'

# Read dependency evidence from another project; hide proven-incompatible guides by default
mpg search "pydantic validator" --project-dir ../my-app

# Supply an exact target-environment override when files cannot prove it
mpg search "pydantic validator" --dependency-version package:pydantic=2.7.4

Guide coverage

41 guides across 3 layers:

Layer Categories Count Examples
1 — stdlib typing, async, stdlib, data-structures 18 list over List, match/case, TaskGroup, deferred annotations, t-strings
2 — frameworks pydantic, fastapi, httpx, django, sqlalchemy, pytest 18 Pydantic V2 migration, SQLAlchemy 2.0 style, Annotated[Depends]
3 — toolchain toolchain 5 uv over pip, ruff over flake8, pickle avoidance

Run mpg list to see the 41-guide catalog, or browse it on GitHub.

Selecting a subset of the catalog

--category, --layer, and --frequency select on guide metadata and combine as an intersection: --layer 1 --frequency high returns the guides that are both, not either. search and list accept all three, as do the search_guides and list_guides MCP tools. mpg list --with-content adds each guide's full body to the output, which is the shape to pipe into a system prompt or a generated rules file.

Two things to expect. First, the counts you get back are what survives after the target Python and dependency filters, which apply on every command whether or not you asked for them — mpg list --layer 1 reports fewer guides than the layer table above when your project targets an older Python, and --python-version 3.14 shows the full catalog. Second, mpg search falls back to fuzzy suggestions whenever the exact query matches nothing, and a filter can leave it with nothing to match; a precise query that returns unexpected results marked fuzzy: true usually means the filter excluded the guide you were looking for, not that the query was wrong.

Note that --layer and --frequency make two abbreviations ambiguous that used to resolve: --f no longer selects --format, and --l no longer selects --limit. Spell those two out.

Version-aware filtering

Guides specify their minimum Python version. Every guidance command resolves the target Python from the nearest project context (and discloses the result as target_python: {version, source}) using this precedence:

  1. --python-version flag
  2. pyproject.toml requires-python
  3. pyproject.toml Poetry python constraint (^3.10, ~3.11, >=3.10,<3.14)
  4. .python-version file
  5. Default: 3.11

The same resolver is used by CLI search/retrieve/list/check, the MCP guidance tools, and the PostToolUse hook. An explicit CLI/MCP version always wins. mpg detect-version keeps its plain output for scripts; use mpg detect-version --format json to audit the resolved version and stable source label, including when a JSON search or list result is empty.

# Only shows guides compatible with Python 3.9 (explicit override)
mpg list --python-version 3.9
# Excludes: TaskGroup (3.11+), match/case (3.10+), etc.

Dependency-aware applicability

Framework and toolchain guides declare machine-readable applies-to-packages and/or applies-to-tools metadata. Every declared requirement must be proven (AND semantics). mpg search and mpg list hide guidance that is proven incompatible by default; use --include-incompatible to inspect it. retrieve always returns an explicitly requested guide so migration work can be reviewed.

Use --project-dir PATH to read the nearest project evidence, and repeat --dependency-version KIND:NAME=VERSION for an exact target-environment override. The MCP search_guides, retrieve_guides, and list_guides tools expose the same project_dir (relative to the MCP server), dependency_versions object, and include_incompatible option where filtering applies. search_guides and list_guides additionally accept layer and frequency; retrieve_guides takes neither, since it is addressed by explicit ID.

Results contain additive dependency_requirements and dependency_compatibility objects. Status is deliberately conservative:

  • confirmed: all requirements are proven compatible;
  • incompatible: at least one requirement is proven incompatible;
  • unknown: evidence is absent, ambiguous, conditional, or cannot safely prove a range.

Unknown is not confirmation. Do not infer the target environment from the interpreter running mpg, a [tool.uv]/[tool.ruff] table, optional or dependency-group entries, or an unrooted/ambiguous lockfile. The PostToolUse hook suppresses known-incompatible findings and asks for verification when status is unknown; mpg check follows the same rule and annotates remaining unknown findings in JSON/human output.

PostToolUse hook

mpg setup registers a PostToolUse hook by default (see Quick start above) — no manual .claude/settings.local.json editing needed. It checks every .py file Claude edits or writes against the detector-capable guides applicable to the target project and surfaces findings via hookSpecificOutput.additionalContext, so Claude receives them as part of its own context rather than as a raw stderr error.

mpg check and the PostToolUse hook automatically check only guides with a detector for the target Python/dependency context. The current catalog has 26 detectable guides out of 41; 15 are advisory-only and are not claimed as actively checked. Advisory-only guides: dataclass-modern, dict-merge-operator, django-check-constraints, exception-groups, fastapi-typed-state, httpx-streaming, match-case-patterns, override-decorator, pytest-parametrize, pytest-raises-match, removeprefix-removesuffix, ruff-over-flake8, sqlalchemy-async-session, template-strings, uv-over-pip. A clean automatic check does not certify advisory-only guidance. Use mpg list --format json or MCP metadata to inspect each guide's detection status.

This capability contract is distinct from #152: #181 describes which guides can produce automatic findings after activation, while #152 measures whether an organic development session reaches the catalog at all.

A few things worth knowing about how it behaves:

  • It scans the whole edited file, not just your diff. An edit anywhere in a file can resurface pre-existing outdated patterns you didn't touch this time, not only the lines you just wrote.
  • Findings are capped at 5 per edit, plus a +N more summary line, to bound how much context gets injected.
  • Only the guide ID and line number are surfaced — never the matching source line itself. Echoing arbitrary file content back as an authoritative-looking hook message would be an indirect prompt-injection channel; guide_id + line number is enough for Claude to look up the modern form.
  • The project's target Python version is auto-detected the same way as mpg detect-version (nearest pyproject.toml requires-python / Poetry python constraint, or .python-version, walking up from the edited file), so patterns that require a newer Python than your project targets are not flagged. The resolved target and source are shown in the summary ([target: py3.X; source: SOURCE]).
  • Non-Python files and clean files produce no output.
  • An existing project (Skills/Rules already linked from a previous mpg setup) is never silently opted in — see the --with-hook/--no-hook flags above.

Verify with /hooks in Claude Code to confirm it's active.

For manual CLI use, mpg check --quiet <file> uses the same automatic resolver. Pass --python-version X.Y when you intentionally want an explicit override; the JSON output contains the same top-level target_python object.

Manual hook setup (advanced)

If you'd rather manage the hook entry yourself instead of mpg setup, add it to .claude/settings.local.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/python",
            "args": ["-m", "modern_python_guidance", "hook", "claude-post-tool-use"]
          }
        ]
      }
    ]
  }
}

Use the interpreter's absolute path (command), not a bare mpg/python — Claude Code spawns hooks from its own environment, where a venv-only interpreter is not on PATH. mpg setup resolves and pins this for you automatically.

Development

git clone https://github.com/yottayoshida/modern-python-guidance.git
cd modern-python-guidance
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
pytest

See CONTRIBUTING.md for project structure and guide authoring details.

License

Apache-2.0 OR MIT — see LICENSE and LICENSE-MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

modern_python_guidance-0.6.0.tar.gz (295.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

modern_python_guidance-0.6.0-py3-none-any.whl (120.8 kB view details)

Uploaded Python 3

File details

Details for the file modern_python_guidance-0.6.0.tar.gz.

File metadata

  • Download URL: modern_python_guidance-0.6.0.tar.gz
  • Upload date:
  • Size: 295.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for modern_python_guidance-0.6.0.tar.gz
Algorithm Hash digest
SHA256 b61d16d23399e648e5dfb75b23a94b5140b8cd7c559ea6b8fd4191d9a5403325
MD5 6d7277483db5dad273810faaa763a038
BLAKE2b-256 bc6b690754e6da7d589bac949c2b8367fa4f6c3cffaea5e4cf3f86728c87ef98

See more details on using hashes here.

Provenance

The following attestation bundles were made for modern_python_guidance-0.6.0.tar.gz:

Publisher: ci.yml on yottayoshida/modern-python-guidance

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file modern_python_guidance-0.6.0-py3-none-any.whl.

File metadata

File hashes

Hashes for modern_python_guidance-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 04dcec33bc162612d76567682c0db535bdc1bf7c809509d79b60212f1896a410
MD5 77bac56ec6a77bb18d3ba86a933e01d5
BLAKE2b-256 259b8502baf8b06f65e4fa6ea208e84e9f6953318f7807f879a155afc54f07fe

See more details on using hashes here.

Provenance

The following attestation bundles were made for modern_python_guidance-0.6.0-py3-none-any.whl:

Publisher: ci.yml on yottayoshida/modern-python-guidance

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page