self-heal
Open-source self-healing helper for Python.
It captures tracebacks (in-process hook / decorator, or a supervised subprocess), gathers code context (the source around the failing frames plus, optionally, similar chunks from an embeddings index), asks an LLM for a unified diff, validates it against a path policy, optionally applies it with a backup, and records an audit trail.
Highlights
- Python
>= 3.11; works with OpenAI, Anthropic, Hugging Face and Ollama (any OpenAI-compatible endpoint for chat and embeddings) - Works without an index: the code around every traceback frame inside your project is always sent to the model; the vector index is an optional boost
- Bounded retries with feedback: an empty, rejected or unappliable patch is explained to the model and it gets another attempt (
heal.max_attempts) - Safety first: model output is never executed, unified diffs only, allow/deny path policy, file-type allowlist, dry-run by default, backups +
rollback, secrets masked before anything leaves the process - Operations:
doctorfor setup checks, JSONL audit log, notifications (Telegram, Slack, webhook, Sentry), supervised restarts that stop on repeated crashes
Contents
- Install
- Quickstart
- CLI
- Library usage
- Configuration
- Providers
- Notifications
- Security
- Limitations
- Development
- License
Install
pip install self-heal-runtime
# Optional: Sentry notifications
pip install "self-heal-runtime[notifications]"
Set the API key environment variable for your provider (OPENAI_API_KEY by default, see [llm].api_key_env).
Quickstart
-
Initialize config in your project root and check the setup:
self-heal init self-heal doctor
-
Index your code (optional, requires an embeddings endpoint):
self-heal index -
Heal from a traceback (dry-run: the diff is shown, nothing is written):
python -m examples.broken_app.main 2> tb.txt self-heal heal --tb tb.txt self-heal heal --tb tb.txt --apply # write it (a backup is kept) self-heal rollback # undo the last applied patch
-
Run under supervision (captures stderr tracebacks, proposes or applies a fix, restarts):
PYTHONPATH=. self-heal run -- python -m examples.broken_app.main PYTHONPATH=. self-heal run --auto -- python -m examples.broken_app.main # apply automatically
CLI
| Command | What it does |
|---|---|
self-heal init [--force] |
Write .self-heal.toml from the built-in template |
self-heal doctor |
Check config, API key, embeddings endpoint, index, git/patch, backups, notification env vars (exit 1 on failures) |
self-heal index [--force] |
Incrementally index Python files under [index].roots (--force rebuilds) |
self-heal heal [--tb FILE] [--apply] [--instruction TEXT] |
Generate a fix from a traceback (file or stdin); --apply writes it |
self-heal run [--auto] -- CMD... |
Supervise a command; heal on tracebacks; restart |
self-heal status [-n N] [--json] |
Recent audit entries |
self-heal rollback [--list] [--backup NAME] |
Restore files from a backup taken before a patch was applied |
--apply / --auto imply --no-dry-run; pass --dry-run explicitly to keep a dry run. Use -v for debug logging and -q for warnings only. -p PATH selects the project root (default: the directory containing .self-heal.toml, found by walking up from the current directory).
Library usage
from pathlib import Path
from self_heal import heal_context, install, self_heal
# Global hooks (sys.excepthook and threading.excepthook); previous hooks still run first.
install(project_root=Path(__file__).resolve().parent, mode="suggest")
@self_heal(retries=2, mode="suggest") # sync or async functions
def risky() -> None:
do_work()
with heal_context(mode="suggest"):
risky()
Modes: suggest only proposes (audit + notifications), apply follows [heal].auto_apply, auto always applies. The same error (exception type + raise site) is not sent to the model again within [heal].cooldown_s.
Lower-level entry points: heal_exception(ErrorEvent), heal_from_traceback_text(str), capture_from_exception(exc), rollback(project_root).
Configuration
See .self-heal.example.toml (the same template is written by self-heal init). Unknown keys are rejected so typos never silently disable an option.
| Section | Key options |
|---|---|
[llm] |
provider, base_url, model, api_key_env, embedding_model, embedding_base_url / embedding_api_key_env (separate embeddings endpoint), timeout_s, max_tokens, max_retries, temperature |
[index] |
roots, exclude, respect_gitignore, chunk_max_lines, chunk_overlap_lines |
[heal] |
allowed_paths, forbidden_paths, allowed_extensions, auto_apply, max_attempts, backup, top_k, context_lines, max_diff_lines, cooldown_s |
[supervisor] |
restart_on_exit_codes, max_restarts, healthcheck_grace_s, stop_on_repeated_traceback |
[notifications] |
enabled, events, include_diff, include_traceback, max_traceback_lines, plus `[notifications.telegram |
Providers
[llm].provider selects how chat completions are issued. Embeddings always use an OpenAI-compatible endpoint: by default the same base_url, or embedding_base_url when set.
-
OpenAI (default):
[llm] provider = "openai" base_url = "https://api.openai.com/v1" model = "gpt-4o-mini" embedding_model = "text-embedding-3-small" api_key_env = "OPENAI_API_KEY"
-
Anthropic: native Messages API. Anthropic has no embeddings API; healing still works with traceback context, and you can point embeddings elsewhere to enable the index:
[llm] provider = "anthropic" base_url = "https://api.anthropic.com/v1" model = "claude-sonnet-4-5" api_key_env = "ANTHROPIC_API_KEY" embedding_base_url = "http://localhost:11434/v1" # e.g. Ollama embedding_model = "nomic-embed-text" embedding_api_key_env = "OLLAMA_API_KEY" # unset is fine for Ollama
-
Hugging Face (Inference Providers router):
[llm] provider = "huggingface" base_url = "https://router.huggingface.co/v1" model = "meta-llama/Llama-3.1-8B-Instruct" embedding_model = "intfloat/multilingual-e5-large" api_key_env = "HF_TOKEN"
-
Ollama (local, no auth):
[llm] provider = "ollama" base_url = "http://localhost:11434/v1" model = "llama3.1" embedding_model = "nomic-embed-text"
Changing embedding_model rebuilds the index on the next self-heal index.
Notifications
Optional outbound reports when an error is captured and when a heal is proposed, applied, rejected or rolled back. Enable [notifications].enabled = true, then turn on channels under [notifications.telegram], [notifications.slack], [notifications.webhook] or [notifications.sentry]. Secrets stay in environment variables (TELEGRAM_BOT_TOKEN, SLACK_WEBHOOK_URL, SELF_HEAL_WEBHOOK_URL, SENTRY_DSN).
- Payload: diffs are omitted by default and tracebacks truncated (
include_diff,include_traceback,max_traceback_lines) - Telegram:
HTML,MarkdownV2or plain text; messages are kept within Telegram's size limit - Webhook: JSON POST with optional HMAC (
X-SelfHeal-Signature: sha256=…,X-SelfHeal-Timestamp); onlyhttpsand public hosts unlessallow_insecure = true - Sentry:
pip install 'self-heal-runtime[notifications]'
Delivery is asynchronous; successes and failures are written to .self-heal/audit.jsonl as notification_sent / notification_failed.
Security
- Model output is never executed; only unified diffs are accepted, and only for files matching
allowed_paths/allowed_extensionsand notforbidden_paths(defaults block.git/,.env*, secret globs,pyproject.toml). Paths are normalised and resolved;.., absolute paths and symlinks escaping the project are rejected. Deletions and binary patches are refused. - Tracebacks and locals are sanitized before leaving the process: variables with secret-looking names, values of secret-looking environment variables, bearer tokens, API keys, JWTs and URL credentials are masked.
- The CLI is dry-run by default; every applied patch is preceded by a backup under
.self-heal/backups/and can be undone withself-heal rollback. - Supervised runs stop restarting when the same crash repeats without a patch; in-process healing has a cooldown so a crash loop cannot flood the model.
Limitations
- Patch application prefers
git apply(inside any git worktree), then the systempatch, then a small atomic Python hunk applier. - Only Python files are chunked and indexed;
allowed_extensionscontrols what a patch may touch. - Supervised mode expects Python-style tracebacks on stderr.
- Applied patches change files on disk; a running process keeps its already-imported code until restarted.
Development
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
ruff check . && ruff format --check . && mypy && pytest
Tests do not need network access or API keys. See CHANGELOG.md for release notes.
Releasing: bump version in pyproject.toml, update CHANGELOG.md, then push a matching tag (git tag v0.4.0 && git push origin v0.4.0). The Publish to PyPI workflow builds the package and uploads it with PyPI Trusted Publishing.
License
MIT — see LICENSE.
Metadata
Release files for self-heal-runtime 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| self_heal_runtime-0.4.0.tar.gz | 56.2 kB | With provenance | Details for self_heal_runtime-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| self_heal_runtime-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for self_heal_runtime-0.4.0-py3-none-any.whl |
Total release size: 124.4 kB
Release files / self_heal_runtime-0.4.0.tar.gz
| Download URL | self_heal_runtime-0.4.0.tar.gz |
|---|---|
| Size | 56.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d96a7278716dd9b53d81ea1d144f02b85ac3e11292bcb53b625a96c2ee9f4b6a
|
|
BLAKE2b-256 checksum How to use checksums |
ccf83cbc5f3914b143d3f15add9afbc9febc68ba32880f135c2e0c04005b5eed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logRelease files / self_heal_runtime-0.4.0-py3-none-any.whl
| Download URL | self_heal_runtime-0.4.0-py3-none-any.whl |
|---|---|
| Size | 68.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e96ee47e0ba04d5c8c457d8cdd754b3fb5bc1f0cc0808499e92d86590d6b93ec
|
|
BLAKE2b-256 checksum How to use checksums |
88d9bdc6e7ee542ef07100877c895451ba14251c16a99b06e4b57c7deddbef0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logSecurity for self-heal-runtime 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for self_heal_runtime-0.4.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.