Guard · Auto-remediation

Verify a remedy, then watch the recovery

RepoOps scopes a case into a brief, builds the fix as a pull request in your own checkout, verifies it five ways, and waits for your decision on the case's Fix section. A merged fix is not a recovered service: the merge opens a recovery window on the merged digest, and a rollback is recorded against it. Nothing merges without you unless you arm the auto-remediation switch for a class of fix.

For: the engineer who owns a repository's findings, and the owner who sets its build policy

What it does, and why it helps

On the local Remediation page, environment, service and time narrow the case evidence for approved digests, recovery, reproducer findings, and scoping and building costs. Resolved cases remain available for recovery review. Action bands, plans and policy settings still cover the repository. Validation logs, staged packages and machine refusal records name their broader scope beside the result; a case filter does not narrow those stores.

A case opens from a security finding, an agent incident or a production incident. The scoper turns it into a brief that names the files a fix may touch. The builder runs your own Claude Code command line in the repository checkout and opens a pull request. The verifier runs five checks against that pull request: it builds, the tests pass, the new regression test fails on the introducing commit and passes on the fix, the guard replays, and the pull request's own CI is green. A missing check counts as a failure, a check that did not run reads did not run, and a check whose CI is still pending waits rather than recording a miss. Reproduction and remedy are one check here, the regression test run both ways; this page has no separate check that legitimate work still behaves, beyond the repository's own tests. The Remediation page lists the fix in the band Waiting for you, and the decision is taken on the case's Fix section.

The Fix section reads Brief, Root cause, Files, Done means, Not in scope, Build and Pull request (with its diff size, such as diff +12 -3), then Verification: the build's five checks plus three a person records (reproduction, deployment, observation-window), each pass, fail, did not run or not applicable, where a pass needs an evidence pointer. Approval reads No approval recorded until an approval binds to the exact patch and target. Approve: verify again, then merge re-runs the whole bar on the server at the moment of the merge, writes the lesson before the merge so the reversible step lands first, and records a receipt with the digest, who decided, and the pull request head it verified. The lesson is admitted to the brain only on a person's review in the Prevention section. Reject: close the pull request, discard the guard and the lesson needs a reason, and the reason travels back to the scoper and the builder.

The merge opens a Recovery window bound to the merged digest, 24 hours by default (1 to 336). It reads Watching <digest> until <time>, then Elapsed or Rolled back, with what was recorded inside it: checks, guard runs and recurrence decisions. When nothing was recorded, it says Nothing was watched inside it; silence is not a clean run. A deployment made elsewhere can be recorded by a person to open a window. Record rollback takes the digest now in the environment, a reason and an optional pointer to the revert; RepoOps records the rollback and does not push a revert. The window is bound to a digest, not to a named service or release.

The hosted Remediation page separates the outcomes: Unverified builds (no verdict recorded), Needs attention (failed verification) and Verified fixes (all five checks passed), with Refusals listed on their own, so a fix a gate refused is not read as a fix nobody tested. The desktop page shows checks passed or checks failed per band. The whole loop is off until you arm its schedules, and merging without you is off until you press the switch.

On a hosted case, an owner or admin can approve the build from the Fix section once a desktop has pushed a digest that passed all five checks. Approve the build starts filled with that digest, and Approve the build at this digest records an approval bound to it. An approve that names no digest while one is on record is refused, and so is one naming a different digest: the branch moved after verification, so verify again on the desktop.

The pain. A finding sits in a list. Someone has to reproduce it, write the fix, prove the fix, arm something that stops it coming back, and remember why. The proof is the part that gets skipped.

The point of view. A fix should arrive with its evidence, and the person who approves it should be re-checking evidence rather than producing it. Verify on the introducing commit and on the fix, before anyone merges, and let the merge write the lesson.

What gets easier. Deciding. The card shows the brief, the diff summary from the real pull request files, the five checks with each miss named, the guard and where it came from, and the lesson the merge will write.

When it helps. A security finding, an agent incident or a production incident that maps to a bounded change in one repository, on a machine that has the Claude Code command line installed and a repository credential the gate can use.

Its limits. It does not merge without the switch. It does not roll back a merged fix; git does. A fix whose checks failed still appears in the queue, with the misses shown, so you can reject it with a reason. The scoper makes one model call per case on your key, and the builder is your own local agent, so a case needs a brief the scoper could ground.

Understand it in 30 seconds

30.1 s, captions on. Narration: Microsoft Zira Desktop (provisional voice; an approved narration source is pending).Transcript
Read the narration
  1. 0:00 A fix arrives as a pull request. Nobody has proved it yet.
  2. 0:06 Five checks run first.
  3. 0:08 The new test fails before the fix and passes after.
  4. 0:13 Open the Fix section: the diff, each check, and the approval record.
  5. 0:17 Approve runs every check again before the merge.
  6. 0:23 A merge is not recovery.
  7. 0:25 The case keeps a recovery window and the rollback on record.

Synthetic example. Read the guide

Where to find it

Where to find it

  • Desktop: localhost:4000, then Remediation, one of the six primary pages in the sidebar.
  • Hosted: repoops.ai/team/remediation, from Remediation in the sidebar.
  • Keyboard: ⌘ K, then type “Remediation”.

When to use it

A high-severity finding with a known fix shape

Situation. The session detectors flag an over-broad CORS allowlist on the checkout route. The floor is high, the daily cap is the default, the schedules are armed, and the switch is off.

What you do. Open the case from Waiting for you. Read the brief and the diff summary. Press Approve: verify again, then merge. Enter your name for the record and the machine's operator confirmation.

What you see. Five check chips read pass. The guard source reads catalog-rule, the detector's own pattern. The receipt records the digest, who decided, the pull request URL and the head it verified. The lesson id and the guard id sit on the case.

What it establishes. The fix is merged and the lesson is in lessons.jsonl and the managed block of CLAUDE.md. A merge receipt is not proof the defect cannot recur; recurrence is read from later captured sessions.

A built fix that failed one check

Situation. The builder opened a pull request, but the regression check failed: the new test did not fail on the introducing commit. The builder already retried once with the failure attached and stopped, with both attempts recorded.

What you do. Read the failed chip's reason on the card. Either push a correction to the branch and press Verify without merging, or press Reject with the reason in the required field.

What you see. The band row reads checks failed. The verdict lists the failing check and its reason. After a reject, the pull request is closed and the case records who rejected it and why.

What it establishes. Nothing merged. The diff, the guard and the lesson were discarded together, so no half of a fix survives. The reason reaches the scoper for the next brief.

Before you start

Supported versions
RepoOps desktop v0.3.1, the release this guide was read against. The builder needs the Claude Code command line installed on the machine that builds; the unattended ticks need the capture daemon running.
Where it runs
Local: the Remediation page (the scope bar's repository applies; environment, service and time do not, and the bar says so), the case's Fix section, and the Today next action Approve the fix for <case>, or reject it with a reason. Hosted: /team/remediation shows the published snapshot (case id, title, severity, state, the five-check verdict, scope and build cost, counts), opens a case's sections in place on the Fix section, and carries the switch and the class table for an owner or admin under Remediation policy, below the review queue and the home's cells. The snapshot panels take the repository only and say so. The hosted page never receives the diff, the prompt, the transcript or the finding body.
Permissions
A local decision takes your name for the record and this machine's operator confirmation. Under team rule a decision takes an approver credential (minted with scripts/approver-credential.mjs) and the role floor; the auto-remediation switch takes the owner role on a team machine.
Connections
A repository credential the merge gate can use, named in repos.config.json as an environment variable or the default credential. ANTHROPIC_API_KEY on this machine for the scoper's one call per case. Remediation publishing turned on in Settings if the team page should see the snapshot.
Plan
The loop itself has no plan gate; the pricing capability map has no remediation row. Seeing the snapshot on the hosted dashboard follows the hosted dashboard tiers.

Configure it

  1. Set the build floor and the daily cap.

    Remediation, the Build policy card: Auto-build floor (default high and critical) and Daily build cap (USD) (default 10), then Save policy. The floor decides which findings the loop may build unattended; the cap bounds what it may spend in a day, and 0 is a real answer that means nothing unattended spends today.

  2. Arm the schedules in the data directory's .env file.

    REPOOPS_AIR_OPEN_SCHEDULE=1 opens cases from findings on the hourly cycle, REPOOPS_ARL_SCOPE_TICK=1 writes briefs (three cases a tick), REPOOPS_ARL_BUILD_TICK=1 dispatches builds (three a tick, a twenty-minute runner). Each is off unless its value is exactly 1. Until the first is set, the Remediation tab says Nothing is opening cases yet.

  3. Decide what each class of fix may do on its own.

    On the Remediation tab, the table What the loop may do on its own has one control per class: build, ask or never. The auto level only appears once the switch below is on, and while it is off a stored auto reads as build.

  4. Decide a built fix.

    Open the case from Waiting for you, or from Today's Open the Fix section. The Fix section offers Approve: verify again, then merge; Verify without merging; and Reject: close the pull request, discard the guard and the lesson. Approve re-runs the five checks on the server and refuses if the branch moved since verification.

  5. Watch the recovery window after the merge.

    The merge opens it on the merged digest for 24 hours unless you set another length (1 to 336 hours). Record a check with an evidence pointer as production confirms the fix; a window with nothing recorded says silence is not a clean run. For a deployment made outside RepoOps, Open a recovery window records it by hand. If the fix is reverted, Record rollback keeps the digest, the reason and the pointer to the revert.

  6. Only then, consider the switch.

    Turn on auto-remediation asks who is pressing this and records it. With it on, classes set to auto merge when all five checks pass, up to five merges a day, and every unattended merge carries the receipt with the policy version. The team's switch is the ceiling over every bound machine.

  7. Narrow a repository if it needs less.

    Remediation, Build policy, the Narrow a repo disclosure: a stricter Floor, a smaller Cap share (USD), or watch only. Narrowing can only tighten the account policy, never loosen it.

SettingWhereA sensible choiceWhy it matters
autoBuildFloorRemediation, Build policy, Auto-build floorhigh and critical (the default)Below the floor a real finding waits in its own band instead of being built unattended.
dailyBuildCapUsdRemediation, Build policy, Daily build cap (USD)10 (the default), or 0 to stop unattended spendScope and build cost, including failed runs, count against it; a reached cap holds the next build with the reason cap-reached.
classesRemediation tab, What the loop may do on its ownbuild for classes you review every time, ask for ones you want a question first, never for ones that stay manualThe level is the answer to what the loop may do without you for that class.
autoMerge (the switch)Remediation tab, Turn on auto-remediationoff until a class has earned itOnly enabled true is on; it records who pressed it and when, and turning it off returns auto rows to build.
dailyAutoMergesstored policy, no desktop control5 (the default)The daily merge cap for unattended merges; the team's value is the stricter ceiling.
REPOOPS_ARL_BUILD_TICK, REPOOPS_ARL_SCOPE_TICK, REPOOPS_AIR_OPEN_SCHEDULEthe data directory's .env1 to arm each, unset to stopAny value other than the string 1 reads as off.
REPOOPS_AIR_CASE_MIN_SEVERITYthe data directory's .envhigh (the default)The severity a finding needs before the open schedule turns it into a case.
repos.<id>.autonomyRemediation, Build policy, Narrow a repo, watch onlywatch for a repository that should build nothingThe gate refuses before any cap arithmetic, and the Build it click refuses too.
ⓘ
To stop or undo
Four levers, each independent: press Turn off auto-remediation on the tab, which records who and when and returns auto rows to build; set the daily cap to 0; tick watch only for the repository; or unset the three environment flags. Rejecting a built fix closes its pull request and discards the diff, the guard and the lesson together.

What you should see

The normal case

Configuration. Floor high, cap 10, the three flags set to 1, the switch off, every class at build.

Expect. A high finding opens a case on the hourly cycle, receives a brief on the scope tick, builds on the build tick, and lands in Waiting for you with five check chips and a guard source.

Verify. The band row reads checks passed, the Fix section lists the five checks, and Today's next action names the same case. Approving re-runs the bar; the receipt names the head it verified, and the Recovery window row reads Watching with the merged digest.

Held below the floor or by the cap

Configuration. A medium finding under a high floor, or a day whose cap is already reached.

Expect. The case sits in Below the auto-build floor with its hold reason: below-floor, cap-reached or watch-only. Nothing builds and nothing spends.

Verify. The band note says to lower the auto-build floor under Build policy on this page to include it; the hosted snapshot counts the refusal. The Build it click on the case refuses with the same reason.

Verification fails, or the branch moved

Configuration. Any of the above, with a regression test that did not fail on the introducing commit, or a pull request whose head moved after verification.

Expect. The failed check records fail with its reason. The builder retries once with the failure attached, then stops with both attempts recorded. An approve on a moved head refuses with BRANCH_MOVED and asks for a fresh verification.

Verify. The band row reads checks failed and the verdict names the check. The refusal is on the case; the pull request is still open until you reject it.

Data and cost

What is captured
One case record per event, appended to the repository brain's incidents/cases/YYYY-MM.jsonl: the finding pointer, the brief, the diff summary, the five-check verdict, the scope and build cost, the decision and the receipt.
Who can see it
Local by default. With remediation publishing on, a gzipped snapshot goes to the team over the device token: at most fifty cases and twenty-five refusals, each a whitelisted copy (id, bounded title, severity, status, build state, timestamps, the verdict as state and reason, the costs, counts). Never the diff, the patch, the generated test, the prompt, the transcript or the finding body. The snapshot replaces the previous one per device and repository.
How long it is kept
Case files are read over a 24-month window. No retention knob shortens it and no purge route exists; see Delete below.
What leaves the machine
The scoper makes one call to Anthropic on your ANTHROPIC_API_KEY per case. The builder runs your local Claude Code command line, whose own traffic follows your account, with the repository token namespace scrubbed from its environment. The hosted snapshot is the only RepoOps egress, and only when publishing is on.
What it costs
Scope cost and build cost are metered per case from token counts and the model rate, including failed runs, and count against the daily build cap. The planner's own calls are capped at 25 a day per account.

When the result differs

SymptomLikely causeNext action
The tab says Nothing is opening cases yet.REPOOPS_AIR_OPEN_SCHEDULE is not set to exactly 1.Set it in the data directory's .env and restart the app.
A real finding waits in Below the auto-build floor.Its severity is under the floor, the day's cap is reached, or the repository is watch only.Lower the auto-build floor under Build policy on Remediation, wait for the next day, or untick watch only. Or press Build it on the case to build it by hand under the same gate.
Built, but the row reads checks failed.One of the five checks recorded a miss; a missing check counts as failed.Read the chip's reason. Push a correction and Verify without merging, or Reject with a reason.
Approve refused with BRANCH_MOVED.The pull request head moved after the verification the card shows.Press Verify without merging, then approve the fresh verdict.
The scoper reports not-configured.No ANTHROPIC_API_KEY on this machine.Add the key to the data directory's .env; the scoper makes one call per case.
The hosted Remediation page reads No desktop has published yet.Remediation publishing is off on the desktop, or no case has been built since it was turned on.Turn on remediation publishing in the desktop app's Settings, then wait for the next snapshot.
The Recovery window reads Nothing was watched inside it; silence is not a clean run.No check, guard run or recurrence decision was recorded against the merged digest during the window.Record a check with an evidence pointer from the production source, or open a new window after the next deploy. Do not close the incident on silence.
A rollback made on the hosted page did not reach the desktop.The hosted rollback record stays on the team; the desktop does not learn of it on its own.Record the rollback on the desktop case as well.
Disable
Any of the four levers above. Turning the switch off records who did it and returns every auto row to build unless another repository on the install still has the switch on.
Roll back
RepoOps does not revert a merged fix; revert it in git or in your deploy tool, then Record rollback on the case against its recovery window, with the digest now in the environment and the reason. The record is its own receipt and leaves the window it reverses unchanged. Before the merge, Reject is the only in-loop reversal and it discards the diff, the guard and the lesson together.
Revoke access
Approver credentials: node scripts/approver-credential.mjs revoke <actorId> (mint replaces the previous token in the same write; tokens are stored hashed). Device binding: disconnect in the desktop app forgets the binding and revokes the device token on the server. A repository token removed with DELETE /api/repos/<id>/credential leaves this machine's .env but is not revoked at GitHub.
Delete
Not provided. No route deletes a case's stored evidence; the file is the repository brain's incidents/cases/YYYY-MM.jsonl. On the hosted side the snapshot is replaced per device, so unbinding the device removes its rows.

Maintenance evidence

Feature id
auto-remediation (spine leaf remediation)
Owner
Remediation program (ARL-WS1 to ARL-WS6; the P7 validation contract, LDG-0690). Guide: LDG-0714.
Supported product version
RepoOps main at 509e8e8ad (after v0.3.2)
Last verified
2026-09-26, read again against origin/main at 509e8e8ad for the Fix section, the Verification row, Approval, Recovery window and Rollback (public/lib/case-sections.js, public/lib/fix-decision.js, lib/remediation/recovery-window.mjs), the hosted page's tiles, refusals and panel notes (website/app/team/(home)/remediation/page.tsx) and the scope bar (public/lib/scope-bar.js, lib/scope-bar-contract.mjs); not opened on a running instance this time. First read 2026-09-15 at b142b98d6, with the Settings and Remediation tab labels checked on an isolated instance (npm run start:verify).
Example fixtures
No fixture file; the case shapes are inline in lib/remediation/verdict-gate.test.mjs and lib/remediation/build-routine.test.mjs, which exercise approve, reject, the retry and the holds with every seam injected.
Source references
lib/remediation/tick-gate.mjs, lib/actions/planner-policy.mjs, lib/remediation/classes.mjs, lib/remediation/verdict.mjs, lib/remediation/builder.mjs, lib/remediation/build-routine.mjs, lib/remediation/scoper.mjs, lib/remediation-snapshot-publisher.mjs, lib/ai-incident-case.mjs, public/remediation.html, public/settings.html, public/lib/fix-decision.js, public/lib/case-sections.js, lib/remediation/recovery-window.mjs, website/app/team/(home)/remediation/page.tsx, public/lib/scope-bar.js
Documentation review
Revised 2026-09-26 by the authoring agent against the code (LDG-0988); independent review not yet recorded.
Video review
Narrated story rendered and published 2026-09-26 (render 5ee843c89384, LDG-0988), beside the desktop navigation with the six pages as they ship; it ends on a recovery window with nothing recorded, not on a green state. Six frames, the captions and the transcript were reviewed by the authoring agent, not an independent reviewer; the audio was not listened to by a person. Narration is the provisional Windows voice until LDG-0721.

Last updated