Watch yourself work with an agent for an hour and count the keystrokes. Open the next ticket. Paste the plan in. Wait. Review the diff. Approve. Open the next ticket. Paste it in. You feel productive, because the agent writes the code. But look at what you actually contributed: you picked which thing to do next. You did the triage. The agent did the typing.
You automated the cheap part and kept the expensive part for yourself.
A modern coding agent is broad and contextless. It can write Go, refactor a React tree, wire up a migration - and it has no idea which of your forty open tickets matters most this sprint. Task selection is the purest case of that gap: “critical bugs before polish” is a priority judgment that lives in your head. As long as it stays there, you apply it yourself, one ticket at a time.
Here is the tension the post turns on. The agent can write the code, and the agent cannot choose the code. Every ticket enters the agent’s world through you and leaves it through you. You have made yourself the transition function between tasks: the step every single ticket passes through, in both directions. A transition function cannot be absent.
And here is where it ends up. A sprint backlog of forty open tickets, cleared by hand-passing one ticket at a time, costs 80 touches - moments you personally stop and act: one to pick each ticket and hand it off, one to review it and close it out. The same forty tickets, run against a priority order you wrote down once, cost 1. That is an 80x cut, and none of it comes from a faster agent. The agent is the same agent. What changed is that the number of tickets stopped mattering.
First, check whether you have this
Section titled “First, check whether you have this”Don’t take the counts below on trust. Two checks on your own tracker, under a minute.
Count all your open tickets, including the ones drifting with no milestone and no owner.
Then try to say your priority order out loud, as a rule a new hire could follow on their first morning: “critical bugs first, then unblock the team, ties break toward recent activity.” Say it all the way through, with no “it depends.”
If the count is small, or the order came out fully formed and you genuinely like hand-passing, you do not have this problem, and the rest of this post will only annoy you. Stop here.
If the count keeps growing while the order dissolved into “whatever came up in yesterday’s incident channel,” keep reading. The first number is the problem this post solves. The second is the precondition: an order that cannot be stated cannot be written down, and nothing downstream works without it.
Count the tickets, then try to say the order out loud: the first number is the problem, the second is the precondition.
What the sprint actually costs you
Section titled “What the sprint actually costs you”Fix the running example now; every number in the rest of the post is computed from it. One sprint’s backlog: forty open tickets, sorted into the five tiers any real backlog falls into. Three critical bugs. Five dev-infra breakages - broken CI, blocked tooling. Eight tracer-bullet features, the thinnest slice that proves a path works. Sixteen polish items. Eight refactors. 3 + 5 + 8 + 16 + 8 = 40.
The countable unit is a touch: a moment you personally stop and act on the tracker or the agent - pick a ticket, hand it off, review a diff, approve a close. A touch is discrete where minutes are mushy: countable with a pencil, arguable one by one.
Hand-passing buys exactly two touches per ticket. One at the front: you read the backlog, choose the ticket, paste in the plan. One at the back: you review the diff, approve it, close the ticket. The loop is blocked on you at both ends of every ticket. Forty tickets:
40 tickets x 2 touches = 80 touches per sprintEighty. Per sprint. Every sprint. And the count scales with the one number that never goes down: the backlog.
The uncomfortable part is what those eighty touches bought: none is typing. You re-purchased the same selection over and over, because it lived in your head and nowhere else.
Every ticket costs two of your touches, and the backlog is the one number that never shrinks.
Five tickets, checked with a pencil
Section titled “Five tickets, checked with a pencil”Shrink the sprint until you can trace the whole thing by hand. Five tickets, same five tiers: one critical bug, one dev-infra breakage, one tracer-bullet feature, one polish item, one refactor.
Ground truth first, the obvious way. Hand-passed:
5 tickets x 2 touches = 10 touchesTen touches, every one of them you. That number cannot move. Five tickets or fifty: the loop is blocked on you at both ends of each one, so the count is twice whatever the backlog is.
Now run it the other way. Suppose the pick was not yours - the agent reads the whole backlog itself, applies a priority order you wrote down once, takes the top ticket, and does the work. Suppose the finish was not yours either - after committing, the agent closes the ticket with a comment when the acceptance criteria are met, or comments and leaves it open when stuck. Count your touches:
1 touch (write the priority order, once)Ten against one at five tickets: a 10x cut, on numbers you can check with a pencil. Both columns come from the same two constants - two touches per hand-passed ticket, one touch to write the rule - and nothing between them is rounded or estimated.
And hold onto the shape of that second column, because the rest of the post pays it off: backlog-fed touches do not move when the backlog does. They are stuck at 1. Those two supposes sound like a lot to ask. The rest of this post proves both are buildable with a rules file, an MCP server, and a loop.
Ten touches against one, and the one does not grow when the backlog does.
Give the agent eyes on the tracker
Section titled “Give the agent eyes on the tracker”Suppose one: the pick. The backlog lives in Linear, Jira, or GitHub Issues, and the agent cannot see it. Everything you paste in by hand is a paraphrase that started going stale the moment the tracker moved.
An MCP server is the bridge. It exposes your tracker’s operations as tools the agent calls directly, so it reads real tickets instead of your summary of them. If MCP is new to you, the general picture is here; this post uses it as one ingredient rather than as the subject.
You want three capabilities: fetch the open issues, read one issue’s full body and comments, and write a comment or close it. GitHub runs an official hosted MCP server, so wiring it into a Claude Code project is a few lines in .mcp.json, present every session:
{ "mcpServers": { "github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/", "headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" } } }}GitHub is just the example. Linear and Jira both ship MCP servers too. What matters is that when ticket #214 says “must handle the empty-array case,” the agent reads that line itself. That is context you stop carrying by hand.
The agent stops reading your paraphrase of the tickets and starts reading the tickets.
Write the pick down once
Section titled “Write the pick down once”The judgment you have been re-making every morning - which ticket next - becomes a persistent rule the agent reads on every run. This is one concrete application of a thesis this site argues elsewhere: every tool converged on a rules file because written context loads for free. Destination and journey point the same instinct at steering one long build; this post points it at which ticket comes next.
Drop a triage block into AGENTS.md (or CLAUDE.md):
## Backlog triage
On each run, fetch all open issues with their number, title, body, andcomments. Choose the single highest-priority issue using this order:
1. Critical bugs - anything labeled `bug` + `critical`, or breaking prod.2. Dev infra - broken CI, failing builds, blocked tooling. Unblock the team first.3. Tracer-bullet features - the thinnest end-to-end slice that proves a path works.4. Polish - UX, copy, edge cases on features that already ship.5. Refactors - only when nothing above is open.
Ties break toward the issue with the most recent activity. If an issue'sacceptance criteria are ambiguous, do NOT guess - comment asking forclarification and move to the next one.Read that order back. It is the same prioritization you already do on instinct, in the same five tiers the sprint was counted in; there is nothing novel in it. The difference is where it lives. An order in your head gets applied by you, one ticket at a time, two touches each. An order in a file gets applied by the agent, on every run, at zero touches.
Notice what the rule had to be to work at all: statable. Rank by label, by type, by recency - some ordering a new hire could apply unsupervised. If you could not get through the self-test at the top, the recipe cannot help you: a rules file can only encode an order that exists.
The pick was never hard. It was just never written down.
Run it with nobody in the chair
Section titled “Run it with nobody in the chair”Suppose two: the finish. A headless loop invokes the agent non-interactively, once per iteration, with the open-issues list injected at the top of context every time:
#!/usr/bin/env bash# backlog-loop.sh - run the agent against the top of the backlog, repeatedly.while :; do issues="$(gh issue list --state open --json number,title,body,comments)"
claude -p "Here is the current open backlog as JSON:$issues
Follow the backlog-triage rules in AGENTS.md. Pick ONE issue, implement it,commit, then honor the post-commit contract below." \ --allowedTools "Bash(gh issue comment:*)" "Bash(gh issue close:*)" "Edit" "Write"
sleep 30doneFetching the list fresh on every iteration matters. The backlog the agent triages is the live one: tickets you closed are gone, tickets filed five minutes ago are in. The agent works the real top of the stack, never a snapshot. (An overnight build loop solves the other half of “what does the agent work on next”: it decomposes one feature into a frozen task list written in advance. This post decides, live, which of many independent tickets comes first.)
Then the part that makes each run accountable: a post-commit contract telling the agent exactly what to do after it commits. Put it in your rules file, right under the triage block:
## Post-commit contract
After committing work for an issue, do exactly one of:
- DONE - all acceptance criteria met: close the issue with a comment summarizing what shipped and the commit SHA.- BLOCKED / PARTIAL - something stopped you: comment on the issue with what you did, what's left, and what's blocking. Leave it open.
Never close an issue you couldn't fully satisfy. Never leave a finishedissue open.This contract is where the review touch goes: into the tracker. Each issue accumulates the agent’s own commentary - what shipped, which commit, what got stuck. You still read it, when and as you choose. Reading a work log at nine in the morning and being the approval gate at one at night are different acts, and only the second blocks the loop.
With nobody in the chair to ask “wait, did you mean the v2 endpoint?”, the issue body has to carry everything. Your planning artifacts move into the tracker: the PRD becomes an issue body, the implementation plan becomes the description of issue #220, cross-referencing #214 and #218. Tickets start being written like specs for someone you cannot ask a follow-up: unambiguous acceptance criteria, edge cases spelled out. And a tracker is somewhere non-engineers can write: your PM files the ticket, your designer adds acceptance criteria in a comment. The backlog becomes the shared interface between the people who know what needs to happen and the agent that does the typing.
The review touch becomes the tracker’s job, and the tracker becomes the work log.
Pre-approve exactly two commands
Section titled “Pre-approve exactly two commands”A headless loop dies the instant it hits an approval prompt nobody is there to answer. The fix is a narrow permissions allowlist, and you already saw it in the script:
--allowedTools "Bash(gh issue comment:*)" "Bash(gh issue close:*)"Scope it tight. Comment and close are the only two tracker writes the contract needs, so those are the only two you pre-approve. A comment is editable; a close is one click to undo. The agent still cannot gh repo delete or force-push main - the rest of your guardrails apply unchanged, including to the code writes the loop does make.
This is where the obvious objection arrives: an agent, closing tickets unsupervised? The two pre-approved writes are the lowest-stakes writes the loop needs, and they are the mechanism the count rests on: the “1 touch” in every table below is true only because closing and commenting were decided in advance. For the full accounting of what an unattended agent can reach, that arithmetic lives here. The short version: scope is the safety, and this scope is two commands wide.
The loop survives the night only if every prompt it can hit already has its answer in a file.
Why not just use the vendor’s agent?
Section titled “Why not just use the vendor’s agent?”Fair question, with three answers by 2026, one per vendor.
GitHub’s Copilot coding agent does the execution half natively. Assign it an issue and, in GitHub’s own documentation, it “will start working on the task, raise a pull request, then request a review from you when it’s finished.” Look at the verb, though: assign. That is a human action in the UI, once per issue, and the review request at the end is a second one. The count is the same two touches per ticket, yours to assign and yours to review. The agent is execution-autonomous and pick-manual: it removed the typing and kept you as the picker.
Devin, from Cognition, is much closer to the whole claim. Its Linear integration documents automation triggers that “let Devin automatically start working on tickets when they match certain conditions, without manual assignment or labeling.” That is the pick itself, removed, shipped as a product. The honest caveat is the boundary: those are Devin’s triggers, running Devin, inside Devin plus Linear. If that is your stack, parts of this recipe may already be done for you.
Linear itself now ships the agent inside the tracker, with the reach wired first-party. The April 23, 2026 entry in Linear’s changelog records that “Linear Agent can now connect to your tools via MCP, giving it access to data and actions beyond your Linear workspace.” The primitive this post wires by hand - an agent with MCP reach - is a vendor feature in at least one major tracker now.
So why build it yourself? Because the portable part is the one thing no vendor can ship: your order. The five-tier triage block works with any tracker that has an MCP server or a CLI, any agent that reads a rules file, any loop you can schedule. Switch tracker, switch agent, keep the rule. Devin already automates the pick inside its own stack; the written order automates it inside yours.
The vendors automate the execution; a written order automates the pick, and it travels across stacks.
The numbers, run out
Section titled “The numbers, run out”Everything above reduces to one table. Hand-passing costs two touches per ticket, so its column is 2N. Backlog-fed costs the single touch that wrote the rule, so its column is the constant 1. Every row follows from those two constants and nothing else:
| Backlog size | Hand-passed (2N) | Backlog-fed | Cut |
|---|---|---|---|
| 1 | 2 | 1 | 2x |
| 5 | 10 | 1 | 10x |
| 10 | 20 | 1 | 20x |
| 40 | 80 | 1 | 80x |
| 100 | 200 | 1 | 200x |
Row 5 is the toy. Row 40 is the sprint this post opened with, paid off exactly: 80 touches against 1, the 80x claimed at the top. The cut column is just the first number divided by one.
Now read the third column down its whole length. Flat. The agent did not get faster between row 1 and row 100. The count went flat because N dropped out of the equation entirely: the rule is written once, and nothing about the fiftieth ticket makes it longer or the loop more attentive.
There is a name for a decision like that, older than software. Ops teams call it a standing order: an instruction issued once, in force for every case it covers, never needing to be reissued per case. A triage block in a rules file is a standing order for your backlog. The name separates two ideas: a rule - this site’s word for the persistent-context primitive - is the medium. A standing order is the act: one decision, issued once, to cover every future case of its kind. The flat column is that act in arithmetic.
Extend it, because one sprint is not where the trick pays biggest. Four sprints of the same forty-ticket shape is one quarter:
| One quarter | Hand-passed | Backlog-fed | Cut |
|---|---|---|---|
| 4 sprints x 40 tickets | 320 | 1 | 320x |
The rule is not re-paid each sprint. It is reused: paid once in the first week, run on for free every sprint after.
A standing order is a decision issued once and in force for every case it covers, which is why the cost column never grows.
When this fails
Section titled “When this fails”Three honest limits. The table does not hide any of them.
Row 1 flatters the trick. At one ticket, backlog-fed still wins, two touches against one. Ignore that arithmetic. Writing a five-tier policy to save one touch on a single ticket is a bad trade, and the “1” quietly understates the real first-time cost: getting the tier order right, deciding the tie-breaks, wiring the loop. More than that, do not trust an unsupervised close on ticket number one before you have watched the rule get several picks right on tickets you could still check. The numbers favor the technique from the first ticket; the trust arrives later, and only from evidence. Hand-pass a few on purpose the first week, with the rule picking alongside you, and stop watching when it has stopped surprising you.
It requires a statable order. Priority has to be statable as a policy - rank by label, by type, by recency - for a rules file to encode it. A team whose real prioritization is whatever came up in yesterday’s incident channel, decided verbally and never written anywhere, gets no help from this recipe. It gets something worse: a confidently wrong pick from a stale written rule. The self-test at the top of this post exists to catch exactly this before you build anything.
The rule expires when your priorities do, and nothing notices. After a 320x win, this is the anti-hype line. A triage order has no natural shelf life. It goes wrong the day the team’s real priorities move and nobody edits the file, and the failure is quiet. Two mid-sprint cases, one benign and one not. A critical bug filed after the rule was written lands in a tier the rule already ranks first, and the loop catches it on the next run: the static rule handles new tickets inside known tiers just fine. A genuinely new kind of urgency the rule never named - a security disclosure, an escalation with no label - gets ranked below sixteen polish items on every run, with perfect consistency, until a human notices.
The arithmetic favors this from the first sprint; noticing that the order has gone stale stays your job forever.
Back to the table
Section titled “Back to the table”Third column, one more time: flat at 1 from one ticket to one hundred, while hand-passing climbs 2, 10, 20, 80, 200, and 320 across a quarter. Same agent in every row. The pick moved from you to the file.
Task selection was the one decision still routing every ticket through you. Writing it down once removed the per-ticket cap on your presence without removing your judgment from the system: the order the loop follows is still yours, stated, in a file anyone can read and argue with. Your job moves up a level, from applying the priority to deciding what belongs in the backlog at all. That work needs you. The triage and the typing were never the point.
Which leaves the cost this post created and does not solve. A standing order carries no date, because no date was ever true of it. It expires the moment the team’s real priorities move and nobody edits the file. The disposable map in cache the explore at least gets a capture date to squint at; a triage rule that has quietly stopped matching the team is invisible until you notice the agent has spent two weeks polishing while something urgent sat in a tier the rule never learned. There is no built-in alarm for that. Who or what checks that the written order still matches the real one is the open question this recipe hands you, wiring not included.
Your backlog is the prompt. Stop pasting it one line at a time.
About the numbers. Every touch count in this post is toy arithmetic, invented for traceability: two touches per hand-passed ticket (pick and hand off, review and close) and one touch to write the rule, both derived from the mechanics described rather than measured on a real team. The forty-ticket sprint and its five-tier split (3 + 5 + 8 + 16 + 8) are an invented but internally consistent breakdown matching the priority order the recipe encodes. Every figure was re-checked with a script before publishing; swap in your own ticket count and the shape holds, with the backlog-fed column still at 1. The vendor facts are quoted from primary documentation read in August 2026: GitHub’s Copilot cloud-agent docs, Cognition’s Linear-integration docs, and Linear’s changelog entry of April 23, 2026. Nothing here comes from secondhand roundups.
For the per-tool mechanics, see MCP servers for giving the agent live reach into your tracker, Rules for encoding the priority order as persistent context, and Headless & CI for running the triage loop unattended.


