/gaia-residue
/gaia-residue goes through the trade-offs reviewers accepted when a pull request merged, instead of fixing them. GAIA calls these residue. You decide what happens to each one. The command never changes code.
It runs like every maintenance command: from the main checkout, on a branch of its own, ending in one pull request. Only you start it, by typing it; Claude never runs it on its own.
Why it helps
Section titled “Why it helps”Accepting a trade-off at review keeps a pull request moving, but a trade-off nobody looks at again is quietly forgotten. Filing every one as an issue would bury the backlog instead. /gaia-residue sits between the two: each accepted trade-off is recorded, and once it is old enough you decide once whether it still matters, so only the ones worth fixing become tech debt.
What a residual is
Section titled “What a residual is”When the Code Audit Team clears a pull request, some findings are not fixed. A reviewer can accept one as a known trade-off, or let one pass because it is outside the change, in a file the pull request already touches. These are not lost: as Tech debt explains, each one is written into the merged pull request’s description, under ## Accepted residuals (recorded, not fixed) or ## Out-of-scope machinery findings (recorded, not filed), with a key that keeps it from being counted twice. Each entry is a residual.
/gaia-residue reads those entries back and asks you to decide each one:
- Dismiss (the default): the trade-off stands and needs nothing more.
- Keep: snooze it. It comes back in 14 days (see Settings to change that).
- Promote: file it as a
tech-debtissue, so/gaia-debtcan fix it. Promoting should be the exception and needs a reason. Promoting too freely makes the backlog grow instead of shrink.
A dismissal or a keep is recorded in a committed file in .gaia/ (audit-residual-dismissals.jsonl), so your team shares the decisions. GAIA only ever adds to it; don’t edit it by hand. A promotion is recorded by the issue it files.
Aged and newer residuals
Section titled “Aged and newer residuals”A residual is aged once the pull request that recorded it merged 30 or more days ago. Only aged residuals count toward the statusline nudge. Newer ones are not shown until they reach 30 days.
When the nudge appears
Section titled “When the nudge appears”The statusline shows 🧹 /gaia-residue (N residuals) once 5 or more aged residuals are still open. “Open” means not already dismissed, kept, or promoted. On a narrow terminal the nudge shrinks to its icon, with a count of hidden nudges beside the row.
With 1 to 4 aged residuals the nudge stays hidden: too few to be worth a prompt.
Outside a run, the count refreshes every 6 hours, so a residual that just turned 30 days old can take up to 6 hours to show. A run refreshes the count as soon as it finishes.
What one run does
Section titled “What one run does”/gaia-residue takes no arguments.
- It reads the residuals from your merged pull requests, oldest first, in batches of 25 (see Settings to change that).
- For each one it shows the full description: how the reviewer recorded it, what could go wrong, the file and line it points to, and what that line says now. When the line it points to is gone, the residual is marked as probably already fixed and suggested for dismissal, but it still needs your answer.
- You answer Dismiss, Keep, or Promote. The answer the evidence supports is marked as recommended. Dismissals can be confirmed in one step for the whole batch. A promotion asks one more question for the severity, and whether the finding is security-sensitive.
- It keeps going, batch after batch and without asking, until no aged residual is left. With 26 or more aged residuals, a run takes more than one batch. It clears every aged residual instead of stopping once fewer than 5 are left, because stopping at 4 would bring the nudge back as soon as one more residual turned 30 days old.
- It updates the nudge count straight away.
- Everything the run decided lands as one pull request,
chore(residue): ..., on a branch of its own (a worktree by default). The run asks once whether to merge it or leave it open for review.
The batch size never hides the nudge
Section titled “The batch size never hides the nudge”The nudge counts every open aged residual, not just the ones in the next batch. With 40 aged residuals the nudge says 40, whatever the batch size.
The optional sweep of newer residue
Section titled “The optional sweep of newer residue”Once nothing aged is left, the run asks before each further batch:
Sweep the next 25 newer residuals? More: https://docs.gaiareact.com/maintenance/residue/with the choices Sweep the next 25 (of 125 remaining) or Stop here. The number in the question is the size of the next batch (smaller on the last one), and “remaining” counts every open residual, newer ones included.
Going through them is optional tidying. Stopping costs nothing: the run publishes what it recorded, and the newer residuals come back as aged residuals 30 days after their pull request merged.
When the nudge can stay up after a run
Section titled “When the nudge can stay up after a run”A promotion that could not file an issue leaves its residual open, so it still counts toward the nudge. That happens when GitHub is unreachable, the filing fails, or the finding is security-sensitive: security findings are never filed in the public tracker, only kept as a local record.
The run does not retry those in the same pass. It ends by saying how many are stuck, that they keep the nudge up, and what you can do:
- Run
/gaia-residueagain once filing works. - For a security-sensitive one, deal with it privately, then dismiss or keep it on a later run.
If the GitHub reads fail at the start, the run says so plainly (“this is not an all-clear”) instead of reporting that nothing is open.
Long runs
Section titled “Long runs”A run with many residuals can take a while. When the session’s context reaches the red band between batches, the run offers to keep going or to clear and resume. Nothing is lost either way: every decision is saved as it is made, and the whole run still lands as one pull request at the end. If you clear and never paste the continuation prompt, the next /gaia-residue offers to finish or publish that run first.
Guardrails
Section titled “Guardrails”- It never edits a file a residual cites, and never fixes anything. Fixing is
/gaia-debt’s job. - It never files an issue without your answer for that specific residual.
- A keep always expires.
The run ends with a cost line.
Settings
Section titled “Settings”Two environment variables change the defaults:
GAIA_RESIDUE_KEEP_DAYS(default 14): how long a Keep lasts before the residual comes back.GAIA_RESIDUE_CAP(default 25): how many residuals one batch holds.
Ask Claude to add one to the env block of .claude/settings.local.json (your machine only, not committed), then restart Claude Code:
Set GAIA_RESIDUE_KEEP_DAYS to 30 in the env block of .claude/settings.local.json.You can export it in your shell profile instead; restart Claude Code either way.
Not the same as leftover-file cleanup
Section titled “Not the same as leftover-file cleanup”After a GAIA update merges, Claude offers a cleanup of local files that retired GAIA features left behind. The script behind it is named residue-sweep, but it has nothing to do with /gaia-residue or audit residuals.