Self-healing Python โ catches runtime errors, fixes code & dependencies via LLM + MCP
Project description
๐ง pfix
Self-healing Python โ catches runtime errors and fixes source code + dependencies via LLM + MCP.
๐ก New in 0.1.5: Zero-configuration mode! Just
import pfixwithPFIX_AUTO_APPLY=truein.envand any exception triggers automatic repair.
Features
- 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
Installation
From PyPI (Users)
pip install pfix
# With MCP server support
pip install pfix[mcp]
# With git auto-commit
pip install pfix[git]
# Everything
pip install pfix[all]
From Source (Developers)
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.
Running Examples
After installation, examples can be run from any directory:
# From project root
cd /path/to/pfix/examples
python demo_auto.py
# The .env file in project root is automatically found
Quick Start (3 Ways)
Option 1: Zero Configuration (Recommended)
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)
Option 2: Explicit Session Control
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}")
Option 3: Decorator (Per-Function)
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"]]
Usage Patterns
Pattern A: Development Mode (Interactive)
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
Pattern B: CI/CD Mode (Non-Interactive)
from pfix import configure
# Auto-apply everything, dry run for safety
configure(auto_apply=True, dry_run=True, create_backups=False)
import pfix
Pattern C: Library Mode (Specific Functions)
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()
Library Behavior
How It Works
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 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 Types & Fixes
| 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(): |
Confidence Thresholds
- > 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)
CLI
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 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)
MCP Integration
pfix exposes tools via FastMCP for IDE integration:
| Tool | Description |
|---|---|
pfix_analyze |
Analyze error โ diagnosis + fix proposal |
pfix_fix |
Analyze + apply fix (with backup) |
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 |
Claude Code / VS Code setup
Add to your MCP config (.claude/mcp.json or VS Code settings):
{
"mcpServers": {
"pfix": {
"command": "python",
"args": ["-m", "pfix.mcp_server"]
}
}
}
Configuration
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()
Configuration Priority
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
Method 1: .env (Recommended for Development)
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/).
Method 2: pyproject.toml (Recommended for Projects)
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
Method 3: setup.cfg (Legacy Projects)
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
Method 4: setup.py (Legacy Projects)
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.
Method 5: Programmatic Configuration
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",
)
# Now import pfix to activate with these settings
import pfix
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 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.
# .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 |
Ollama (Local - Free, Private)
Run models locally for zero cost and complete privacy.
Setup:
# Install Ollama: https://ollama.ai
# Pull a code-capable model
ollama pull codellama:7b
ollama pull qwen2.5-coder:7b
ollama pull deepseek-coder:6.7b
Configure 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 |
OpenAI
# .env
PFIX_MODEL=gpt-4o
PFIX_API_KEY=sk-...
PFIX_API_BASE=https://api.openai.com/v1
Models: gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo
Anthropic (Direct)
# .env
PFIX_MODEL=anthropic/claude-3-sonnet-20241022
PFIX_API_KEY=sk-ant-...
Models: claude-3-opus, claude-3-sonnet, claude-3-haiku
Azure OpenAI
# .env
PFIX_MODEL=azure/<your-deployment-name>
PFIX_API_KEY=...
PFIX_API_BASE=https://<resource>.openai.azure.com
Google Vertex AI / Gemini
# .env
PFIX_MODEL=vertex_ai/gemini-1.5-pro
# or
PFIX_MODEL=gemini/gemini-1.5-pro
Choosing a Model
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)
Advanced Usage
Custom Error Handlers
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():
...
Async Support
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()
Session with Custom Config
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()
Examples
See examples/ directory for working examples:
demo_auto.pyโ Zero-config auto-healingdemo.pyโ Explicit session controlREADME.mdโ Examples documentation
Best Practices
- 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")
Troubleshooting
"LLM confidence too low"
- Increase context with
@pfix(hint="...") - Check your API key is valid
- Try a different model in
PFIX_MODEL
"Could not locate function"
- Ensure the error is in a named function (not
lambdaorexec) - Use
pfix_sessionfor module-level code
Backups filling up disk
- Set
PFIX_CREATE_BACKUPS=false - Clean
.pfix_backups/periodically:rm -rf .pfix_backups/
Too many restarts
- Set
PFIX_MAX_RETRIES=1to limit attempts - Use
PFIX_AUTO_RESTART=falseto disable restarts
Dependencies
| 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) |
License
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Licensed under Apache-2.0.
Apache 2.0 โ Tom Sapletta / Softreck
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pfix-0.1.21.tar.gz.
File metadata
- Download URL: pfix-0.1.21.tar.gz
- Upload date:
- Size: 49.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3ce4e5a643dab5a1592ed2142b175694a0c3bf0bf2e588f4d1512183260bd6a
|
|
| MD5 |
3e727ca5ba81b5413cceb7cf55910536
|
|
| BLAKE2b-256 |
e259bad0727738851ce932bef379fd1cf2b4b5b50724b539f97fa4e44b9c8ee5
|
File details
Details for the file pfix-0.1.21-py3-none-any.whl.
File metadata
- Download URL: pfix-0.1.21-py3-none-any.whl
- Upload date:
- Size: 36.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5901a61ac47e2cd804781d0c5be9b79929ca438a11fd296890a66f78150e0ab
|
|
| MD5 |
f7cc5c3e572826343b7fa9dabea60653
|
|
| BLAKE2b-256 |
46129e671b7ce2f864c9232f33eee39362fdff1919c08d9b061536763ca8bbf6
|