Software that files its own fix. With the safety built first.
Self-healing here means one specific thing. When your system crashes, a loop detects it, diagnoses it, proposes an exact code fix, reviews that fix adversarially, runs your full test suite against it, and then either commits it with a complete audit trail or rolls it back to a clean tree. You choose how much of that runs unattended. The cage below is what makes that choice safe.
Who this is for
You run an error tracker. We use Sentry; any tracker with an issues API works. You have a git repo with a test suite you actually trust. You can invoke an LLM agent from the command line with an enforceable tool whitelist. We use Claude Code; the pattern is agent-agnostic. And you have Slack, or any channel your team actually reads. If any of those are missing, build them first. This page will still be here.
Two registers. The main text teaches the pattern, which ports to any stack. Boxes like this one show our reference implementation: real numbers from our running system, so you can see one working instance. Our numbers are outputs of our environment. Tune yours.
Build the cage before the animal.
Most people ask what the AI can fix. The better first question is: what stops a bad fix from shipping? Every unattended commit this system makes must pass through all twenty-one of these. Skip one and you are not running this system. You are running a slot machine with push access.
| Guardrail | The rule | The failure it prevents |
|---|---|---|
| Full-suite gate | Every proposed diff runs your entire test suite before commit. Not a subset. | A fix that quietly breaks three other things. |
| Exact-diff-only writes | The only thing that can touch the repo is a reviewed, machine-materialized git diff. | "The agent improvised" is not in this system's vocabulary. |
| Read-only proposer | The diagnosing agent gets read tools only. Enforced by whitelist, not by prompt. | A helpful agent editing files mid-diagnosis. |
| Independent reviewer | A second, fresh agent tries to refute every proposal. Any error in review counts as a fail. | One model grading its own homework. |
| Two-strike breaker | Two consecutive failed or rejected proposals pause the whole loop until a human unpauses it. | A bad day becoming a bad week. |
| Per-issue cooldown | One attempt per issue per 24 hours. | The loop hammering the same wall all night. |
| Daily budget | At most 5 proposals a day, one undecided at a time. | Volume replacing judgment. |
| Regression watchdog | An auto-healed issue that returns within 7 days strikes the breaker. | Declaring victory on a symptom. |
| Kill switches | Independent flags shut down each layer. Remove the tracker key and everything is off. | Needing a deploy to stop the machine. |
| Notify-with-revert | Every unattended commit posts to your channel with the exact revert command. | Hunting through docs during an incident. |
| Audit lineage | Every transition writes an audit line. Every commit names its approver and the issues it resolves. | Archaeology instead of history. |
| Perimeter ratchet | A conformance suite derives coverage from the source: every scheduler heartbeats, every store is registered, every remediation is real. New code that skips coverage turns the suite red. | Coverage that erodes one new module at a time. |
| Severity ring | The executor inspects every diff's file paths. Anything touching money, clients, secrets, or deploy code demotes to a human click, at any trust tier. A conformance test keeps the protected list from rotting. | A "low-risk" label on a high-stakes file. |
| Grounded gating | Autonomy refuses to act when its own instruments are stale, blind, or unreadable. The human click path stays open. | Confident action on out-of-date sight. |
| Baseline aging | A pre-existing red test file is tolerated for 7 days, then it blocks unattended heals until a human fixes it. Going green resets the clock. | An emergency posture becoming a way of life. |
| Recurrence-to-test | The second heal of the same issue must pin a regression test, or it demotes to a human click. | False lessons compounding quietly. |
| Crash budget | More than 5 new error classes in a rolling 7 days drops the loop to propose-only for the rest of the window. Diagnosis keeps flowing. | Unattended patching during a storm that needs a human. |
| Escalation nag | An undecided proposal nags the channel at 48 hours, then daily. It runs even in fully manual mode. So does a paused loop: benched is a state someone hears about, not a state that goes quiet. | Proposals rotting in a queue nobody reopens. |
| Blocked-fix ceiling | An approved fix blocked on a busy working tree retries itself when the tree clears and nags daily while it waits. Past seven days it never silently applies. It asks again. | A week-old decision executing itself at 3am. |
| Red-team drill | Quarterly, plant fixes the loop MUST refuse: a money-path diff, a protected-file diff, a wrong diagnosis, a poisoned signal. Every gate has to fire, on the record, against isolated state. | A refusal gate that has never refused anything. |
| Surface admission exam | A new system joins the loop only by filling in a surface contract (scope, protected paths, test command, autonomy tier) and passing the red-team drill against that exact contract. | Copy-pasting the healer somewhere it has not earned. |
Tick what is true today. The dot resolves when you are actually ready, not when you feel ready.
Some stacks should not run this yet.
Your test suite is slow enough that you batch runs instead of running on every change. Or it is flaky, and a gate that lies is worse than no gate. Or coverage is thin exactly where the crashes happen. Or nobody reads the alert channel on weekends.
None of these are permanent. All of them are disqualifying today. A propose-only loop is still worth running while you fix them.
One real crash, walked through every gate.
Here is the morning of July 14 in slow motion. Six screens in our dashboard had been crashing for weeks, with six different error signatures. Every one traced to the same seam: a fetch wrapper that let a degraded server answer "success" with no data attached. Watch that one bug travel the whole loop.
The tracker catches every crash and groups them by signature. Three things make this layer trustworthy rather than noisy. Scrubbing: a before-send hook strips user data from every event, and session replay stays off. The scrubber is load-bearing; give it a regression test. Release stamping: every event carries version plus git sha, so "which commit broke this" is a lookup, not a hunt. Signal hygiene: security denials and expected noise stay in local audit logs. The tracker gets crashes only. Scheduled jobs post check-ins, so silence is itself an alert.
Our security layer once flooded the tracker with junk issue groups minted from routine denials. One mirror-filter regex ended the burn. Fix the generator, not the instances.
A poller pulls unresolved issues every 5 minutes, ranks them by event volume and recency, and renders a queue in our dashboard. The cache is stale-while-error: an API failure never wipes what you knew, it only marks it stale. Every issue deep-links back to the tracker. The queue is where a human, or later the loop itself, decides what gets attention.
A read-only agent gets the stack traces and one instruction that matters more than the rest: cluster stack-similar issues to one root cause. Six signatures, one seam, one proposal that names all six. The agent cannot write. Its whitelist has read tools only, so "read-only" is enforced by the runtime, not by the prompt. Its output is verbatim find-and-replace edits, never a diff. The server materializes those edits into a canonical git diff and restores the tree byte-for-byte.
Our first live proposal covered all six issues in one diff: two hunks, one file, at the shared fetch seam. Risk: low. The clustering instruction is why one morning closed six groups.
A second agent, fresh context, one job: try to refute the proposal. It reads the diff and every crash site, and hunts for the case where the fix makes things worse. It answers in line format, because a one-token verdict cannot be broken by a long string. And it fails closed: a parse error, a timeout, or an unreadable answer all count as a fail. Nothing ships on a mumble.
VERDICT: pass CONCERN: one endpoint still returns a bare object instead of the standard envelope CONCERN: callers that relied on the malformed shape will now see a clean failure REASONING: the guard normalizes bad GET envelopes to the standard error shape, which every crash site already handles.
The reviewer passed our fix and still raised real concerns. One became a tracked task. A reviewer that only says yes is decoration.
The executor is the only thing in the entire system that can write. It runs a fixed chain of gates. Passing every gate earns a commit. Failing any gate lands in the same place: a clean tree, nothing committed, the evidence kept.
- 1 · PreflightAre the diff's target files clean? A teammate editing the same file means wait, not strike.pass ↓fail ↳ wait
- 2 · Applygit apply the materialized diff. A diff that no longer applies stops here, tree untouched.pass ↓fail ↳ rollback
- 3 · Full suiteEvery test. Not the fast ones. Not the related ones. All of them.green ↓red ↳ gates 4 and 5
- 4 · Flake checkA failing file re-runs alone, with the diff still applied. Passing alone means a contention flake, tolerated within a small bound.flake ↓real red ↳ gate 5
- 5 · Baseline checkIs the suite red without the diff too? Then the main branch is broken, not the fix. Wait, do not blame the proposal.ours ↓baseline red ↳ wait
- 6 · CommitLineage trailers: who approved, which issues this resolves, the heal id.↓
- 7 · Push + resolveIssues resolve in the tracker with the sha attached. A regression rule reopens them loudly if the crash returns.↓
- 8 · NotifyThe channel gets the summary and the exact undo command. You are never more than one paste away from reversing it.done
heal: guard the GET envelope at the shared fetch seam
(resolves APP-9, APP-8, APP-A, APP-7, APP-B, APP-1P) [via error-queue]
Approved-By: heal-reviewer (auto, operator tier: low)
Heal-Id: fe3c740e
Sentry-Issue: https://yourorg.sentry.io/issues/APP-9/
The best thing this system did all week was refuse to ship.
What the loop said that day
Condensed from our alerts channel, July 14, 2026. Relative times shown where the exact minute is not in the log.
Four levels. Earn each one.
Do not build this in a weekend and flip everything on. Each level below is a complete, useful system on its own. Each ends with a gate you must witness in your own repo before moving up. The autonomy is not the achievement. The gates are.
Level 0 · Watch: detect and triage
needs: TRACKER_DSNWire the tracker with a scrubber and release stamping. Set two alert rules: first-seen and regression, both into your channel. Add check-ins to every scheduled job, so a job that silently stops running becomes an alert instead of a mystery. Then build the poller and the ranked queue.
const EVERY = 5 * 60 * 1000; // 5 minutes
setInterval(async () => {
try {
const issues = await tracker.listIssues({ status: 'unresolved' });
const ranked = issues
.map(i => ({ ...i, score: i.events / Math.max(1, hoursSince(i.lastSeen)) }))
.sort((a, b) => b.score - a.score);
cache.write({ issues: ranked, fetchedAt: Date.now() });
} catch (err) {
cache.markStale(err.message); // stale-while-error: never wipe what you knew
}
}, EVERY);
tracker.init({
dsn: process.env.TRACKER_DSN, // unset = the whole integration is off
sendDefaultPii: false,
release: `app@${VERSION}+${gitShortSha()}`, // "which commit broke this" is a lookup
beforeSend(event) { return scrubUserData(event); } // give this a regression test
});
Throw a deliberate error in production code. It must reach your channel in under a minute, scrubbed of user data, stamped with a release. Skip nothing until this works.
Level 1 · Diagnose: propose-only
adds: HEAL_LOOP=onSpawn a read-only agent against your ranked queue. Give it the stack traces, the repo, and the clustering instruction. Store its proposals in a queue with the cooldowns from the cage. Nothing writes anything yet. You read the diagnoses and apply the good ones by hand.
const proposal = await agent.run({
tools: ['Read', 'Grep', 'Glob'], // no Write, no Bash: it cannot touch the repo
cwd: REPO_ROOT,
prompt: buildPrompt(issueCluster), // traces + "cluster to ONE root cause"
timeoutMs: 15 * 60 * 1000,
});
// output contract, strictly validated:
// { summary, risk, resolvesIssues: [...], edits: [{ file, find, replace }], testPlan }
const diff = materializeDiff(proposal.edits); // server-side, below
function materializeDiff(edits) {
assertInsideRepo(edits.map(e => e.file)); // refuse absolute paths and ".." segments
const before = snapshotBytes(edits); // exact bytes, for the restore
try {
for (const e of edits) applyExactlyOnce(e); // find must match verbatim, exactly once
return git('diff'); // git writes the canonical, appliable diff
} finally {
restoreBytes(before); // the repo is untouched after this returns
}
}
Run it for a week minimum. Apply at least one proposed diff by hand, after verifying the diagnosis yourself. If the diagnoses are wrong, stay here. Wrong at L1 costs reading time. Wrong at L3 costs a bad commit.
Level 2 · Approve: human-gated commits
adds: AUTO_APPROVE=off · breaker + budgets liveBuild the executor with the full gate chain from the loop section. Add an approve and reject control on an exact diff view, with a double-confirm. The breaker, cooldown, and daily budget go live here. Every approval is a named human. Every transition writes an audit line.
async function applyProposal(p) {
if (dirtyTargets(p.diff)) return wait('someone is editing these files');
if (!gitApply(p.diff)) return fail('diff no longer applies'); // tree untouched
const suite = runFullSuite();
if (!suite.green) {
if (isolatedPass(suite.redFiles, { withDiff: true }))
{ /* contention flake, tolerated within a small bound */ }
else if (!baselineGreen()) { rollback(); return wait('main is red without this diff'); }
else { rollback(); return fail('the diff broke the suite'); }
}
const sha = commit(p, { trailers: lineage(p) }); // Approved-By, issue links, heal id
push(); resolveIssues(p.resolvesIssues, sha);
notify(`Healed. ${sha}. Undo: git revert ${sha}`);
return ok(sha);
}
You have personally watched one red suite roll back to a clean tree with nothing committed. Trigger it on purpose with a deliberately bad edit if you must. Do not proceed on faith.
Level 3 · Unattend: reviewer-gated auto, low-risk only
adds: AUTO_APPROVE=low · regression watchdogAdd the adversarial reviewer between proposal and executor. The chain becomes: propose, review, and only a reviewer PASS on a low-risk proposal reaches the executor unattended. Medium and high risk still wait for a human click. The 7-day regression watchdog arms on every auto-healed issue. Every auto-commit posts notify-with-revert.
const text = await freshAgent.run({ tools: ['Read','Grep','Glob'], prompt: refutePrompt(p) });
const verdict = /^\s*VERDICT:\s*(pass|fail)\b/im.exec(text)?.[1];
const concerns = [...text.matchAll(/^\s*CONCERN:\s*(.+)$/gim)].map(m => m[1]);
if (!verdict) return { pass: false, error: 'unparseable review' }; // fail closed
return { pass: verdict === 'pass', concerns };
We ran the manual path first. Four things failed on our first live day, and each one became a permanent gate (see the museum below). Only after that, and an explicit operator decision, did we set AUTO_APPROVE=low. Never start at "all".
Two clean weeks at L2, plus the ladder contract in the governance section signed by whoever owns the repo. Then flip to low, not all. Revisit the tier after a week of unattended heals.
Separate appendix, separate switch: runtime actions (kick a wedged job, reload a config, clear a stale lock) run behind their own flag, off by default. Run supervised dry-runs before trusting it: ours caught an action that reported success while doing nothing (see the museum). Prefer firing a fresh, instrumented run of the job over restarting infrastructure, keep a 24 hour cooldown per action, and never point any of it at anything that moves money.
Nine failures we keep on display.
Every guardrail on this page exists because something real broke. The first four broke on our first live day. Three more arrived over the two days after, each in a place the first four could not reach. The last two never got the chance to break anything: we found them on purpose, by unplugging the system and timing the silence. Each is now a permanent part of the system. Steal the lessons without paying for them.
The corrupt patch
The first approved fix died at the apply gate: "corrupt patch at line 25." The agent had hand-written a unified diff and got the arithmetic wrong. Nothing shipped; the rollback held. Agents now output verbatim find-and-replace edits, and git itself writes the diff.
What it built: exact-diff-only writes
The verdict that broke JSON
The reviewer returned its verdict as JSON, and one long explanation string arrived unterminated. The parse failed, and fail-closed held: no commit. Verdicts moved to line format, where a one-token answer cannot be broken by a long sentence.
What it built: the fail-closed reviewer
The flake that killed a good fix
A reviewer-passed heal was rejected because one unrelated test file goes red under parallel load. It had done the same thing earlier that day, without any diff. The executor now re-runs red files in isolation with the diff applied. Genuine reds still roll back.
What it built: flake discipline inside the suite gate
The red that wasn't ours
A teammate's commit turned the main branch red while a heal was in flight. The loop blamed the proposal and burned a strike on someone else's bug. Now it checks the baseline: a suite that is red without the diff means wait, not strike.
What it built: baseline awareness
The day the loop went blind
The dashboard went behind a public tunnel, and bot noise turned one routine security event into thousands of tracker events a day. The error quota drained, and the tracker started rate-limiting real crashes at ingest. The loop looked green on every check while new crashes fell on the floor. Proven during a drill: the planted event never arrived.
What it built: a per-class throttle on every telemetry mirror, and a BLIND state the status page shows loudly
The regression that wasn't
The watchdog struck the breaker on an auto-healed issue that "came back." It had not come back. The resolve call to the tracker had silently failed, leaving the issue open with zero new events. The fix was two rules: resolve calls verify and retry, and the watchdog only strikes on new events after the heal, never on an open flag.
What it built: a watchdog that counts events, not labels
The heal that did nothing
The runtime-remediation layer shipped off by default, pending dry-runs. The dry-runs found why they exist: its restart action checked that a function existed, returned a success message, and acted on nothing. Flipped on in production, it would have logged "healed" forever while healing nothing. Remediations now do the thing itself, and a test asserts every action resolves to something real.
What it built: dry-runs as a mandatory gate, and the perimeter ratchet
The impostor heartbeat
We killed the dashboard on purpose to time the alarm. No alarm came. A forgotten second instance, started weeks earlier on a different port for an audit, was still running every scheduled job: checking in the "alive" monitor for a process that was dead, and double-posting the morning brief. Schedulers now arm only on the canonical port. Any other instance serves pages and stays dark, and says so in its log.
What it built: one-instance scheduling, and the blackout drill itself
The miss nobody heard
The tracker had recorded twenty consecutive missed check-ins on one monitor and told no one. That monitor's issue had been marked resolved, and every alert rule watched for new or returning issues, never for misses on a closed one. A dedicated rule now fires on every monitor-failure event, resolved or not. Re-timed after both fixes: process killed to miss declared in under ten minutes.
What it built: alert on the event class, not the issue state
A loop you can watch working.
A self-healing system invites a special kind of rot: everything looks green because nothing is checking. We added these four habits after the loop was already "done," because done and provable turned out to be different claims. They are what let this page say "confirmed" instead of "configured."
Build one status page where every claim binds to a live check. Each node of the loop, from ingest to commit, is colored by a real probe of the real thing: the token exists, the poller ticked, the alert rules are enabled, the queue store reads, the fleet of scheduled jobs has actually checked in. A node with nothing live to show is drawn in a neutral color and says so. It never pretends to be green. And give the verdict one state beyond live, stale, paused, and down: BLIND, for when the tracker is rate-limiting new events while accepting none. A loop that cannot see new crashes passes every other check while missing the only one that matters.
Ours runs fourteen checks behind one page. The two silent failure modes it watches hardest: a scheduler that has never checked in (silence never trips a staleness alarm, so absence itself is the signal, with a grace window of twice the job's own period), and a per-machine store that never got registered for auditing.
Quarterly, plant a harmless defect in a sacrificial file, commit it, and fire one real event. Then stand back and watch the whole chain earn its keep: the alert, the proposal, the adversarial review, the full suite, the commit with the revert command attached, the issue resolved. One button, owner-only. It refuses politely on a 24 hour cooldown, an in-flight heal, or a closed storm guard, because a drill that weakens a guard costs more than it proves. A safety system you have never watched fire is a rumor.
Our first full drill ran July 15: planted defect to healed commit, end to end, no human past the button. The drill checklist on the wiring page derives entirely from evidence that already exists, git history and the live queue, so it cannot drift from reality.
The fire drill proves the loop can heal. The red-team drill proves it can refuse: plant fixes the loop must reject, and verify every gate fires. A diff that touches a money screen. A diff that touches a protected security file. A diagnosis the evidence contradicts. A poisoned signal feed. Each one must be turned away at the specific gate built to catch it, on the record, against isolated state so the drill's own rejections never trip the live breaker. The result is a receipt, not a claim: a running check on the proof page that reads REFUSED 4 of 4, with a date. When that receipt is stale or missing, the check goes amber on its own. This same exam is how a new surface earns the loop: fill in its contract, pass the drill against it, and only then does the healer watch it. A guardrail you have never seen refuse something is a memory, not a guarantee.
Our first run refused all four, including the reviewer catching that a planted "fix" did not contain the guard its diagnosis claimed. Designing the drill found two ring gaps before it ever ran: money-facing frontend files and the security chokepoint chain were unprotected. The exam paid for itself before the first question.
The fire drill proves the loop can heal. The blackout drill proves the alarms can fire: kill the process on purpose, and time how long until something tells you. The whole monitoring stack rests on one assumption, that silence gets noticed, and that assumption is exactly the thing no green dashboard can prove. Ours failed its first blackout twice, in ways no amount of watching the healthy system would have found: an impostor instance keeping the heartbeat alive, and a tracker swallowing missed check-ins on a resolved issue (both in the museum above). Run it quarterly, alongside the fire drill. Detection should be a measured number, not an assumption.
Our measured gap after both fixes, process killed to miss declared: 9 minutes 59 seconds, against a 10 minute check-in window. The number gets re-measured every quarter.
Log it where you already learn. Every applied heal appends a short entry to the same feed your nightly review reads, so fixes become tomorrow's context instead of buried commits. A recurrence metric keeps the score honest: fixes that stuck are healed issues with zero new events since the commit.
Lessons become tests. Any failure whose root cause generalizes gets pinned as a conformance check in the suite, in the same commit that fixes it. Prose lessons fade. A red test does not.
The perimeter ratchet. The quiet failure mode of any monitoring system is the module added after it: a new scheduled job with no heartbeat, a new store outside the audits, a new telemetry stream without a throttle. So derive the perimeter from the source itself. A conformance suite walks the code and fails on any standing job that does not check in, any capture site outside the throttle, any store outside the registry, any remediation that does not resolve to a real action. Because the executor runs the full suite before every unattended commit, the loop refuses to heal on top of an uncovered perimeter. Coverage stops being a memory and becomes a property of the build.
Our ratchet's first audit caught three schedulers running with no heartbeat, one of them shipped the day before, plus one unregistered store. We proved the bite by planting a bare scheduler: the suite went red and named the file and the fix. That red is the guarantee.
What it costs. What it pays.
Agent tokens. Every heal is two agent runs: a proposer and a reviewer, minutes of runtime each. Cheap next to an engineer-hour, but not free.
Tracker plan realities. Alert rules and issue APIs are standard. Extras are not: budget for cron monitors if you want vendor-side check-in alerts, and treat vendor AI root-cause add-ons as optional. The loop is complete without them.
The discipline tax. A green, fast, trusted test suite is the entry fee, and it never stops being due. The loop amplifies whatever your suite is: rigor or noise.
Human time, early. The L1 and L2 weeks are real hours spent reading diffs. That reading is what buys the right to stop reading.
Our plan includes one active cron monitor; more run about $0.78 per month each (public Sentry pricing). The vendor's AI root-cause add-on answered 402 until budgeted. We link out to it and let the propose agent do the diagnosis.
Crashes triaged in minutes, not weeks. The 5-minute poll turns a crash into a ranked queue entry with the stack trace attached before anyone notices the symptom.
Silent-error debt stops compounding. Six of our screens crashed for weeks because nobody had a spare afternoon. One unattended morning ended all six.
Mornings become a log read. The channel tells you what crashed, what the loop proposed, what the reviewer thought, what shipped, and how to undo it. Two minutes, and you know. One velocity line keeps the trend honest: new crash classes versus last week, heals applied and regressed, and the median hours from proposal to commit.
The audit trail is free. Lineage trailers answer "what changed and why" forever, for every heal, without anyone writing a postmortem.
Who holds the keys.
Autonomy is a governance decision wearing a technical costume. Write this part down before you flip anything.
The ladder contract
- Name the owner. One human owns the repo's autonomy level. Not a team, not a rotation. A name.
- L0 to L1: the owner turns on proposals after the L0 gate passes.
- L1 to L2: the owner reads a week of diagnoses and signs off on their quality.
- L2 to L3: two clean weeks, and the owner has personally watched a rollback happen.
- Any incident: anyone on the team can flip the loop off, no permission needed. Turning it back on takes the owner.
What never gets automated
Money paths: billing, payouts, bank syncs. Schema migrations. Security configuration. Anything that talks to a customer. The loop fixes crashes. It does not do surgery. Ours will not even auto-restart a wedged job on a money path; those stay propose-only regardless of any flag.
And make the list a gate, not a memory. Ours started as policy; now the executor inspects every diff's file paths against the protected list and demotes any match to a human click, at any trust tier (the severity ring). A conformance test walks the codebase so the list cannot rot as new modules land. A rule the code does not enforce is a rule the code will eventually break.
The circuit panel
Every layer has its own switch. Shell environment beats the env file for these flags, so a supervised terminal can dry-run a level without changing the system's defaults.
| Flag | Effect |
|---|---|
| TRACKER_DSN removed | Everything off. The app boots identically without it. |
| HEAL_LOOP=off | Loop off. No proposals, no reviews, no commits. |
| AUTO_APPROVE=off | Default. Every diff waits for a human click. |
| AUTO_APPROVE=low | Reviewer-gated auto for low-risk proposals only. |
| AUTO_APPROVE=all | Any risk, unattended. We do not run this. Neither should you. |
| HEAL_AUTOPROPOSE=off | Default. Diagnosis waits for a human click. On: persistent top-ranked crashes spawn the read-only proposer on their own. Proposals only, never commits. |
| AUTO_HEAL=off | Default. Runtime restart actions propose only. A separate ladder with its own dry-runs. |
Tune our numbers to your suite
Every constant on this page is an output of our environment. Our full suite is 2,200+ tests and finishes in about a minute, so 5 proposals a day is cheap for us. If your suite takes an hour, your budget is different and your cooldowns are different. Copy the gates. Do not copy the constants.
And the last line of the contract: you own this loop, its commits, and its risk. This page is the map, not a warranty.
What mornings look like now.
The tracker is quiet, or it isn't. Either way the channel tells the story: what crashed overnight, what the loop proposed, what the reviewer thought, what shipped, and the one line that undoes it. You read for two minutes and start the day knowing.
The morning of July 14, ours read: one alert at 9:31, one proposal, one passing review, one green suite, six issues closed, one revert command nobody needed. We built the cage first. Then we let it run.
Building your own second brain?
Write us what you are wiring up and where it fights you. We answer operator to operator.
Write to us See what we build