selfheal-sdk
AI self-healing decorator for any Python data pipeline.
When your pipeline raises an exception, @healed classifies the failure, applies a fix automatically, and escalates to humans only when genuinely needed.
Built by Sahil Deol
Install
pip install selfheal-sdk
With AI backends (recommended):
pip install selfheal-sdk[typesafe] # TypeSafe JEV — best classification
pip install selfheal-sdk[anthropic] # Claude Haiku fallback
pip install selfheal-sdk[ollama] # Ollama local LLM fallback (needs openai pkg for compat API)
pip install selfheal-sdk[all] # everything
No extras? Zero-dep keyword fallback always works out of the box.
Quickstart
from selfheal import healed
@healed(pipeline="daily_sales_etl")
def run():
records = extract()
validate(records) # raises? selfheal catches and heals it
cleaned = transform(records)
load(cleaned)
if __name__ == "__main__":
run()
That's the only change needed.
How it works
When run() raises, @healed does this:
- Classify — sends the error + traceback to TypeSafe JEV (or fallback LLM). Returns
failure_type,action,confidence,severity. - Threshold check — auto-heals only when
confidence ≥ 0.65ANDseverity ≤ 3. - Act:
| Failure type | Action | Auto? | Hook needed |
|---|---|---|---|
| BAD_DATA | QUARANTINE | ✅ | run_quarantine() |
| TRANSIENT | RETRY | ✅ | none |
| SCHEMA_DRIFT (new col) | ADD_COLUMN | ✅ | add_columns_to_dest() |
| PERMISSION / CODE_DEFECT | ESCALATE | ❌ | human approval |
| High severity (≥4) | ESCALATE | ❌ | human approval |
- Report — best-effort POST to your dashboard if configured. Never blocks the pipeline.
API keys
The healer tries backends in order: TypeSafe JEV → Anthropic → Ollama (local) → keyword fallback.
export TYPESAFE_API_KEY=ts-... # TypeSafe JEV (recommended)
export ANTHROPIC_API_KEY=sk-ant-... # Claude Haiku fallback
# Ollama runs locally — no API key needed. Start with: ollama serve
Keyword fallback requires no API key and always works.
Decorator options
@healed(
pipeline="my_etl", # name in logs
server_url="http://localhost:8000", # optional dashboard URL
on_escalate=None, # sync callback(result) on ESCALATE
max_retries=1, # retry attempts before giving up
silent=False, # suppress INFO logs
retry_safe=False, # set True if pipeline is idempotent
retry_backoff_base=1.0, # backoff base seconds (exponential)
retry_jitter=0.25, # random jitter added to each backoff
send_source_code=True, # set False if code contains secrets
source_redactor=None, # optional fn(src) → redacted_src
)
def run():
...
Recovery hooks
Define these in the same module as your decorated function. selfheal calls them automatically.
BAD_DATA → run_quarantine()
@healed(pipeline="daily_sales_etl")
def run():
records = extract()
validate(records)
load(transform(records))
def run_quarantine():
records = extract()
clean = [r for r in records if r.get("customer_id") and r.get("amount", 0) > 0]
bad = [r for r in records if r not in clean]
log_bad_rows(bad)
load(transform(clean))
SCHEMA_DRIFT → add_columns_to_dest(cols, schema)
def add_columns_to_dest(extra_cols: list[str], actual_schema: dict) -> None:
with connect() as conn:
for col in extra_cols:
conn.execute(f"ALTER TABLE dest ADD COLUMN IF NOT EXISTS {col} TEXT")
conn.commit()
selfheal calls this before retrying, so the retry succeeds with the new column in place.
ESCALATE → on_escalate callback
def notify_slack(result: dict):
print(f"[ALERT] {result['root_cause']}")
@healed(pipeline="orders_etl", on_escalate=notify_slack, max_retries=3)
def run():
...
Environment variables
| Variable | Default | Description |
|---|---|---|
TYPESAFE_API_KEY |
— | TypeSafe JEV API key |
ANTHROPIC_API_KEY |
— | Anthropic Claude Haiku fallback |
SH_OLLAMA_BASE_URL |
http://localhost:11434/v1 |
Ollama API base URL |
SH_HEALER_OLLAMA_MODEL |
qwen3-coder:30b |
Ollama model for classification fallback |
SH_MIN_CONFIDENCE |
0.65 |
Minimum confidence to auto-heal |
SH_MAX_SEVERITY |
3 |
Max severity (1–5) to auto-heal |
Version history
| Version | Changes |
|---|---|
| 0.3.4 | Replaced NVIDIA NIM with local Ollama (qwen3-coder:30b) as the third fallback backend — no external API key required; configure via SH_OLLAMA_BASE_URL and SH_HEALER_OLLAMA_MODEL |
| 0.3.3 | Major hardening: PATCH_AND_RETRY permanently removed; normalize_decision() strict fail-closed gate (unknown types → UNKNOWN/ESCALATE, out-of-range confidence fails closed, "false" string → False); ALLOWED_FAILURE_TYPES frozenset; IDENTIFIER_RE SQL injection guard on ADD_COLUMN columns; keyword fallback reordered (PERMISSION/RESOURCE checked before TRANSIENT); BAD_DATA + SCHEMA_DRIFT from keyword fallback always advisory (safe=False); retry_safe=False idempotency guard; exponential backoff on all retries including first; latest exception propagated through retry loop; QUARANTINE/ADD_COLUMN escalate with diagnosis context (no module hooks); send_source_code / source_redactor source privacy controls; bool rejected for max_retries; async on_escalate rejected for sync functions at decoration time; backoff params validated at decoration time; max_retries=0 handled without UnboundLocalError; suppress_escalated_exception param; server_url=None default |
| 0.3.2 | PyPI release |
| 0.3.1 | README updated for PyPI |
| 0.3.0 | TypeSafe JEV primary backend; ADD_COLUMN auto-heal; max_retries; runbook ingestion; confidence + severity thresholds |
| 0.2.0 | Anthropic + NVIDIA LLM backends |
| 0.1.0 | Initial release — keyword fallback only |
selfheal-sdk — by Sahil Deol
Release files for selfheal-sdk 0.3.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| selfheal_sdk-0.3.5.tar.gz | 16.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| selfheal_sdk-0.3.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.9 kB
Release files / selfheal_sdk-0.3.5.tar.gz
| Download URL | selfheal_sdk-0.3.5.tar.gz |
|---|---|
| Size | 16.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3966723de174ce384abcea164430ef0bdf716a652783a9425fa19ced399808f4
|
|
BLAKE2b-256 checksum How to use checksums |
33506f754d38a946426fbadd98743e1c2833f8f463c48dab9a9c987b2b17fd02
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.8
|
Release files / selfheal_sdk-0.3.5-py3-none-any.whl
| Download URL | selfheal_sdk-0.3.5-py3-none-any.whl |
|---|---|
| Size | 15.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f9b66b1645f32d17e5a967456c93cbffaaa7efdc1e4db5c737b2e3e2f5598b0f
|
|
BLAKE2b-256 checksum How to use checksums |
c03c4faf2b38bf24c78b2089f15c22db9c8de69786d06f283fdc8ff722e7cea6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.8
|