· Nathaniel May · Practical Engineering · 16 min read
Herding Agents
How I conserve my time, attention, and sanity while shipping across multiple concurrent projects.

Views expressed here are my own and do not necessarily reflect those of my employer.
If you’re reading this past Feb 1 2027, treat this as an archeological record rather than up-to-date advice.
My expert attention is the most valuable resource when building with agents, and my tools are designed to preserve it. Ephemeral sandboxes free up my attention to manage a larger herd and to improve my workflow to scale up my own throughput. My agents write code, commit, push, open PRs, and request outside reviews unattended, all because they have access to everything they need and nothing more. My time and attention are spent making real decisions and shipping, not mindlessly orchestrating.
I fire off workflows on top of tools that save my attention on several fronts: I front-load human judgment with a long unsupervised tail for implementation and automated reviews, I have status at a glance across agents, and I safely ignore what bash is running in the sandboxes. This post walks through my stack so you can see the attention savings, and take the ideas that resonate for your own workflow.
Two jobs, two tools
At first I used Zed as both my IDE and agent management hub. It’s become a popular tool for multiplexing across agents for good reason, but it’s doing too much with too little screenspace. I love using it to write and inspect code myself, but an agent-centric workflow needs a different layout than a code-centric workflow. Carefully toggling back and forth became a tiresome chore, and when I left the house my whole high velocity multi-agent workflow was stuck to my MacBook while I sat doing nothing on the train. The solution was to split the two workflows into two tools: I still use Zed to read and write code by hand, and I use herdr for multiplexing agents.
With Zed in its own Mac workspace, I pull what the agent pushes, test, make changes, and push back. It feels extremely familiar since this is how I’ve always worked with collaborators. I get to keep using my favorite tools the way I always have, all while multiple agents from different families work with me.
The work
Work is scoped to small meaningful changes that make progress on their own. Standard engineering stuff. Sometimes I ask for changes with loose definitions, and through the design discussion I decide to split the work into smaller, well-defined, manageable pieces. In practice, these chunks of work take between 20m and 2hrs to complete. It’s not a target I aim for, just a consequence of tightly scoped work.
Within a single workstream, I use exactly two skills, dev-workflow and pr-review, to orchestrate development across any of my supported agents. Right now that’s just Claude and Codex, but I plan to add open weight models using a Pi or OpenCode harness in the future. There’s nothing novel about my skills, but they automate something I used to do manually when I first started developing with agents: implementor-reviewer feedback loops. The idea is sound, but copy-pasting back and forth is a waste of my time. I may replace these with more widely shared skills like superpowers or keep the control and update my own with the good ideas I find in the open.
My environments are ephemeral so I need my workflow to be resumable in a fresh sandbox and right now that state is stored in GitHub issues and PRs. Because these tools grew from working alone on private repositories, my agents use GitHub like they are my collaborators. GitHub as a boundary has always let people collaborate with different workflows and that’s true when collaborating with agents too. This choice starts to deteriorate quickly once you introduce a team or point it at an open source project. No one should be collaborating with my agents but me, so I plan to move that boundary to my host machine.
Because I care about operating quickly without guzzling tokens and cash, I’ve crafted the skills to use different size models and reasoning levels for each task. Smaller models are used for exploratory work with lots of input and for work that requires a volume of output tokens. Bigger models are reserved for reviewing plans and diffs made by the smaller models as well as gating PRs with reviews. I’ve experimented with raising the model size and reasoning for these skills but the time spent grows with no measurable return.
Here’s what dev-workflow does today:
- Setup. A Claude Sonnet or Codex Terra agent becomes the orchestrator. It creates the random run ID, new wip branch off main, and a local journal file for recording state and history.
- Design. A subagent gets fired off to investigate the current state and write a design doc, collecting questions to ask me along the way. The larger same-family reviewer, Claude Opus or Codex Sol, then reviews. There are some fuzzy optimizations in here like capping rounds and periodically clearing context history for the reviewer that could still use some data-driven fine tuning.
- Human Gate. I review the summary of the design and answer any open questions from the designer. For small tasks, it usually gets it right the first time and I rubber stamp it. For anything larger I most often have several rounds of feedback while we hammer out my own assumptions and the details for what implementation I want to see. This is where some work will get split into smaller chunks and multi-stage execution emerges. This isn’t just a phase to decide how something should be built, but also a cheap mechanism for deciding whether it should be built at all. Almost every time I choose not to pull on a thread it’s because of this step here. I rarely need to see the code to decide it was a bad idea and shouldn’t be merged. Once approved, the design gets posted as a comment on the issue so I can resume from another session cleanly.
- Plan. A subagent writes a detailed document on implementation with the same reviewer loop and no human gate. This is where I choose to inject intelligence from the larger models while letting token output for the code and comments come from a smaller model. Once approved, the plan gets posted as a comment on the issue so I can resume.
- Implementation. A subagent makes changes to the code and uses a mirror of CI steps for cheap and deterministic feedback before tapping in the reviewer. Just like with human development, this is where we find hidden assumptions that don’t hold up, and those end up as comments for the reviewer to see. New commits appear for each round of fixes from the reviewer. The implementor keeps its context for the duration to conserve on input tokens.
- Draft PR. The orchestrator opens a PR as an integration point for the next steps.
- Cross Family Review. The orchestrator fires a command that spins up another reviewer in a separate sandbox. Claude asks for a Codex review, and Codex asks for a Claude review. Like the previous review loops, this continues until both families are satisfied or the cap is reached and a conflict is raised to me. At this point, the draft PR is a bit of a mess with all the agent chatter.
- History rewrite. A subagent opens a new PR with a fresh set of ordered and titled commits for me to review. This hides the internal synchronization that doesn’t belong in my review. The new state is statically evaluated to match, and the draft PR is closed.
- Merge Decision. I review and decide to merge or request changes. For very small tasks the code usually looks perfect and I just merge it. For larger tasks I have to decide if the part of the codebase I’m working on is okay with a little vibe bloat or if I want to start reading for questionable decisions. For critical parts of my codebases I still read every line and push my own commits for fixes. This is where I may opt to make an update to my AGENTS.md like
A justfile recipe is one command. The logic it calls belongs in a tested TypeScript function.
This process only has one human input and one human gate right at the front. Once the design is approved I can move on to spinning up another work item and juggle them with ease. Just like human development, the big thing to watch out for is scope creep. If 5 of these PRs land and they’re each 10k lines, you have to choose between blindly accepting bloat and doing some real work to carve them down to size.
So much of this workflow relies on sandboxing and sbx is a great choice for agent microVMs. With features like first-class provider integrations for auth and credential substitution in the network proxy, it was an easy choice for me. What’s in these sandboxes is determined by Docker sbx kits and what they can reach is determined by a network policy. Where I deviate from their operational model is that I make these environments ephemeral by construction. sbx gives you the tools to make them each a special snowflake, but state management is complex and annoying so I choose to eliminate it when I can.
When spinning up sandboxes you have many choices to make. Every choice is very personal to the needs of each organization or developer and should be codified in an auditable way. I’ve concentrated all of the decisions that make up my security risk profile into a tool I wrote with the uninspiring name sbx-new. I’m not going to share it because I chose to collapse all the structure that would be required to express multiple people’s security profiles and instead simply encode what I alone am comfortable with. The transferable part is not the tool itself. It’s that the tolerances live in one place, enforced by construction, instead of scattered across prompts, doc comments, and good intentions.
The most important part of sbx-new is enforcing key limitations: access to GitHub via a limited PAT for the one repo, read-only host mounts, and internet access via an explicit network allow list.
This creates the most important primitive of the whole workflow: one disposable environment per task.
Running several at once
Each agent’s sandbox is launched inside the herdr UI. What makes herdr so appealing is that it has a minimal UI footprint that lets your terminal tabs span multiple workspaces while detecting and displaying the status of each agent you’ve launched. Unlike most terminal UIs, the layout is designed for both desktop and mobile screens.


Here’s how this usually goes: I sit down with one or two big ideas I want to implement. Say write a new blog post on my AI workflow and add a new graph to my personal analytics BI. Analytics I split into “Add personal GitHub commits as a source” and “model commits by agent or human author over time through to BI.” The blog post I split into a research task and a collaborative outline creation. Now I have two workstreams with blocking and subsequent tasks which is easy to keep in my head. I fire the first two off, and after working for a bit I realize there are some silly Mac files creating token waste when my agents go to push, so I spin up a new agent in my dotfiles repo to investigate and make a fix. The agent from my GitHub source project realizes my source freshness table only surfaces successful runs, but it hopes to detect failed runs as well — very reasonable. I spin up another to merge that first so my source work can rebase on top of it.
To keep track of this growing dependency tree, I’m currently experimenting with using a little mermaid diagram for each day. I made a POC that’s less than vibe coded: it’s a directory, justfile, and AGENTS.md to see how I like the workflow. After updating the graph with an agent a few times, I can request my state and view a little ascii chart right in my terminal.
If I find value in using this, I’ll code it up as a minimal Rust cli or a herdr extension and bake it into my workflow without the extra token usage. If it’s not the right fit I may try using beads or another built-for-purpose tracking system. But POCs like this take minutes to build, and I get to test the user flow before getting into the weeds of implementation.
This can easily feel like it’s spinning out of control. However, what’s actually happening is that I have the freedom and time to solve workflow and system tech debt before shipping features. This was the dream that was always just out of reach without AI. These tasks were often viewed as impractical yak-shaving but now we can have it all.
When I leave the house
With this construction it’s safe to let agents work when I’m not at the keyboard. That doesn’t mean I’m always valuemaxxing while on dinner dates or while watching a movie with friends. But when I’m in a waiting room or on a bus I’m usually mindlessly scrolling to pass the time. I’d much rather be building something and I bet you would too.
When I leave the house, I turn on caffeine, shut off the screen, and walk out the door. I have Ubiquiti equipment at home so I can use UniFi Teleport to make my local network accessible to my phone. If you don’t, Tailscale works just as well. I open up Termux, ssh into my laptop, type herdr, and the whole herd is ready for me to take action. Between herdr over ssh and the GitHub app I can do pretty much everything I can at home. The changes I might have pushed myself, I’ll just ask the agent to do for me.
Unfortunately ssh isn’t the most resilient to faulty networks, so I was hoping to fold mosh into the stack to protect against unnecessary disconnects. Until this issue is resolved I’ll have to live with occasional disconnections. In practice on my outings I get maybe one disconnect an hour, which is tolerable.
How I know this works
Just because I’m using this workflow doesn’t make it smart. Here’s what I observe that keeps me at it:
The design gate forces assumptions to the surface and I either change the ask, split the work, or even kill the thread entirely. The same was true when hand coding, but the assumptions often didn’t surface till the coding was well underway, delaying the entire process.
Agents have always been exceptionally good at reviews, but using an agent from a different model family catches problems that survived multiple in-family reviews even with fresh context windows. In a sample of nine PRs I recently worked on, seven had a P1 blocker from the cross reviewer and the other two had valid P2s. I personally inspected these for the purpose of this post and I agreed with every single one of the findings.
My personal-analytics project was a migration away from its prior form in a monstrous spreadsheet pushing the limits of what Google Sheets can realistically compute. A rough estimate of the time it took based on commit timestamps is about 42 hours. In all honesty, five eight-hour days is about what I’d expect it to take if I were to code it by hand. I was initially disappointed at this finding, till I looked at what was actually included: a full database migration from an earlier Postgres prototype to DuckDB, OAuth token juggling for multiple sources, a fresh dbt transformation layer, exceptionally robust CI, encrypted off-site backups with a well-tested restore path, a daily production publish job, and a first-class login integration with session handling. 42 hours of my time would have accomplished half as much.
I’m working on collecting more empirical data on this workflow’s performance. I’m planning to add a thin state tracking seam, and once the data is collected I’ll have a new post to write.
What this costs
Prioritizing a single, portable management pane and the ability to seamlessly spawn different agents in an ephemeral environment comes with limitations. Some products, like a Gemini subscription with Antigravity, don’t have a way to authenticate in a headless environment. Each model provider has an ecosystem of mobile and cloud tools I’m choosing to ignore for the freedom to treat agents as interchangeable. For a richer mobile experience I could use Claude remote-control and Codex Remote. My laptop is a single point of failure: I forget caffeine, the cat closes my cracked laptop, or my battery dies and I’m back to no mobile workflow. I could use Claude Code on the web and Codex Cloud to fix that. Lastly, I own so much of my stack that I am trading complete control for a non-trivial maintenance burden. I could free up my time by paying for tools such as fly.io Sprites for ephemeral workspaces off my laptop if I wanted to spend $50–$500 per month.
For a while this system helped me very efficiently balance two $20 plans: Claude Pro and Codex Plus. When my Claude session limit was more than half I’d swap my next few runs to Codex implementors and switch back. I was able to completely saturate my weekly limits on both which made me feel like I earned the max plans. For any craft I’m learning, I want to outgrow my tools before I buy the expensive ones so I know what I need from them, which ones to buy, and how to wield them. The limitations of the $20 plans helped me develop this process, and my current usage of the max plans is much more intentional for it.
Landing designs, plans, and automated reviews in GitHub was perfect for debugging and improving my own workflow while working on personal projects, but it’s a rude and messy nightmare for someone else to parse through. The next stage is to move this shared state off GitHub and into a new local state tracking application that agents in sandboxes can read and write to through a very thin CLI.
Bring all your agents. You decide where to spend your judgment and what gets automated into oblivion. I’ll sit on my stack of sandboxes that won’t exist tomorrow and we’ll work on that PR together.



