Self-healing runner for Python projects: catches crashes, remembers them, and patches them on the fly with a headless Claude agent.
Project description
Lazarus
Self-healing runner for Python. Run your app under it; when the app crashes, Lazarus captures the full incident (traceback, locals, source context), stores it in a per-project SQLite memory, hands it to a headless Claude agent that reads the code — and past related incidents — patches the root cause, and then restarts (or hot-reloads) to verify the fix held.
Zero runtime dependencies (stdlib only). Needs Python ≥ 3.11 and the
claude CLI for healing.
Built by AJTheDev — a North London developer. If Lazarus saves you a 2am debugging session, say hi.
Install
pip install lazarus-agent
Or from source:
git clone https://github.com/AlexJamesDean/lazarus
pip install -e lazarus
(Stdlib-only, so it installs into any venv.)
Per project
cd my-new-project
lazarus init # writes lazarus.toml, creates .lazarus/, gitignores it
lazarus run app.py # or: lazarus run -m mypackage.server
That's it. The loop:
- Run — your program runs as a child process with a crash-reporting hook,
breadcrumb capture (last output lines + log records), and — for batch jobs —
an optional dead-man timer (
max_runtime) that catches hangs and deadlocks by dumping every thread's stack. - Capture — an unhandled exception writes a structured report: frames,
code lines, local variables, breadcrumbs, fingerprint. When the failing
call's arguments are serializable, the crash is frozen into a permanent
regression test in
.lazarus/repro/(crash-to-test). - Remember — the incident lands in
.lazarus/lazarus.db. Recurrences of the same fingerprint bump a counter instead of duplicating. Related past incidents are recalled by fuzzy token similarity (not just exact type/file match), and verified fixes from your other projects are pulled from the hive (~/.lazarus/hive.db). - Heal — a headless
claude -pagent (Read/Edit/Grep/Glob, plus WebSearch for library errors) patches the root cause with the smallest safe change. A per-attempt model ladder (models = ["haiku", "sonnet", "opus"]) starts cheap and escalates. Implicated files are backed up to.lazarus/backups/first, and the resulting diff is stored with the attempt. Withheal_clones = truethe agent also greps for the same bug pattern elsewhere and patches the siblings. - Gate — before a patch counts, the canary runs: your
test_commandplus every captured repro test. A patch that breaks the tests is marked failed immediately and the next attempt is escalated. - Verify — Lazarus restarts the program. Clean exit, a long healthy run
(
verify_seconds), or even a different crash => the fix is verified, recorded in the hive, and written up in the patchlog (.lazarus/PATCHLOG.md) — root cause, fix summary, and diff. The same crash => the attempt is marked failed and the next heal is escalated with the failed diff ("this was tried; it didn't work"). Aftermax_attemptsfailures on one error it gives up and tells you.
Transient-looking exceptions (ConnectionError, TimeoutError, ...) get one
free backoff-retry before any healing — no code patches for a flaky network.
Healing without a restart
For long-running services where a restart is unacceptable, guard the hot path:
from lazarus import guard
@guard # or @guard(retries=2)
def handle_request(payload):
...
When the function raises, Lazarus heals in-process, importlib.reloads the
patched module, and retries the call with the same arguments. (Functions
defined in __main__ can't be reloaded — the patch still lands on disk, and
lazarus run covers those via restart instead.)
Inspecting the memory
lazarus errors # every incident: status, hit count, location
lazarus show 3 # full traceback + every fix attempt with its diff
lazarus hive # verified fixes shared across ALL your projects
Config (lazarus.toml)
| key | default | meaning |
|---|---|---|
model |
sonnet |
model for healing (haiku for cheap, opus for hard) |
models |
[] |
per-attempt escalation ladder; overrides model |
max_attempts |
3 |
fix attempts per distinct error before giving up |
max_turns |
25 |
agent turn cap per heal (cost control) |
verify_seconds |
30 |
survival time that counts as "fix verified" |
restart |
auto |
never = patch once, don't relaunch |
allow_web_search |
true |
let the healer search the web for library errors |
allow_bash |
false |
let the healer run shell commands |
heal_timeout |
600 |
seconds before a heal is aborted |
catch_threads |
true |
uncaught thread exceptions count as crashes |
breadcrumbs |
true |
capture recent output + log records for the healer |
test_command |
"" |
canary command a patch must pass (e.g. pytest) |
test_timeout |
120 |
seconds before the canary command is killed |
repro_tests |
true |
freeze crashes into regression tests |
repro_dir |
.lazarus/repro |
where generated repro tests live |
transient |
[Connection…, Timeout…] |
exception types that get a free retry |
transient_backoff |
5 |
seconds to wait before the free retry |
max_runtime |
0 |
dead-man timer for batch jobs; 0 = off (servers) |
hive |
true |
share verified fixes across projects |
heal_clones |
false |
also patch the same bug pattern elsewhere |
patchlog |
.lazarus/PATCHLOG.md |
postmortem journal of verified fixes |
protected |
[] |
files the healer must never edit |
healer |
claude |
or any shell command (see examples/fake_healer.py) |
claude_path |
— | explicit path if claude isn't on PATH |
Safety rails
- Per-error attempt cap — no infinite patch/crash loops.
- Pre-heal backups of implicated files in
.lazarus/backups/incidentN-attemptM/. - Every attempt's diff is stored;
lazarus showmakes the agent auditable. - The healer gets no Bash by default and is told never to touch
.lazarus/,lazarus.toml, or anything inprotected. - Non-Python deaths (segfault, OOM kill) are reported, never "healed".
Browser bridge (Lazarus Bridge extension)
Instead of (or alongside) the healer's own WebSearch, Lazarus can research
through your browser. Load extension/ as an unpacked extension
(chrome://extensions → Developer mode → Load unpacked). While lazarus run
or lazarus bridge is up, the extension long-polls 127.0.0.1:8377 and:
- researches crashes — searches the web and opens the top results in
background tabs (your active tab, and your video, are never touched),
extracts each page to markdown with a bundled defuddle
build (fallback extractor included), saves it under
.lazarus/research/incidentN/, cites it to the healer, then closes its tabs. - lets you clip pages — the popup's "Clip this page for Lazarus" button
saves whatever you're reading into
.lazarus/research/clips/, and clipped pages ride along into the next heal prompt. See a relevant GitHub issue? One click and the healer has it. - gives Lazarus a voice — with
personality = "roast", Lazarus checks what you're watching when the crash lands, roasts you for it via chrome.tts ("Do not pause Never Gonna Give You Up on my account. One of us has a stack trace to read."), announces fixes out loud, and sends a desktop notification with the fix summary. The Claude healer is asked for a bespoke ROAST: line; canned lines cover token-free backends.deadpankeeps the spoken status updates and drops the jokes; the popup has a mute toggle.
The bridge binds localhost only. No extension connected simply means research
and speech are skipped. examples/fake_browser.py speaks the same protocol
for token-free testing and doubles as protocol documentation.
Troubleshooting
heal failed: ... 401 Invalid authentication credentials— theclaudeCLI's own login is stale (it authenticates separately from the desktop app). Runclaude loginonce in a terminal.- Lazarus can itself be launched from inside a Claude Code session: it strips the session-scoped auth environment before spawning the healer, so the nested CLI authenticates like a normal terminal launch.
Try the demo
cd examples
lazarus run buggy.py # crashes with KeyError, heals itself, reruns clean
lazarus errors
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 lazarus_agent-0.1.0.tar.gz.
File metadata
- Download URL: lazarus_agent-0.1.0.tar.gz
- Upload date:
- Size: 151.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a129db4052ae01841e44717b5d385de390fe72fa5face0ff6a8a2e52e0f90e3a
|
|
| MD5 |
527b166dc40b8495cee20e83806516c2
|
|
| BLAKE2b-256 |
bed5045267d6df92261c6268be65b48d175254b02df46c18828562cfe27df380
|
File details
Details for the file lazarus_agent-0.1.0-py3-none-any.whl.
File metadata
- Download URL: lazarus_agent-0.1.0-py3-none-any.whl
- Upload date:
- Size: 38.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8442b26428aeca64146624104586bffa4b143aa877c6b48ae7d9594e97b2805c
|
|
| MD5 |
f3ade87f336c17f2ca0746d416eb85ed
|
|
| BLAKE2b-256 |
ab8caaa575bbbebe3f2367fc14c45e43ebcb2b31e772dabc57617fab4e46d709
|