GitHub PRs are slow. Keep shipping anyway.

The issue is ready, the code is ready, and then the PR page spins. A check stays queued. A webhook arrives late. The review that should have taken ten minutes turns into an afternoon of refreshing GitHub and wondering which part of the pipeline is actually broken.

That is not hypothetical in October 2026. GitHub’s August 17 incident report says a 7 hour, 47 minute outage disrupted the site, APIs, Actions, pull requests, and issues. Its September availability report describes database pressure and work to contain failures in pull requests. The status history also records October delays across PRs, Issues, Actions, and webhooks. GitHub is doing capacity work. A development team still needs a plan for the hours when its work is waiting on that capacity.

Find the actual wait

“GitHub is slow” describes the feeling, not the bottleneck. Track issue ready to first code change, code complete to first review, review complete to checks, checks complete to merge, and merge to deploy. Look at the median and the ugly tail. A slow PR page is one problem. A two day review queue is another. A CI job that queues for an hour and runs for three minutes has a different remedy from a test suite that takes an hour on a ready runner.

This measurement matters because some delays are in our own process. If a task cannot start until somebody writes an elaborate issue, or a trivial change waits behind a weekly approval meeting, GitHub uptime will not fix it. Write the acceptance criteria and the risk in a short issue or local task note, then let implementation start. The artifact should help the next person understand the work, not become a ceremony the work must survive.

The delivery timeline separates local work, GitHub dependent review and checks, and deployment

Move the fast feedback close to the code

Make the build, focused tests, formatting, and relevant static checks runnable with one documented local command. Run them before opening the PR. A remote check is still useful as the shared attestation, but it should confirm a result developers can reproduce, not be the first place anyone discovers a compiler error. Cache dependencies carefully, keep the quick checks quick, and reserve expensive matrices for changes that need them.

Review can begin from a branch or a patch while the PR UI is unhealthy. A reviewer can read git diff, run the relevant tests, and write findings in a shared local note. When GitHub recovers, put that discussion on the PR so the decision remains visible with the change. Do not mistake a green local run for the required check on a protected branch. Branch protection is a team contract, and an outage is a poor reason to silently discard it.

Keep a second path for coordination

Issues are a convenient source of truth until the issue service is unavailable. Keep enough task context in the repository or another team owned system to continue: a task ID, expected behavior, owner, and decision log. It can be a small Markdown file. When GitHub returns, reconcile it to the canonical issue. Avoid two competing permanent backlogs.

Git itself is distributed. If GitHub’s web services are degraded but Git operations still work, teams can continue committing and exchanging branches through the remote. If Git operations are unavailable too, local commits keep the work safe. For a prepared contingency between trusted machines, Git bundles can carry repository history without a live server. A second forge or internal mirror can provide a more complete continuity path, but only if the team has already rehearsed access, review, and reconciliation. Setting one up during an incident is not a shortcut.

Self hosted Actions runners solve a different problem: where jobs execute. They still connect to GitHub for job assignments, so they do not remove the Actions control plane dependency. A locally runnable test script does. A separate CI system can, if its triggers and repository access are independent too.

Reduce the amount of GitHub work per change

A giant PR asks the platform and the reviewer to do too much at once. Keep changes small enough to inspect and merge. Separate mechanical cleanup from behavior changes. Use feature flags or compatible incremental changes so one PR need not contain the entire release. Avoid automations that trigger redundant workflows on every push, comment, label, and issue edit. They add queue pressure and make it harder to tell which signal matters.

This is also where agent output can hurt. An agent that opens a PR for every tiny correction can swamp reviewers and checks. One that generates a thousand file change is worse. The useful middle is a coherent slice with a clear behavior change and a reproducible local result.

Decide what happens during an outage before one happens

For ordinary work, keep committing, testing, and reviewing locally, then publish when service recovers. For urgent production work, use the team’s documented emergency path, including independent review, recorded test evidence, and a later audit trail. If branch rules require a specific bypass, make that an explicit incident decision by the people authorized to make it. Do not give agents broad bypass permission so they can “keep shipping.”

GitHub should remain a useful place to coordinate and verify work. It does not need to be the only place work can happen. The practical goal is a pipeline that can keep making safe progress when a PR page, webhook, or runner queue has a bad day.

AI code quality: Ship fast without the fires

The October 2025 DynamoDB disruption spread through AWS after a race condition in automated DNS management erased the service’s regional endpoint. Its published cause was an automation defect, not AI-written code. That distinction matters. If we blame every outage on an LLM, we miss the specific mechanisms that made the outage possible.

The AI-related cases are narrower and messier. Reporting connected an AI coding tool to an AWS Cost Explorer interruption, while Amazon attributes that event to misconfigured access controls and disputes the reported cause. In separate Amazon retail incidents, the company says an engineer followed advice an AI tool inferred from an outdated internal wiki. These cases do not prove that faster AI development caused AWS’s broad outage. They do show how stale context and excess authority can give an ordinary mistake operational reach.

There is a cleaner example. In 2025, Replit acknowledged that its agent deleted data from a user’s application database while development and production data were insufficiently separated. The data was restored, but the production application could have been broken during the recovery window. Replit’s response was to separate the databases by default and keep the agent away from production data during development. The system had given a development tool production reach.

Most failures look less dramatic. An agent adds a retry around a payment call without an idempotency key. It makes a slow query pass the unit suite by mocking the database. It replaces a boring, explicit validation rule with a generic helper that accepts an empty value. Each diff can look reasonable. Each can make the application worse. Generate enough of those diffs, and the review queue becomes an exercise in finding one dangerous sentence in a book that keeps rewriting itself.

The old gate is getting squeezed

The traditional bargain was that a developer made a change, a reviewer read it, CI ran, and the team shipped. Those steps still matter. The trouble is the arrival rate. Agents can produce plausible changes faster than a team can understand them. A reviewer staring at a giant generated PR is likely to check syntax and style, then miss the changed behavior. A test suite assembled by the same agent can reinforce the same mistaken assumption.

The answer cannot be “add three more approvers.” That makes the queue longer without making anyone better informed. The real unit of review needs to get smaller, and the evidence attached to each change needs to get better. I argued for small, scoped changes before the current volume of agent output made the problem obvious. A reviewable diff has one job, names its expected behavior, and says which failure modes it considered. A generated feature that rewrites twelve unrelated files needs to be split before it reaches a reviewer.

Put checks where mistakes enter

Start before code generation. Give the agent the current source of truth: the domain terms, the relevant files, the interface it must preserve, and the operations it may perform. If the design is unclear, ask for a plan and a list of unknowns first. My ask, plan, confirm workflow is useful here because it makes a change in authority visible. A read only investigation should not quietly become a production edit.

Next, make every implementation change answer three concrete questions in its PR description:

  1. What behavior changed for a user or another system?
  2. What happens when the dependency is slow, unavailable, or returns an unexpected result?
  3. How will we know the change is wrong after deployment, and how will we back it out?

Those questions are more valuable than a declaration that “all tests pass.” Tests need to exercise the behavior, including a failed request, a duplicate request, and a partially completed operation where those cases apply. A retry that works on the happy path can duplicate an order. A migration that passes locally can lock a table under production load. The test plan should follow the risk, not the quantity of generated code.

Then put hard boundaries around the places where a wrong answer is expensive. Development agents do not need production credentials. Migration agents do not need permission to destroy live data to draft a schema change. Deployments that alter durable state deserve a separate authorization step and a recovery rehearsal. The Replit incident makes that point more clearly than any policy memo.

Review the behavior, then the shape of the code

“Clean code” is too easy to reduce to formatting. I want a reviewer to trace the new behavior through the caller, the domain rule, the persistence boundary, and the observable result. Does the code use the team’s vocabulary? Does it duplicate a rule already implemented elsewhere? Does it leave a clear place for the next change? Is the error path understandable to someone on call at 2 a.m.?

An independent review helps when it has a specific lens. Ask one reviewer to look for changed invariants and another to check operational failure modes. Give both the actual diff and current contract. Do not ask the authoring agent to certify its own work with a cheerful paragraph. In additive, mutative, and destructive changes, I used those categories to make the impact of a diff easier to see. They also help decide how deep the review and rollout need to be.

Finally, use production as a feedback loop without treating customers as the test suite. Release behind a flag when practical. Start with a small cohort. Watch error rate, latency, saturation, and business outcomes. Have a known rollback path. If the change modifies data, confirm that rollback restores behavior even when old code meets new data. An automatic rollback triggered by a reliable signal beats a heroic incident call after everyone has gone home.

Change the throughput target

The target is not generated lines per engineer or PRs merged per day. It is useful behavior delivered without borrowing trouble from next week. Track how often a change needs a follow-up fix, how long failures take to detect, and how easily the team can restore service. If those numbers get worse while code output rises, the pipeline is accelerating in the wrong direction.

AI can make the first draft cheap. Understanding the system, containing the blast radius, and learning from what shipped are still the work. A faster keyboard makes those jobs more urgent.

Long-running coding agents: When to stop and split

I have written about Herdr as a place to see all the agents and about why I give spaces, tabs, and panes specific jobs. A multiplexer helps me find the agent that is blocked on a question. It does not tell me whether the agent should still be working on that question at all.

That distinction matters when several agents are active. Six sessions can all report “working” while two implement the same feature, one waits on a test process that will never exit, and another repeatedly rewrites a file to satisfy an impossible prompt. The dashboard is truthful about process state. It is silent about whether the work is useful.

Give each run a finish line

Before starting an agent, write down its owner, scope, expected output, and stop condition. “Improve the billing service” has no finish line. “Add an idempotency check to POST /charges, show the duplicate request test, and stop before changing the database schema” does. The run can finish, fail, or ask for a decision. Each state has something a human can inspect.

I also set a budget appropriate to the task: elapsed time, tool calls or tokens if the platform exposes them, files touched, and number of attempted approaches. These are tripwires, not productivity scores. An agent spending twenty minutes on a slow integration test may be doing exactly the right thing. An agent spending twenty minutes alternating between two incompatible implementations is not.

A useful checkpoint is a short record of what has changed, what has been verified, what remains, and what is blocked. The evidence should be commands and artifacts, not just the agent’s confidence. If a long run cannot say what changed since the previous checkpoint, I want to inspect it before buying another hour of execution.

Long running can be legitimate

Some work has a real long pole. A full build, a large data migration rehearsal, a cross platform test matrix, or a carefully scoped investigation may need hours. The clue is visible progress against a fixed plan. The agent reaches milestones, the diff stays within scope, test results accumulate, and the remaining work gets smaller. The clock alone is a poor judge.

Other runs are long because the task contains too many different verbs. The agent is asked to research a domain, design an API, implement it, update dependencies, test it, deploy it, and review its own work. Each phase changes what “done” means. The conversation grows, old assumptions remain in context, and the agent starts using its own earlier guesses as facts. That is where I stop and split the work.

My practical test is to ask whether the current run can be reviewed without replaying the entire transcript. If the answer is no, ask for a checkpoint and create a new task with the verified facts. Split at a decision boundary: investigation into a brief, brief into a design, design into one implementation slice, implementation into an independent review. Do not split a single atomic edit into five agents just because parallelism is available. The handoff can cost more than the edit.

A checkpoint decision: continue a run with verified progress, split work with multiple decisions, or stop work without new evidence

Supervise the queue, not every keystroke

With several agents, I want one visible register of active work. A simple table is enough: task, owner, branch or environment, paths or interfaces owned, state, last checkpoint, and next decision. The multiplexer tells me where the process is. The register tells me what the process is allowed to change. When an agent goes blocked, I answer the decision once and record it where the next session will find it.

I keep a limit on simultaneous writers. More agents do not automatically mean more completed work. They create more integration edges and more reviewer load. Read only investigators and reviewers can often run alongside an implementer. Two agents changing the same contract, deployment configuration, or migration sequence need sequencing even if their files are separate. Worktrees isolate files; they do not isolate architecture, a shared database, or the main branch after merge.

The review agent gets a different job from the writer. It reads a committed diff and reports behavior risks with file and line evidence. It does not silently fix what it finds. A fix becomes another scoped implementation task. That keeps the person supervising the queue from confusing an agent’s reported success with independent verification.

A run needs an end, even when the project does not

“Keep going until everything is perfect” is an expensive prompt and an impossible stop condition. I prefer a bounded assignment that can end with a useful handoff: what landed, what failed, what remains, and the exact next slice. A fresh session can consume that handoff plus the source files. It does not need the entire history of abandoned attempts.

There are exceptions. An agent supervising a known batch job may stay alive to watch it, provided it has a timeout, a clear alert condition, and no open ended permission to change the system when something looks strange. A long lived process should be easier to audit than a short one, because it has more opportunities to drift.

A punch list for a busy team

  1. Name one owner and one finish line for every agent run.
  2. Record the paths, interfaces, and environments each writer may touch.
  3. Limit concurrent writers to the number the team can integrate and review.
  4. Set checkpoints and tripwires for time, tool use, diff size, and repeated failed approaches.
  5. Split work at design, implementation, and review decisions. Preserve verified facts in a short handoff.
  6. Give production resources separate permissions from development resources.
  7. Run meaningful behavior and failure tests before merging, then review the combined result.
  8. Ship with observability and a recovery path, especially for data and deployment changes.

The aim is not to keep every agent busy. It is to keep the codebase coherent and the application boring to operate. A blocked agent is easy to spot with the right tool. A busy agent making the wrong change needs a clear assignment, evidence, and someone willing to stop the run.

AI agent collisions: Worktrees aren't enough

Two developers editing the same service at once is older than Git. One changes an API, the other writes a caller against the old shape. One migration lands, the other assumes the previous schema. The collision may wait until integration, but nobody invented it with coding agents.

Agents compress the timeline. They can start the overlapping work within seconds, finish competing implementations before either human sees a diff, and spend tokens repeatedly “fixing” each other’s changes. A human collision can cost far more than the token bill, sometimes an order of magnitude more once meetings, rework, and a delayed release are counted. That is a scenario, not a universal ratio. The new problem is how quickly both kinds of cost can accumulate while everyone thinks parallel work is progress.

I have already written the case for giving each agent its own worktree. Set that option aside here. Even with separate directories, two agents can change the same behavior, rely on incompatible contracts, or point tests at the same database. We need ways to manage the work itself.

Assign ownership at the level that matters

File ownership is a useful start, but interfaces are the real collision surface. If one agent changes the response shape of GET /orders and another changes the frontend that consumes it, they are collaborating on one contract. Give one task ownership of that contract and sequence the dependent implementation after the new shape is agreed. If parallel work is valuable, freeze the interface first and let both agents build against a shared contract test.

The same rule applies to domain terms, schemas, feature flags, and deployment configuration. A small task register can say: agent A owns the API contract and tests; agent B owns the UI after the contract is approved; agent C performs a read only review. It need not be a complicated scheduler. Its purpose is to stop two plausible plans from quietly disagreeing.

Use short leases on hot areas. A lease says who is editing a shared contract, when they expect to hand it off, and where the result will appear. It is a social protocol with a visible record, not a file lock that magically prevents bad code. If an agent exceeds the lease, review progress and renew or split the task. Do not let an abandoned session hold the architecture hostage all day.

Choose the kind of parallelism deliberately

Some tasks are naturally parallel: read only investigation, documentation of settled behavior, tests for a frozen contract, or independent review. Others are sequential: a migration followed by code that assumes it, a public API change followed by client updates, or two fixes to the same state machine. Forcing the second group into parallel execution creates integration work disguised as speed.

When the work can be split, split by stable boundary. “Agent A handles orders, agent B handles billing” may work if the interface between them is already explicit. “Agent A edits the first half of the file, agent B edits the second half” probably will not. File lines are not architecture. A good boundary gives each agent a testable outcome and few shared assumptions.

Another option is a single writer with several readers. Ask separate agents to investigate edge cases, inspect the current behavior, or critique the plan. Feed those findings to the writer after a human checks them. That gets the benefit of parallel thought without parallel mutation. It is particularly useful in a sensitive area where three implementations would be hard to reconcile.

Isolate the shared things that are not code

Separate branches do nothing for a shared development database, a common staging environment, one cloud account, or the same test tenant. Give agent runs separate databases or schemas where practical, unique test data, distinct ports, and credentials limited to their task. If isolation is not available, schedule the shared resource as a single writer and make its current owner visible.

Generated artifacts need the same care. Two agents can each pass tests locally, then regenerate the same client library from different versions of a schema. A dependency lockfile can change under both tasks. A shared cache can hide an integration failure. Decide which task owns generation, pin the input, and test the combined result after both changes are present.

Detect conflict before merge time

At task start, have each writer declare the files, interfaces, and resources it expects to change. Recheck that declaration when the diff expands. If an agent discovers it needs a boundary owned by another task, it stops and asks. This is a cheap rule, and it prevents a lot of expensive “helpful” edits.

At integration time, do more than resolve text conflicts. Run contract tests and the affected application path against the combined code. Look for two implementations of the same behavior, changed assumptions about defaults, and migrations whose order matters. A clean merge only proves Git could combine the files. It says nothing about whether the resulting application makes sense.

When a collision does occur, preserve both task intents before choosing a fix. Ask what behavior each agent was trying to protect, then select the contract the product actually needs. Blindly asking agents to reconcile each other’s diffs often creates a third implementation that nobody intended.

Keep parallel work cheaper than serial work

A small number of clear assignments, visible ownership, bounded runs, and one integration pass will beat a large crowd of agents whose outputs need arbitration. Count rework and review time alongside token use. If adding another agent makes the queue of conflicting diffs longer, reduce concurrency or stabilize the interface first.

Collisions were always part of software development. Agents make them arrive while the coffee is still hot. The fix is to make the boundaries, contracts, and shared resources explicit before the work starts, then check the integrated behavior before calling it done.

Spaces, Tabs, Panes, and Precise Words: Why I Break Agent Work Out the Way I Do

In the previous post I toured Herdr and how I lay it out: one space per folder, one tab per kind of work, agents in tall columns, shells in short stacks, all of it spread across a 5120×1440 ultrawide. That’s the what. This one is the why, and then the part that actually decides whether any of it pays off: how I talk to the agents once they’re in their panes.

Short version: the layout isn’t decoration. It’s context management for two kinds of brains, mine and the models’, and the prompts are the same idea at a smaller scale. Every tool in this stack, Claude Code, Codex, Cursor, and the human, gets worse the more unrelated junk is in its head. So I keep the junk out, structurally first and then verbally.

Part 1: Why I break it out like this

Spaces are folders because the folder is the agent’s whole world

An agent’s working directory isn’t a detail. It’s the edge of its universe. Whatever it can read, grep, build, and break starts at that folder. So when I make one space per folder, I’m not organizing windows. I’m drawing the same boundary the agent already lives inside, and making it visible to me.

That buys three things:

  1. The sidebar is a readout of my working memory. Ten spaces means ten things in flight. If a folder isn’t in the sidebar, I’m not working on it. When I’m done, the space goes away. There’s no “misc” space and no “scratch” space, because “misc” is where context goes to die.
  2. Blast radius is legible. If something is going sideways in ledger-service, the dot next to ledger-service says so. Nothing in that space can be quietly editing storefront-web, because it doesn’t live there.
  3. It pairs with worktrees. When I need two implementation agents on the same repo at once, each gets its own worktree and its own branch, and in Herdr that’s just another folder, so another space (herdr worktree create does this directly). I made the full case in Giving Every Agent Its Own Branch: Git Worktrees for Parallel AI Work: “Run two coding agents against a single working tree and they will fight.” Spaces-as-folders keeps the referee’s view honest.

Tabs are modes because each mode is a different verb

I name tabs domain-modeling, implementation, and pr-reviews because those are three different jobs. Each one comes with a different posture from me and a different register of prompt to the agent.

Tab The verb My posture What the agent is allowed to do
domain-modeling think Skeptical, Socratic Read, reason, write a model. No code. Plan mode.
implementation change Directive, fenced Edit inside an explicit scope, after an approved plan
pr-reviews judge Adversarial, evidentiary Read the diff, report findings. No fixing.

The failure mode I’m designing against is verb drift. You start a conversation reviewing a PR, you say “huh, good catch,” and three messages later the “reviewer” is rewriting the module, now with the confidence of something that just graded its own homework. Separate tabs, and separate agent sessions in them, make the verb change explicit. If I want a fix, I go to the implementation tab and ask for one there, with a scope. It’s the same rule I put on the read-only reviewer agents in Ask, Plan, Confirm: Making Agents Stop Before They Start: the reviewer doesn’t get to “slide from ‘here is a finding’ into ‘and I fixed it’ without crossing the same line everyone else crosses.” The tab is that line, drawn on screen.

There’s a human benefit too. When I switch to a tab named pr-reviews, my brain switches hats before I’ve read a word. Mode labels are cheap and they work.

A pane is one agent, one context window, one job

Every agent pane gets one job for the life of that conversation. When the job is done, the conversation ends, and the next job gets a fresh agent. Context windows are big now, but they aren’t free and they aren’t clean. Every stale plan, abandoned approach, and “actually, ignore that” sits in there and pulls on the next answer. A pane per job is the cheapest context hygiene there is.

The panes next to an agent are there for verification, not decoration:

  • In domain-modeling, the glossary and domain notes sit beside the agent, so I can check that it’s using the words we agreed on.
  • In implementation, a diffstat and a shell sit beside the agents, so I can see what actually changed, not what the agent says changed.
  • In pr-reviews, the raw diff sits beside the reviewer, so every file:line it cites can be checked by moving my eyes and nothing else.

Trust, but keep the evidence in the same field of view.

Tall for agents, short for shells, and why 32:9 matters

Agents emit long, structured output (plans, findings, tables), so they get full-height vertical splits. Shells and watchers are glanceable, so they get short horizontal stacks in a utility column. That isn’t a style choice. It’s matching pane shape to how much reading each pane needs.

The ultrawide makes it work without compromise. At 5120×1440 I get three or four full-height agent columns and the utility column and the sidebar, with nothing hidden behind a zoom or another tab. That matters for one reason above all: a blocked agent is a cost that accrues silently. Herdr’s sidebar tells me that something is blocked. Having it physically on screen tells me why, in peripheral vision, without moving. The less effort it takes to notice, the shorter the stall.

Part 2: Keeping Claude, Codex, and Cursor effective and accurate

All of the above is plumbing. The water is language.

I’ve been on this soapbox a while. In Precision in Words, Precision in Code: The Power of Writing in Modern Development I argued that “Writing isn’t just ‘extra work’—it’s the work that clarifies, simplifies, and accelerates everything else,” and in AI Prompt Engineering: Mastering Language Constructs I went into how the actual constructs, imperatives, conditionals, and contextual markers, shape what comes back. With agents that act, not just answer, the stakes go up. A vague word in a chat gets you a vague paragraph. A vague word in an agent prompt gets you a nine-file diff.

Here’s what I actually do. Every example below is a real prompt and a real response, captured for the screenshots in this repo with Claude Code in plan mode against throwaway demo projects.

1. Use the domain’s words, and ban the overloaded ones

Accurate language starts with the same word meaning the same thing every time: in the docs, in the code, in the prompt, in the review. That’s just ubiquitous language from domain-driven design, and agents need it more than humans do, because they fill every gap with the most statistically likely meaning, which is rarely your meaning.

So I keep a glossary in the notes repo (more on that in Notes Repos as Shared Project Context, where the glossary is described as “cheap insurance against confident mistakes”), and I put the words in the prompt, including the ones that are off limits:

Read docs/domain.md and internal/ledger/entry.go. Using only the domain terms Account, Entry, Journal, and Posting (never ‘transaction’), describe a Posting aggregate: its invariants, what it owns, and what it must reject. Do not write code. Output a short markdown model.

“Transaction” is banned because in a ledger it’s hopelessly overloaded: a database transaction, a business event, a bank-statement line. Pick one meaning, give it its own word, and forbid the ambiguous one. Here’s what came back:

Two things to notice. The model sticks to Account, Entry, Journal, Posting the whole way through. And it marks which rules it inferred from general double-entry practice versus which came from the repo: “Rules marked (inferred) come from standard double-entry practice, not the repo.” That distinction is gold in domain modeling, and it showed up because the prompt was explicit about where the truth lives (those two files).

2. Lead with scope, as the first word

My implementation prompts literally start with the word Scope:.

Scope: cmd/main.go only. Plan a minimal CLI entrypoint that loads a Journal from a JSON file and prints the balance per Account. Do not touch internal/ledger. Keep the planned diff under 50 lines.

Scope first, because everything after it gets read in its light. Then a positive fence (only this file), a negative fence (not that package), and a size limit stated as a number, not a vibe. “Keep it small” means nothing. “Under 50 lines” is checkable. I went deeper on why scope and diff size are the main levers in Hurting or Helping Devs?.

The payoff:

The repo had no go.mod, so cmd/main.go couldn’t import internal/ledger. An unfenced agent “fixes” that by adding a module file, rewiring imports, and maybe stubbing a Journal type in the package I’d fenced off. This one stopped and asked, offered the in-scope option as the recommendation, and named the out-of-scope option as out of scope: “This touches a second file, which goes beyond the cmd/main.go-only scope.” Herdr flagged it blocked, and I could see it on the ultrawide without switching anything. That’s the whole system working: precise words create the stop, and the layout makes the stop cheap.

3. Pick verbs that mean exactly one thing

plan, implement, review, and fix are different verbs, and I never let one stand in for another.

  • Plan means produce a plan and change nothing. I back it with tooling: agents start in plan mode (claude --permission-mode plan; Codex and Cursor have their own read-only and ask-first modes), so the verb and the permission agree.
  • Implement means change things inside the approved plan’s scope, and only after an explicit yes. Approval is scoped to the plan that was approved. This is the three-beat gate from Ask, Plan, Confirm.
  • Review means read and report. It doesn’t mean fix.
  • Fix means a new implementation task, with its own scope, in the implementation tab.

When the verb is precise, the agent’s job is precise, and so is my evaluation of whether it did the job.

4. Specify the shape of the answer

If I can’t check an answer quickly, I’ll check it badly. So I specify the output format in a way that’s easy to verify against the pane next door:

Review the diff main…feature/posting-aggregate. Classify every change as additive, mutative, or destructive. Flag any naming that drifts from docs/domain.md. Report findings as a numbered list with file:line. Do not propose rewrites outside the diff.

“Additive, mutative, or destructive” isn’t decoration either. It’s the vocabulary from Additive vs. Mutative vs. Destructive Code Changes (and Why AI Agents Love the Wrong One at 2:13AM), and giving the reviewer that vocabulary makes it classify instead of just commenting.

And because the question was precise, the reviewer had attention left over for what mattered. Under “side notes” it flagged that any Direction other than the exact string "debit", including "" or "Debit", gets counted as a credit, and that an empty Posting passes validation as balanced. Neither is a naming issue. Both are exactly the kind of quiet behavioral drift that post warned about: code that looks right and behaves like an alien artifact. A vague “please review this PR” tends to bury that under eleven style nits.

The same pattern works for any review lens. On the storefront demo, “integer cents only, no floating point until display formatting. Numbered findings with file:line, severity first” produced a short, ranked list I could verify in about thirty seconds.

5. Front-load the context instead of looping for it

A thin prompt plus five rounds of correction is worse than one well-fed prompt, and more expensive. I made that argument at length in “Loop Engineering” Is Mostly Just Broken SDLC Wearing a Costume: “A well-fed single pass beats a starved five-pass loop most of the time.” In practice that means every prompt names where the truth lives: the files to read, the glossary, the plan in the notes repo, the decision that was already made and shouldn’t be re-litigated.

It also means the environment has to be ready. An agent that can’t build, test, or reach the systems it needs will improvise, and improvisation is the opposite of accuracy. The checklist I use for that is in Agent-Ready Local Environments and MCP: “An agent with broad access and no rules will eventually do something technically impressive and socially awful.”

6. Same template, any agent

Claude Code, Codex, and Cursor have different personalities and different defaults, but the prompt shape carries across them. Herdr doesn’t care which one is in a pane. It detects them all, so I can put a different tool in the reviewer pane than the one that wrote the code. A second model has different blind spots, and that’s the point of a second opinion. The template:

Scope: <path(s)> only. <Do not touch: path(s)>.
Context: Read <files / glossary / plan>. Use the terms <A, B, C>; never <overloaded term>.
Task (<verb: plan | implement | review>): <one sentence, one job>.
Constraints: <additive only | under N lines | no new dependencies | tests first>.
Output: <numbered list | file:line | severity first | markdown model | test names first>.
If anything above is ambiguous or blocks you, stop and ask.

That last line matters most. It turns “the agent is stuck” from a silent failure into a blocked state, which Herdr turns into a dot I can see from across the room.

7. When an agent goes blocked or done

The loop on my side is short and boring, on purpose:

  1. Blocked: read the question in place (it’s already on screen), answer it, and if the answer is a decision, write it into the notes repo’s decisions file so the next session doesn’t ask again.
  2. Done: read the output against the evidence pane next to it. If it’s a plan, approve it or correct it. If it’s findings, open a scoped implementation task in the other tab for anything worth fixing.
  3. Finished job: end that agent’s conversation. New job, new agent, clean context.

The point of all of it

The spaces, tabs, panes, and ultrawide exist to keep context small, boundaries visible, and stalls cheap. The prompting exists to keep meaning precise. Neither works without the other. A gorgeous Herdr layout full of agents with vague instructions is just a very wide way to watch things go wrong in parallel, and the most precise prompt in the world doesn’t help if the agent has been blocked on it since lunch and you never noticed.

Draw the boundaries on screen. Draw them again in words. Then let the agents work.

References

Herdr

Previously on Composite Code

Elsewhere