Issue #1382 is titled "fix bug". It was filed 11 months ago by an engineer who left in the spring, the description says "see slack thread", and the thread is gone. You only opened it because you were searching for the crash a customer reported yesterday, certain someone had filed it before. Search came back empty. Search matches words, and the titles in your backlog do not contain any: "fix bug", "doesn't work", "edge case", "follow-up". 400 issues deep, the backlog has stopped being a queue of work. It is the place context goes to die.
The fix is content work, not workflow work, and that is what makes it tractable. Titles that name the symptom, so search starts returning. Descriptions with a shape: what happened, what was expected, what actually happened, and where. Likely duplicates flagged with the evidence side by side, so a human can merge them in Linear instead of trawling the backlog on a hunch. That is 400 small edits plus a pile of cross-referencing, exactly the work no grooming meeting survives. The loop below changes the shape of it: pull the backlog into local files, let your AI agent rewrite and cross-reference, then review every changed title as a word-level diff before anything writes back.
Your options
Grooming meetings
The room is where the judgment lives, and judgment is the hard part: what to kill, what to keep, what last quarter's half-plan actually meant. The 2017 Scrum Guide budgeted up to 10% of a team's capacity for refinement, and that was an honest price. The 2020 revision dropped the number; the work did not get cheaper. What the room cannot do is content work at scale. Nobody rewrites 400 titles in a meeting, and nobody cross-references duplicates there either: studies of mature trackers put duplicate rates at 15 to 30%, and manual hunting runs close to 3 minutes per duplicate found, which makes a 400-issue backlog hours of cross-referencing the room will never do out loud. The meeting triages around the bad titles. It does not fix them.
Linear's built-in tooling
Linear's multi-select bulk actions are quick and good: select 50 issues and change status, priority, or project in one stroke. Auto-archiving sweeps closed issues on a schedule each team sets, and the Similar issues AI suggests possible duplicates with a one-click mark-as-duplicate. The Linear Method itself endorses pruning: important requests resurface, low-priority ones were never getting fixed. Two gaps for this job. The bulk actions cover workflow fields; nothing in Linear's documentation bulk-edits a title or description, so prose stays one issue at a time. And Similar issues fires when an issue is created or sits in triage. Your 400 were created months ago, and no documented surface sweeps the existing backlog for clusters.
A script on the GraphQL API
The API side of this job is genuinely easy. Reads default to 50 issues a page, so a 400-issue backlog arrives in a handful of requests, comfortably inside the hourly limits, and the issueUpdate mutation writes only the fields you pass. For mechanical cleanup, a script is the right tool: strip a dead prefix, fix a misspelled product name everywhere. The wall is that this cleanup is not mechanical. A script can fetch all 400 issues in seconds and still cannot tell you which titles are wrong, let alone write the better one. And its writes land on the live workspace the moment it runs, no preview, with Linear's per-issue history as the only undo.
An agent on Linear's MCP server
Linear's official MCP server gives an agent real reach: list issues, fetch one, update a title or description. Judgment is finally in the loop. The read shape is the first cost. Full descriptions come back one issue per tool call, roughly 400 calls for 400 issues, each response a block of stringified JSON with state history, UUIDs, and timestamps along for the ride, all of it metered through the context window after the tool definitions have already eaten thousands of tokens. Duplicate-hunting needs every issue in view at once, which is exactly what a context window that full cannot hold. The second cost is the write: each update lands live, unreviewed, the moment the agent decides.
Scratch
Scratch gives the same agent the same backlog as 400 local files. Now it can grep for repeated error strings, build an index of every title, write a similarity script that scores all the pairings, and spend its judgment on the clusters that score high. It edits titles and descriptions only. Status, labels, assignees, and estimates have no write path, and Scratch cannot close, merge, or create issues, so likely duplicates are flagged with evidence for a human to merge in Linear. Every rewrite comes back as a word-level diff before anything ships, because nobody wants a robot silently rewording the team backlog. The trade: 400 diffs is an afternoon of real reading, and Scratch does not do that part for you, on purpose.
| Option | Rewrites titles and descriptions | Whole backlog at once | Duplicate clusters | Reviewed before it lands |
|---|---|---|---|---|
| Grooming meetings | No, triages around them | A slice per meeting | By memory | The meeting is the review |
| Linear built-in tooling | One issue at a time | Workflow fields only | At creation and triage | Nothing to review |
| Script on the GraphQL API | Pattern edits only | Yes | No judgment | No, writes land live |
| Agent on Linear MCP | Yes | Call by call | Context permitting | No, writes land live |
| Scratch | Yes, your agent | Yes, as files | Flagged with evidence | Every change, as a diff |
How the loop works on your backlog
- Scratch pulls the backlog into files. Each of your 400 issues lands as its own file: the title and description editable, with status, labels, assignee, and cycle beside them as read-only metadata. Nothing in Linear has changed, and the agent never holds a Linear credential.
- Your AI rewrites titles and cross-references duplicates. Point Claude, Codex, Cursor, or Copilot at the folder and give it the brief. Rewrite every title to name the actual problem in under 70 characters: the symptom, the surface, the condition that triggers it. Restructure each description into what happened, what was expected, what actually happened, and where, keeping every original detail and link. Never delete information. Where two issues describe the same bug, change nothing; append a "Possible duplicate" note to both, citing the overlapping evidence. The agent greps for repeated stack traces, scripts a similarity pass across every title and description, then reads the high-scoring clusters with judgment. On local files that cross-referencing takes minutes, and the descriptions land in the shape bug-writing guides have asked for since bug trackers existed. This is the 99% of the work nobody was ever going to do in a meeting.
- You review every diff and publish. Each rewrite appears as a word-level diff next to the original. Validators run first, if you set them: a title length cap, a ban on non-titles like "fix bug" and "doesn't work". Approve per issue, and Scratch writes only the approved issues back through Linear's GraphQL API, at the API's own pace, one at a time. The duplicate notes ship as ordinary description edits; the merging happens in Linear, by a human, with the evidence already attached. The last 1%, deciding what the backlog actually says, stays with the team. Rejecting a published rewrite puts the old text back.
Start with the 50 oldest issues. If the diffs read like a careful teammate tidied them, the other 350 are the same brief.
What issue #1382 looks like afterward
Before, the title is "fix bug" and the description says "see slack thread". After the loop, the diff you approve reads:
CSV export drops columns when a header contains a comma
What happened: customer exported a board with "Revenue, net" as a column header. Expected: a CSV that opens with every column intact. Actual: the file downloads, but every column after the comma shifts. No error shown. Where: web app, export dialog. Reported by 2 accounts, most recently May 12.
Possible duplicate: #1907 reports shifted columns on import with the same header pattern. The evidence overlaps; merging is your call.
The search that found nothing now has a symptom, a surface, and a condition to land on. And the issue still belongs to the same team, the same project, the same assignee, because nothing but the words changed.
Questions people ask
Will the AI close, merge, relabel, or reassign anything?
No. Scratch's Linear connector edits issue titles and descriptions, and project names and descriptions. That is the whole write surface. Status, labels, assignees, estimates, and cycles have no write path, and nothing can close, merge, or create an issue. A cleanup pass cannot turn into a workflow change.
Does Scratch merge the duplicates it finds?
No. It flags them. The agent appends a note with the evidence: the issue numbers, the overlapping error string or symptom, why it thinks they match. A human reads that and clicks merge in Linear, or does not. A wrong automated merge buries a real bug, which is why the call stays human.
Does anything change in Linear before I approve it?
No. The agent works on files on your laptop and never holds a Linear credential. Linear first hears about an edit when you approve the diff and Scratch writes it back through the GraphQL API.
What happens to statuses, labels, assignees, and estimates?
Nothing. There is no write path back to any of them. Status, labels, and assignees come down as read-only metadata so the agent can use them as context, since an issue's age and team are useful evidence.
Will rewriting 400 titles break links or issue IDs?
No. The identifier, the ABC-123, does not change. A title edit through the API is the same edit as renaming the issue inline, and mentions and links that point at the issue keep pointing at it.
Should we just delete the old issues instead?
Sometimes. Linear's own method docs argue for a manageable backlog: important requests resurface, low-priority ones were never getting fixed. But you cannot make the keep-or-kill call on a list you cannot read. Clean the titles first and the issues that deserve archiving become obvious. That decision stays yours; Scratch deletes nothing.
Can I undo a rewrite after it publishes?
Yes. The original stays next to every published rewrite, per issue. Reject it and the old title and description go back, with Linear's own per-issue history underneath as a second net.
See it on your own backlog
A cleanup is easiest to believe on your own issues. See it run on your Linear backlog →, or download Scratch free, connect Linear, and pull one team's backlog tonight. Ask your agent to list the 20 vaguest titles before changing anything. That list is usually the whole argument.