Running background agents, for humans
An agent you have to sit and watch isn't saving you much. The point of handing a task to an AI agent is to go and do something else while it works.
From my perspective, what makes an agent safe to walk away from is where you let it run, not how smart/new/shiny the model is. For example, if you let it loose on your current working checkout, you're stuck because one git checkout from the agent and your half-finished work is gone. My preference is to give it a throwaway worktree instead, that you can run in the background with screen (or similar), then have it hand its work back as a pull request ready for your review.
The agentic trifecta
Use a worktree for isolation. The agent gets its own checkout on its own branch, sharing your repo's history but isolated from what you're currently working on. It can edit, build, run tests, commit, whatever, and the checkout you're sitting in stays safe.
Use screen as a background runner. Start the agent in a screen window, detach, and it'll do what it needs to do in its own little bubble (assuming you prepped it correctly and it doesn't need any confirmations from you). You can check up on it by reattaching to see how it's getting on, look at what it's done, and ask or answer any follow up questions.
Use pull requests to see the output. The agent shouldn't merge anything, just push its branch and open a PR (I like to have them assigned to me on creation). You review it like any other PR: QA it, read the diff, make amends (or suggest improvements to the agent itself), then merge or close so nothing gets merged that you haven't given the all clear on.
Put together: you spin a worktree off the latest origin/main, start an agent in it under screen, detach, and get on with your actual work. When it's done it's a PR in your queue.
This all assumes one thing: the agent can act without stopping to ask. Most agent CLIs prompt for approval before each command or file edit, and one that keeps pausing for a yes/no isn't something you can walk away from. So running unattended means letting it run commands on its own, which is a lot of trust to hand over. It's the other reason the isolation matters. Inside a throwaway checkout it can't escape, which means nothing it does reaches main until you've read the PR.
How an agent should use a worktree
The worktree from one of my previous notes was something you spun up and destroyed by hand. An agent wants the exact same lifecycle, just driven entirely in code.
A good agent setup, in order:
- Name branches well. Derive the branch deterministically from the task ("drop the dead code in
StockService" becomes something likecleanup/stock-service-dead-code), then create the worktree on that branch:
$ MAIN="$(git rev-parse --show-toplevel)"
$ git -C "$MAIN" fetch origin
$ git -C "$MAIN" worktree add "$HOME/.cache/agents/stock-service" \
-b cleanup/stock-service-dead-code origin/mainIf the branch already exists, worktree add -b fails, which means another agent (or an earlier run) already took this exact task. So you can fire off as many agents as you like, all at once, with no shared lock and no coordinator, and there's no worry they'll be double dipping or overwriting each other.
Never touch the primary checkout. Everything happens inside the worktree. The agent never branch-switches, stashes, or commits in the checkout you're working in. Reading it (a grep, a glance at a file) is fine, but writing to it is off limits.
Borrow dependencies, don't install. Symlink
node_modulesfrom the main checkout, exactly as before, so the agent is ready to run tests in seconds rather than sitting through a fresh install on every task:
$ ln -s "$MAIN/node_modules" "$HOME/.cache/agents/stock-service/node_modules"
If you're running several agents at once, give each its own build cache directory too, so they're not fighting over one shared cache.
If you're installing or updating dependencies, you'll still have to npm install as this kind of borrowing assumes the lockfiles won't be changing.
Open and assign one PR only. Push the branch, open a single pull request assigned to yourself, and do nothing else to the remote. No pushing to
main, no force-pushing, no deleting other branches.Always tear down. On success or on abort, remove the worktree and prune. This is mainly housekeeping as we don't want abandoned worktrees littering the disk, or pushed branches with no PR behind them.
$ git worktree remove --force "$HOME/.cache/agents/stock-service" $ git worktree prune
Of the five, be strictest about "never touch the primary checkout". An agent that branch-switches or stashes where you're working can eat changes you haven't committed.
Spinning a side task off without losing your place
You're deep in a feature, and you notice something unrelated: a bit of dead code, a flaky helper, a dependency a minor version behind. Stopping to fix it now can destroy your mental map, and creating a ticket is sometimes as big a task as fixing the thing itself (with the added possibility of it sitting in the backlog forever). So being able to hand off this task to a background agent is just pure productivity nectar.
The "for humans" part is because none of this needs you to be an AI to drive it. It simply slots into your human-centric workflow, as if you're handing tasks off to junior engineers.
A worked example
I've got a couple of small skills of my own that follow the principles above. One of them is called whittle which opens one small behaviour-preserving PR. Things like drop an else after an early return, delete a line of dead code, the kind of tidying I never get round to, but an agent can do safely. I start it in a screen window, detach, and when I remember, I take a look at the PR sat in my queue with my name on it.
$ screen -S whittle # start the agent in here, hand it the task, then: # Ctrl-a d - detach, and I'm back on my feature
Start it on something safe
Give it a go, maybe not beginning with agents that refactor your critical code, but something boring. Behaviour-preserving stuff. Get a feel for handing work off and reviewing what comes back, and once the loop is muscle memory (spin a worktree, run an agent in it, review the PR, throw the worktree away), start increasing the size of the task you trust it with.