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
Metadata
Release files for lazarus-agent 0.1.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 | |
|---|---|---|---|
| lazarus_agent-0.1.0.tar.gz | 151.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lazarus_agent-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 189.9 kB
Release files / lazarus_agent-0.1.0.tar.gz
| Download URL | lazarus_agent-0.1.0.tar.gz |
|---|---|
| Size | 151.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a129db4052ae01841e44717b5d385de390fe72fa5face0ff6a8a2e52e0f90e3a
|
|
BLAKE2b-256 checksum How to use checksums |
bed5045267d6df92261c6268be65b48d175254b02df46c18828562cfe27df380
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|
Release files / lazarus_agent-0.1.0-py3-none-any.whl
| Download URL | lazarus_agent-0.1.0-py3-none-any.whl |
|---|---|
| Size | 38.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8442b26428aeca64146624104586bffa4b143aa877c6b48ae7d9594e97b2805c
|
|
BLAKE2b-256 checksum How to use checksums |
ab8caaa575bbbebe3f2367fc14c45e43ebcb2b31e772dabc57617fab4e46d709
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|