Python Dev Bundle¶
What is the Python Dev Bundle?¶
You've used grep to find text and LSP to navigate definitions. But Python development isn't just reading code — it's a tight loop of writing, checking, and fixing. You write a function, and you need to know immediately: does it lint? Does it type-check? Did you break something downstream?
The Python Dev bundle integrates code quality and code intelligence into a single package. It supersedes the older LSP Python bundle by combining two capabilities that used to live apart: a python_check tool that runs formatting, linting, and type checking in one pass, and a code-intel agent that handles complex semantic navigation. On top of that, it hooks into file writes — every time you save a Python file, checks run automatically, so problems surface before they compound.
The result is a development loop where code quality isn't a separate step you remember to run. It's built into the way you work.
What's Included¶
The bundle provides two main capabilities and an automatic checking hook:
| Component | What It Does |
|---|---|
python_check tool |
Runs ruff (formatting + linting), pyright (type checking), and stub detection on files or inline code |
python-dev:code-intel agent |
LSP/Pyright specialist for multi-step semantic code navigation |
| Auto-check hook | Fires on every Python file write — runs lint and type checks automatically |
python_check Tool¶
The python_check tool is your single entry point for code quality. It orchestrates three checkers behind the scenes:
- Ruff — formatting and linting (replaces black, isort, flake8, and dozens of other tools)
- Pyright — static type checking with full type inference
- Stub detection — identifies missing type stubs for third-party packages
You can run it against files, directories, or raw code strings, and optionally auto-fix what's fixable.
code-intel Agent¶
The python-dev:code-intel agent is a Pyright/LSP specialist. It handles complex, multi-step code navigation that would require chaining several LSP operations together — tracing inheritance hierarchies, mapping module dependencies, building call graphs, debugging type flows across files. Think of it as the senior developer who already knows how to use all the LSP operations and will chain them together intelligently for you.
Getting Started¶
Prerequisites¶
The bundle requires ruff and pyright installed as Python packages in your environment — not just on PATH:
pip install ruff pyright
Both must be importable from the Python environment your project uses. If you're working inside a virtual environment, install them there.
Your First Check¶
Run a check against a file:
Check src/main.py for issues
[Tool: python_check]
paths: ["src/main.py"]
✓ Format: clean
✗ Lint: 2 issues
src/main.py:14:5 F841 Local variable 'result' is assigned but never used
src/main.py:27:1 E302 Expected 2 blank lines before function definition
✗ Types: 1 error
src/main.py:31:12 error Argument of type "str" cannot be assigned
to parameter "count" of type "int"
Summary: 2 lint issues, 1 type error
Three checkers, one tool call. The response tells you exactly what to fix and where.
Auto-Fix¶
Many lint and format issues can be fixed automatically:
Fix the formatting and lint issues in src/
[Tool: python_check]
paths: ["src/"]
fix: true
Fixed 14 issues across 6 files:
src/main.py — 2 fixes (unused import, blank lines)
src/utils.py — 5 fixes (import sorting, trailing whitespace)
src/models.py — 3 fixes (formatting)
src/api/views.py — 4 fixes (line length, blank lines)
Auto-fix handles formatting and safe lint fixes. Type errors require manual intervention — the tool reports them, you fix the logic.
Key Features¶
Automatic Checking on File Writes¶
This is the feature that changes your workflow. Every time a Python file is written — whether you write it, an agent writes it, or a recipe step writes it — the auto-check hook fires. It runs lint and type checks and reports problems immediately.
Add a caching decorator to src/utils.py
[Tool: edit_file] src/utils.py — added cache_result decorator
[Hook: python-dev auto-check]
src/utils.py — lint clean, types clean ✓
If the edit introduces problems, you see them instantly:
Refactor the database connection to use async
[Tool: edit_file] src/db.py — converted to async/await
[Hook: python-dev auto-check]
src/db.py:42:5 error "await" not allowed in non-async function
src/db.py:58:12 error Return type "Coroutine[Any, Any, Connection]"
is not assignable to "Connection"
No separate "now run the linter" step. The feedback loop is immediate.
Checking Inline Code¶
You can check code without writing it to a file first — useful for validating a snippet before committing to it:
Check this code for issues
[Tool: python_check]
content: |
def process(items: list[str]) -> int:
for item in items:
result = item.upper()
return result
✗ Lint: 1 issue
line 3:9 F841 Local variable 'result' assigned in loop body
✗ Types: 1 error
line 4:12 error "result" is possibly unbound
Selective Checks¶
Run only the checks you need with the checks parameter:
Just run type checking on src/api/
[Tool: python_check]
paths: ["src/api/"]
checks: ["types"]
src/api/views.py:22:8 error Cannot access attribute "user_id"
for class "AnonymousUser"
Available check types: format, lint, types, stubs.
Using the code-intel Agent¶
For simple, single-step LSP operations — go to definition, find references, hover — use the LSP tool directly. For complex tasks that require chaining multiple operations, delegate to the code-intel agent:
Trace how request authentication works from the middleware through to the permission check
[Agent: python-dev:code-intel]
1. Found AuthMiddleware.process_request in src/middleware/auth.py:18
2. Traces to authenticate_token() in src/auth/tokens.py:42
→ Returns AuthResult with user and permissions
3. AuthResult flows to PermissionCheck.has_access() in src/permissions.py:65
→ Checks user.permissions against required_perms
4. Permission failure raises PermissionDenied (src/exceptions.py:12)
Call chain: process_request → authenticate_token → has_access
Key types: AuthResult(user: User, permissions: Set[str])
When to delegate vs. use LSP directly:
| Task | Approach |
|---|---|
"Where is UserModel defined?" |
LSP goToDefinition directly |
"What type does get_config() return?" |
LSP hover directly |
"Find all callers of validate()" |
LSP incomingCalls directly |
| "Trace the data flow from API to database" | Delegate to code-intel |
| "Map the inheritance hierarchy of all handlers" | Delegate to code-intel |
| "Why is this type mismatch happening across modules?" | Delegate to code-intel |
The rule of thumb: if you'd need to chain three or more LSP operations, or if the task requires judgment about which operations to run next, delegate.
Configuration¶
The bundle reads configuration from your project's pyproject.toml:
[tool.amplifier-python-dev]
# Checks to run automatically on file writes (default: lint + types)
auto_checks = ["lint", "types"]
# Additional ruff rules to enable or disable
ruff_select = ["I", "UP"]
ruff_ignore = ["E501"]
# Pyright type checking mode
type_checking_mode = "basic" # "off", "basic", "standard", "strict"
Ruff and Pyright also respect their own configuration sections in pyproject.toml — [tool.ruff] and [tool.pyright] — so your existing project settings carry over automatically.
A Practical Workflow¶
Here's a real development loop using the Python Dev bundle — writing a new feature from scratch:
Add a retry decorator with exponential backoff to src/utils/retry.py
[Tool: write_file] src/utils/retry.py — created with retry decorator
[Hook: python-dev auto-check]
src/utils/retry.py:8:22 F821 Undefined name 'wraps'
src/utils/retry.py:15:5 error "sleep" is not defined
The auto-check caught two missing imports immediately. Fix them:
Add the missing imports for wraps and sleep
[Tool: edit_file] src/utils/retry.py — added imports
[Hook: python-dev auto-check]
src/utils/retry.py — lint clean, types clean ✓
Now verify the whole utils package is consistent:
Run a full check on src/utils/
[Tool: python_check]
paths: ["src/utils/"]
✓ Format: clean
✓ Lint: clean
✓ Types: clean
✓ Stubs: no missing stubs
Summary: all checks passed
Clean across the board. The whole loop — write, catch, fix, verify — happened without leaving the conversation.
Tips¶
-
Trust the auto-check. It fires on every write. If you don't see warnings, the file is clean. You don't need to run
python_checkmanually after every edit — only for broader sweeps across directories. -
Use
fix: truefor formatting. Don't manually fix import order or blank line issues. Letpython_checkhandle them automatically. Save your attention for type errors that need actual thought. -
Check content before files. When prototyping a tricky function, pass it as
contentfirst. Once the snippet is clean, write it to disk. -
Delegate complex navigation. If you find yourself running three LSP operations in a row trying to trace something, stop and delegate to
code-intel. It'll get there faster with better context. -
Configure your project's pyproject.toml. The bundle's auto-checks respect your project's ruff and pyright settings. Set them once and every check — manual or automatic — follows your rules.
Next Steps¶
- Learn about the LSP Tool for direct code intelligence operations
- Explore the Foundation Bundle for the core tools Python Dev builds on
- See Recipes for automating multi-step Python workflows
- Read about Skills for adding Python domain knowledge