- π€ LLM usage: $2.9533 (86 commits)
- π€ Human dev: ~$2235 (22.4h @ $100/h, 30min dedup)
Generated on 2026-07-05 using openrouter/deep/deep-v4-pro
Self-healing Python β catches runtime errors and fixes source code + dependencies via LLM + MCP.
The strategy of using a small tool for detecting errors in a single library or file enables quick bug fixes before writing a prompt, since all context is contained in the error file. This offloads large and expensive models that should be used where smaller ones are insufficientβallowing them to plan and create strategy for the entire library instead of handling individual errors, like in test files.
This automation can also be leveraged via CI/GitOps with provided API keys to the LLM provider for fixing encountered errors during testing across the entire ecosystem.
π‘ New in 0.1.5: Zero-configuration mode! Just
import pfixwithPFIX_AUTO_APPLY=truein.envand any exception triggers automatic repair.
- Zero-config mode β
import pfix+.env= auto-healing for entire project @pfixdecorator β wrap any function; errors trigger automatic repair- Fast dep fix β
ModuleNotFoundErrorβ instantpip/uv install(no LLM call) - pipreqs scanning β project-wide import analysis for missing dependencies
- LLM code repair β sends error context to LLM (OpenRouter/LiteLLM) for intelligent fixes
- pip + uv β auto-detects
uvfor faster installs, falls back topip - MCP server β
@mcp.tool()via FastMCP for IDE integration (Claude Code, Cursor, VS Code) - Git auto-commit β optional auto-commit of fixes with configurable prefix
- Auto-restart β
os.execvprocess restart after fix applied - Interactive diff β unified diff with confirmation before applying
- Backup system β timestamped backups in
.pfix_backups/(can be disabled) - Async support β
@apfixfor async functions
pip install pfix # With MCP server support pip install pfix[mcp] # With git auto-commit pip install pfix[git] # Everything pip install pfix[all]
Clone and install in editable mode:
git clone https://github.com/softreck/pfix.git cd pfix pip install -e . # Or with all optional dependencies pip install -e ".[all]"
Editable mode (-e) allows you to modify source code without reinstalling. Changes take effect immediately.
After installation, examples can be run from any directory:
# From project root cd /path/to/pfix/examples # Run a single example category cd types && python main.py cd data && python main.py # The .env file in project root is automatically found
Example workflow:
cd examples python run_all.py # Run all 12 categories, auto-reset at end python run_all.py --dry-run # Preview what would run python run_all.py --no-reset # Keep fixed versions for inspection python reset.py # Manual reset when needed
Just import pfix with PFIX_AUTO_APPLY=true in your .env:
# .env
OPENROUTER_API_KEY=sk-or-v1-...
PFIX_AUTO_APPLY=true# your_script.py import pfix # Auto-activates global exception hook def buggy_function(x): return 1 / x # Division by zero? Auto-fixed! buggy_function(0) # pfix catches, analyzes, fixes, and retries
What happens:
- Exception is caught by global hook
- LLM analyzes the error context
- Fix is applied to source file
- Process restarts (if
PFIX_AUTO_RESTART=true)
Use pfix_session for fine-grained control:
from pfix import configure, pfix_session configure(auto_apply=True, dry_run=False) def process_data(data): return data[0] / data[1] # Might fail with pfix_session(__file__, auto_apply=True): result = process_data([1, 0]) # Auto-fixed on error print(f"Result: {result}")
Use @pfix for function-level control:
from pfix import pfix @pfix(retries=3, hint="Processes CSV files") def analyze_csv(path): import pandas as pd # Auto-installed if missing df = pd.read_csv(path) return df.groupby("category").sum() @pfix(deps=["requests", "python-dateutil"]) def fetch_events(url: str): import requests from dateutil.parser import parse return [parse(e["ts"]) for e in requests.get(url).json()["events"]]
from pfix import configure # Ask before applying fixes configure(auto_apply=False) import pfix # Hook installed def risky_operation(): return undefined_variable # NameError risky_operation() # Shows diff, asks for confirmation
from pfix import configure # Auto-apply everything, dry run for safety configure(auto_apply=True, dry_run=True, create_backups=False) import pfix
from pfix import pfix, pfix_session # Only protect specific functions @pfix(auto_apply=True) def unstable_api_call(): ... # Or specific code blocks with pfix_session(__file__): untrusted_code()
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Code β
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
β β Zero Config β or β Session Block β or β @pfix Decor β β
β β import pfix β β with pfix_sessionβ β @pfix β β
β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ ββββββββ¬βββββ β
β β β β β
β ββββββββββββββββββββββββββ΄βββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Exception Occurs β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β 1. ModuleNotFoundError? β β β
β β β β pip/uv install β retry β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β β
β β βΌ β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β 2. Build ErrorContext β β β
β β β - Traceback β β β
β β β - Source code β β β
β β β - Local variables β β β
β β β - File imports β β β
β β β - pipreqs scan β β β
β β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β β
β β β β β
β β βΌ β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β 3. LLM Analysis (LiteLLM β OpenRouter) β β β
β β β - Diagnosis β β β
β β β - Fix proposal β β β
β β β - Confidence score β β β
β β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β β
β β β β β
β β βΌ β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β 4. Apply Fix (if confidence > 0.1) β β β
β β β - Show diff (or auto-apply) β β β
β β β - Create backup (if create_backups=True) β β β
β β β - Write fixed code β β β
β β β - Git commit (if git_auto_commit=True) β β β
β β ββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ β β
β β β β β
β β βΌ β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β 5. Recovery β β β
β β β - Reload module β retry β β β
β β β - or os.execv restart β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Error Type | Auto-Fix Strategy | Example Fix |
|---|---|---|
ModuleNotFoundError |
pip/uv install | pip install requests |
NameError |
Add import | import os at top |
TypeError |
Type conversion | str(age) instead of age |
AttributeError |
Fix attribute access | obj.get() instead of obj.attr |
ZeroDivisionError |
Add guard clause | if x == 0: return 0 |
IndexError |
Bounds checking | if i < len(list): |
KeyError |
Safe dict access | dict.get(key, default) |
ValueError |
Input validation | Try/except or validation |
FileNotFoundError |
Check path existence | if os.path.exists(): |
- > 90%: High confidence fixes (type conversions, simple guards)
- 50-90%: Medium confidence (logic changes, API adjustments)
- 10-50%: Low confidence (complex refactorings)
- < 10%: Skipped (manual review recommended)
pfix run script.py # Run with global exception hook pfix run script.py --auto # Auto-apply fixes pfix run script.py --restart # Restart process after fix pfix check # Show config status pfix diagnose # Run environment diagnostics pfix diagnose --category memory,filesystem # Filter categories pfix diagnose --fix # Auto-fix what can be fixed pfix diagnose --output TODO.md # Save to file pfix deps scan # Scan for missing deps (pipreqs) pfix deps install # Install all missing deps pfix deps generate # Generate requirements.txt pfix server # Start MCP server (stdio) pfix server --http 3001 # Start MCP server (HTTP)
pfix exposes tools via FastMCP for IDE integration:
Write-capable MCP tools are disabled unless the server is started with
PFIX_MCP_ALLOW_WRITE=1. A live mutation additionally requires an actor and
the exact approval_hash returned for that proposal; analysis remains available
without the flag.
| Tool | Description |
|---|---|
pfix_analyze |
Analyze error β diagnosis + fix proposal |
pfix_fix |
Analyze + apply fix (with backup) |
pfix_diagnose |
Run environment diagnostics |
pfix_deps_scan |
Scan for missing deps |
pfix_deps_install |
Install a package |
pfix_deps_generate |
Generate requirements.txt |
pfix_edit_file |
Write file content |
Add to your MCP config (.claude/mcp.json or VS Code settings):
{
"mcpServers": {
"pfix": {
"command": "python",
"args": ["-m", "pfix.mcp_server"]
}
}
}pfix supports multiple configuration methods (in order of priority):
- Environment variables (override everything)
.envfile in project rootpyproject.toml[tool.pfix]sectionsetup.cfg[pfix]sectionsetup.pykeyword arguments- Programmatic
configure()
Higher numbers win (environment variables have highest priority):
[6] Environment variables (PFIX_*)
[5] .env file
[4] pyproject.toml [tool.pfix]
[3] setup.cfg [pfix]
[2] setup.py setup()
[1] configure() programmatic
Create a .env file in your project root:
# Required OPENROUTER_API_KEY=sk-or-v1-... # Behavior PFIX_AUTO_APPLY=true # Auto-apply fixes without confirmation PFIX_AUTO_INSTALL_DEPS=true # Auto-install missing dependencies PFIX_AUTO_RESTART=true # Restart process after fix PFIX_MAX_RETRIES=3 PFIX_CREATE_BACKUPS=false # Disable backups # Optional PFIX_MODEL=openrouter/qwen/qwen3-coder-next PFIX_PKG_MANAGER=uv # pip or uv PFIX_GIT_COMMIT=false # Auto-commit fixes PFIX_GIT_PREFIX="pfix: "
Note: .env is searched from current working directory upward, so it works from any subdirectory (e.g., examples/).
Add to your pyproject.toml:
[tool.pfix] model = "openrouter/qwen/qwen3-coder-next" auto_apply = true auto_install_deps = true auto_restart = true max_retries = 3 create_backups = false git_auto_commit = false git_commit_prefix = "pfix: " enabled = true dry_run = false pkg_manager = "uv" # auto, pip, or uv mcp_enabled = false mcp_transport = "stdio" mcp_server_url = "http://localhost:3001"
Benefits:
- Version controlled with your project
- Works with any Python packaging tool
- No external files needed
For projects using setup.cfg:
[metadata] name = myproject version = 1.0.0 ... [pfix] model = openrouter/qwen/qwen3-coder-next auto_apply = true auto_install_deps = true auto_restart = false max_retries = 3 create_backups = true
For projects using setup.py:
from setuptools import setup setup( name="myproject", version="1.0.0", # ... other setup args # pfix configuration pfix_model="openrouter/qwen/qwen3-coder-next", pfix_auto_apply=True, pfix_auto_install_deps=True, pfix_auto_restart=False, pfix_max_retries=3, pfix_create_backups=True, pfix_enabled=True, )
Note: setup.py config requires pfix to be installed in the same environment.
Configure at runtime in your Python code:
from pfix import configure # Before importing pfix or using the hook configure( # LLM settings llm_model="openrouter/qwen/qwen3-coder-next", llm_api_key="sk-or-v1-...", llm_temperature=0.2, llm_max_tokens=4096, # Behavior auto_apply=True, auto_install_deps=True, auto_restart=True, max_retries=3, enabled=True, dry_run=False, # Project pkg_manager="uv", create_backups=False, project_root="/path/to/project", # Git git_auto_commit=False, git_commit_prefix="pfix: ", # MCP mcp_enabled=False, mcp_transport="stdio", ) ### Configuration Reference | Variable | Type | Default | Description | |----------|------|---------|-------------| | `OPENROUTER_API_KEY` | `str` | β | **Required** β OpenRouter API key | | `PFIX_MODEL` | `str` | `openrouter/qwen/qwen3-coder-next` | LLM model to use | | `PFIX_API_BASE` | `str` | `https://openrouter.ai/api/v1` | API base URL | | `PFIX_AUTO_APPLY` | `bool` | `false` | Auto-apply fixes without confirmation | | `PFIX_AUTO_INSTALL_DEPS` | `bool` | `true` | Auto-install missing dependencies | | `PFIX_AUTO_RESTART` | `bool` | `false` | Restart process after fix applied | | `PFIX_MAX_RETRIES` | `int` | `3` | Max fix attempts per error | | `PFIX_DRY_RUN` | `bool` | `false` | Show proposed fixes without applying | | `PFIX_CREATE_BACKUPS` | `bool` | `true` | Create `.pfix_backups/` before fixing | | `PFIX_ENABLED` | `bool` | `true` | Master switch to disable pfix | | `PFIX_PKG_MANAGER` | `str` | auto | `pip`, `uv`, or auto-detected | | `PFIX_GIT_COMMIT` | `bool` | `false` | Auto-commit fixes to git | | `PFIX_GIT_PREFIX` | `str` | `pfix: ` | Git commit message prefix | | `PFIX_MCP_ENABLED` | `bool` | `false` | Enable MCP server | | `PFIX_MCP_TRANSPORT` | `str` | `stdio` | `stdio` or `http` | | `PFIX_PROJECT_ROOT` | `str` | `.` | Project root for relative paths | ## LLM Models & Providers pfix uses [LiteLLM](https://litellm.ai) to support multiple LLM providers. You can use cloud APIs or run models locally. ### OpenRouter (Cloud - Recommended) OpenRouter provides access to multiple models with a single API key. ```bash # .env OPENROUTER_API_KEY=sk-or-v1-... PFIX_MODEL=openrouter/qwen/qwen3-coder-next
Recommended models:
| Model | Description | Best For |
|---|---|---|
openrouter/qwen/qwen3-coder-next |
Claude 4 Sonnet | Balanced quality/speed |
openrouter/anthropic/claude-opus-4 |
Claude 4 Opus | Complex fixes |
openrouter/anthropic/claude-haiku-4 |
Claude 4 Haiku | Fast, cheap fixes |
openrouter/qwen/qwen3-235b-a22b-2507 |
Qwen3 235B | Code-heavy tasks |
openrouter/qwen/qwen3.5-flash-02-23 |
Qwen3.5 Flash | Fast responses |
openrouter/nvidia/nemotron-3-super-120b-a12b:free |
Nemotron 3 Super | Free tier |
openrouter/deepseek/deepseek-coder-v2 |
DeepSeek Coder | Code-specific |
Run models locally for zero cost and complete privacy.
Setup:
# Pull a code-capable model
ollama pull codellama:7b
ollama pull qwen2.5-coder:7b
ollama pull deepseek-coder:6.7bConfigure pfix:
# .env PFIX_MODEL=ollama/codellama:7b PFIX_API_BASE=http://localhost:11434 # No API key needed for local models
Recommended local models:
| Model | Size | Speed | Quality |
|---|---|---|---|
ollama/codellama:7b |
7B | Fast | Good |
ollama/qwen2.5-coder:7b |
7B | Fast | Very Good |
ollama/deepseek-coder:6.7b |
6.7B | Fast | Very Good |
ollama/codellama:13b |
13B | Medium | Excellent |
ollama/qwen2.5-coder:14b |
14B | Medium | Excellent |
PFIX_MODEL=gpt-4o PFIX_API_KEY=sk-... PFIX_API_BASE=https://api.openai.com/v1
**Models:** `gpt-4o`, `gpt-5.4-mini`, `gpt-4-turbo`, `gpt-3.5-turbo`
# .env
PFIX_MODEL=anthropic/claude-3-sonnet-20241022
PFIX_API_KEY=sk-ant-...
Models: claude-3-opus, claude-3-sonnet, claude-3-haiku
PFIX_MODEL=azure/ PFIX_API_KEY=... PFIX_API_BASE=https://.openai.azure.com
# .env
PFIX_MODEL=vertex_ai/gemini-1.5-pro
# or
PFIX_MODEL=gemini/gemini-1.5-pro
For beginners: Start with openrouter/qwen/qwen3-coder-next (good balance)
For cost savings: Use Ollama locally or OpenRouter free models (:free suffix)
For complex fixes: Use larger models (Claude Opus, GPT-4, Qwen 235B)
For speed: Use smaller models (Haiku, GPT-4o-mini, local 7B models)
pfix can automatically capture runtime errors to TODO.md for production monitoring:
[tool.pfix.runtime_todo] enabled = true todo_file = "TODO.md" min_severity = "medium" max_entries = 500 deduplicate = true include_local_vars = false include_traceback_depth = 5
Features:
- Absolute paths β errors tracked with full file paths
- Deduplication β same error 1000x = one entry with counter
- Full traceback β complete call stack, not just last frame
- Environment context β Python version, hostname, PID, venv path
- Thread-safe β file locking for multi-worker setups (gunicorn/uvicorn)
- Append-only β never loses history
Enable via environment:
PFIX_RUNTIME_TODO=true PFIX_TODO_FILE=TODO.md
Comprehensive environment checking with 14 diagnostic categories:
pfix diagnose # Run all diagnostics pfix diagnose --category venv,memory,network pfix diagnose --json --check # CI mode (exit 1 on errors) pfix diagnose --fix # Auto-fix what can be fixed
Categories:
| Category | Checks |
|---|---|
import_dependency |
Missing imports, circular deps, version conflicts, stdlib shadowing |
filesystem |
Disk space, permissions, broken symlinks, large files |
venv |
Activation, integrity, global leaks, requirements sync |
python_version |
pyproject.toml requires-python, deprecated features |
memory |
Available RAM, swap, recursion limit, GC pressure |
network |
DNS, connectivity, SSL certs, proxy config |
process |
ulimits, signals, zombie processes |
encoding |
UTF-8 BOM, line endings, locale |
paths |
sys.path issues, PYTHONPATH, long paths |
config_env |
.env security, required vars, gitignore |
concurrency |
Thread count, asyncio loop issues |
serialization |
Pickle protocol, corrupt cache files |
hardware |
GPU availability, CPU count, Docker limits |
third_party |
API rate limits, auth expiration, schema changes |
Auto-fixable issues:
- Stale
.pycfiles βfind . -name '*.pyc' -delete - UTF-8 BOM β remove BOM markers
- Mixed line endings β convert to LF
- Missing
.envβ copy from.env.example .envnot gitignored β add to.gitignore- Large log files β truncate to last N lines
Usage in CI/CD:
- run: pfix diagnose --check --json continue-on-error: true
from pfix import pfix def log_error(exc): with open("errors.log", "a") as f: f.write(f"{type(exc).__name__}: {exc}\n") @pfix(on_error=log_error, retries=3) def risky_operation(): ...
from pfix import apfix @apfix(auto_apply=True) async def fetch_data(url): import aiohttp async with aiohttp.ClientSession() as session: async with session.get(url) as response: return await response.json()
from pfix import pfix_session, get_config config = get_config() config.llm_model = "openrouter/anthropic/claude-opus-4" config.llm_temperature = 0.1 with pfix_session(__file__, auto_apply=True, restart=True): main()
See examples/ directory for working examples:
demo_auto.pyβ Zero-config auto-healingdemo.pyβ Explicit session controlREADME.mdβ Examples documentation
- Start with
PFIX_AUTO_APPLY=falseto review fixes before applying - Enable backups (
PFIX_CREATE_BACKUPS=true) in development - Use dry-run mode in CI/CD to preview fixes without applying
- Set
PFIX_AUTO_RESTART=truefor long-running processes - Add hints to decorators for better LLM context:
@pfix(hint="Processes CSV files")
- Increase context with
@pfix(hint="...") - Check your API key is valid
- Try a different model in
PFIX_MODEL
- Ensure the error is in a named function (not
lambdaorexec) - Use
pfix_sessionfor module-level code
- Set
PFIX_CREATE_BACKUPS=false - Clean
.pfix_backups/periodically:rm -rf .pfix_backups/
- Set
PFIX_MAX_RETRIES=1to limit attempts - Use
PFIX_AUTO_RESTART=falseto disable restarts
| Package | Role |
|---|---|
litellm |
LLM proxy β OpenRouter, OpenAI, Anthropic, Ollama |
python-dotenv |
Load .env configuration |
rich |
Terminal UI (diffs, panels, tables) |
pipreqs |
Project import scanning |
pathspec |
Gitignore-aware file filtering |
mcp |
FastMCP server (optional) |
gitpython |
Git auto-commit (optional) |
watchdog |
File change watching (optional) |
Licensed under Apache-2.0.
Last updated by taskill at 2026-04-25 13:42 UTC
| Metric | Value |
|---|---|
| HEAD | 6ddd51f |
| Coverage | β |
| Failing tests | β |
| Commits in last cycle | 50 |
Introduced a deep code analysis engine and a configuration management system, plus a number of documentation/refactor updates and CLI/config fixes across the project.
See dependency updates and Python tool groups for locked tests, daily updates and freshness checks.