
Practical Process (and Guardrails) for Agentic Projects
What I learned building a working multi-agent system.

What I learned building a working multi-agent system.
At some point, running one AI agent on a project stops being enough. You split the work: one agent handling infrastructure and backend, another handling the frontend, maybe a third for a specific app or service. Then you discover a problem nobody warns you about going in: two competent, well-intentioned agents can still collide, duplicate work, act on stale information, or quietly disagree about who's allowed to decide what. None of this is a capability problem. It's a coordination problem, and it's the same one distributed teams of humans have always had, just compressed into a much faster feedback loop.
What follows is my own homegrown framework that emerged from actually running this stack, without designing it on a whiteboard first. Every pattern here exists because something went wrong without it, got fixed, and then had to be written down so it wouldn't have to be relearned the hard way. It's not a finished spec by any means - it's still evolving, in fact, but the general shape of how I structure agents in larger projects (web, app, video, editorial, animation, etc) has stabilized enough to be worth sharing.
Start with one source of truth, not two memories
The first mistake is letting each agent keep its own notes about how the system works. It seems harmless to let each agent remember its own context, write things down as it learns them, and that's efficient, right up until two agents' notes disagree. One agent believes a policy changed; the other doesn't know about it. One agent thinks it owns a decision; the other thinks it doesn't. Nobody notices until the disagreement causes a real problem, and by then it's not obvious which agent's understanding of the problem was ever correct.
The fix is boring but it works: a single canonical document - call it a roles manifest - that every agent reads, describing their hierarchy, ownership, communication rules, and the thresholds for when a human needs to be involved. Every agent's own instructions point at this file instead of duplicating its contents. When something about how the system coordinates needs to change, it changes in one place, and every agent reading it afterward sees the same thing. The manifest itself gets a lightweight but real change process - propose a change, let every affected agent weigh in, require a human to actually approve it - specifically because it's the one document nobody should be able to unilaterally rewrite, including the agent that maintains it.
There’s lots of ways to solve this - in my case I use a custom Apple Notes connector so we can work in Markdown format there (and I can read things across my mobile/Apple devices), it’s essentially a contract doc that’s synced each session. I know many that use Notion or Obsidian for similar processes to make sure the shared role corpus is centralized, updated and referred to as canon.
This sounds obvious in the abstract. It's not always obvious in practice because the alternative - each agent just remembering things in their own way - works fine for weeks at a time. The failures will seem rare enough to feel like edge cases until you've been bitten by two or three of the big ones, at which point the pattern becomes unmistakable: divergent private memory is just a bug that hasn't happened yet.
Decide, in advance, what needs a human, and default to asking
The obvious approach to autonomy is a checklist: enumerate the dangerous actions, require approval for each of them, let everything else run freely. But this fails quietly because you can't always predict every potentially dangerous action in advance. Something you didn't remotely anticipate will turn out to actually matter, and by the time it does, it's already a problem.
A more durable rule inverts the default: below the confidence threshold at which an action is safe and expected, stop and ask. Don’t be exhaustive about what's risky - be exhaustive about the fallback. Merging code, deploying anything, pushing a release, touching money or legal exposure, acting on anything genuinely ambiguous - all of it defaults to a human checkpoint, and "I wasn't sure, so I checked" isn't considered a failure. The expensive mistake is an agent that was 90% sure but acted anyway; the cheap one is an agent that paused to confirm something that turned out to be fine after all.
It's best to pair this with a deliberate, narrow escape hatch: a phrase a human can use to say, explicitly, "I'm authorizing you to complete this specific task without stopping for approval at every step." This level of autonomy should always be scoped to a specific task, not shareable between agents, logged clearly each time it's invoked, and explicitly excluded from covering the riskiest categories of action (for example, you don't want a blanket authorization to accidentally cover "delete the database" or "change the rules that govern all of this"). The point isn't to weaken the default. It's to give the human a clean, visible way to opt out of friction they've already decided isn't buying them anything for this task, without eroding the default for everything else.
On anything shared, work serially, and mean it
Two agents can each be doing something individually reasonable and still produce a collision if they're touching the same shared surface at the same time: a shared deploy target, a shared cache, anything with global, mutable state. The instinct is to let them work "in parallel, since neither one is blocking the other," but that's exactly how silent collisions happen: one agent is actively changing something while the other, believing itself merely "reading ahead" or "prepping," draws conclusions about state that's about to be invalidated.
The rule that actually holds is stricter than it sounds at first: only one agent works on the shared surface at a time, and the other is genuinely idle: not quietly reading, testing, or preparing in the background. Handoffs are explicit. If the idle agent thinks that something urgent needs attention, it says so and waits for the handoff rather than acting preemptively because waiting felt costly to it . This has caught real bugs in practice: a design decision from one agent conflicting with an optimization from the other, both individually sound, only visible once someone stopped and looked at them side by side instead of both shipping independently.
Split coordination into a live channel and a durable record
Agents need to negotiate constantly: who's doing what, who found what, what just changed. If that negotiation only happens on a slow, async, durable channel (an issue tracker, a shared document), it's too slow for anything that needs a quick back-and-forth, and people stop using it for the fast stuff, which means the record becomes incomplete exactly where it matters.
The better split: real-time coordination happens directly between agents, as fast and low-ceremony as the tooling allows. A separate, durable channel exists purely as a record: a summary posted after reaching a decision, not a place where the decision gets made. This gives a human overseeing the system something they can actually audit with no need to reconstruct a decision from two agents' private context, while not forcing every routine exchange through a slow, formal process. Plainly stated: this split is itself something that evolved. It started as a single async channel doing both jobs badly, and improved once it was explicitly split into two channels doing one job each, well. Expect to revise your own version the same way. Don't treat whatever you start with as the final architecture.
Let leadership follow the work, not the org chart, but say clearly what it isn't
With fixed assignments (one agent always leads repo A, another always leads repo B) the process is simple, but it breaks down the moment a project's nature doesn't match its repo. Backend-focused projects can turn into a design conversation partway through; a frontend project can turn into an architecture discussion. A more useful rule lets the lead follow the work currently underway, negotiated directly between the agents and logged for the record, rather than fixed by which repository holds the code.
This needs one explicit caveat, stated out loud rather than assumed: leading a project means driving the day-to-day thinking and effort on it. It does not mean deciding for the human, and it does not mean one agent's domain expertise outranks the other agent's or the human's judgment. It's easy for “Agent X is leading this effort" to quietly drift into “Agent X's calls are final" if nobody names the difference. Say it plainly, more than once if needed: the human is the final decision-maker in every area, always, regardless of which agent is currently driving the work. Delegating who does the legwork is not the same as delegating who decides.
Keep most agents narrow, and let them ask rather than reach
As the number of agents grows, the temptation is to give each one broad access so it can get things done without waiting on anyone: its own credentials for every system, standing visibility into every other repo. This is convenient right until it isn't: the blast radius of any single agent's mistake, bug, or compromised credential now includes everything it can touch, which under this model is everything.
A narrower shape holds up better. One agent (call it the coordinating or meta-agent) has broad, cross-cutting visibility because coordination is genuinely its job. Every other agent is scoped tightly to what it actually owns, and when it needs something outside that scope, it asks rather than reaches: an explicit, structured, auditable request to whichever agent owns the thing it needs, rather than standing access to go get it directly.
The concrete version of this that's worked well: a narrowly-scoped agent opens a structured, labeled request against the system that owns what it needs: naming what it wants done, what repo or context it's asking on behalf of, and enough detail for the receiving side to act without a live conversation. An automated process on the receiving end picks it up, does the work, and posts the result back to the same request, without a human or an always-on agent needing to be watching in real time. Nobody needs standing credentials for anything they don't own; every cross-boundary request leaves a visible, time-stamped trail; and the whole thing runs on ordinary, cheap automation rather than a bespoke service that has to be kept alive.
The corollary of note: if a request like this is ever a throwaway, a test, or explicitly not meant to be acted on as real, say so unmistakably, in the request itself, and have the requesting side clean it up once it's served its purpose. An unmarked test artifact sitting in a queue of real ones is exactly what gets picked up and treated as real by whatever's next in line to process the queue, automated or human.
Trust, but verify: especially claims relayed between agents
Agents report to each other constantly: what they did, what they found, what the human told them. All of this is genuinely useful, and none of it should be treated as automatically true just because it came from a peer instead of an unknown source. The discipline that matters here is small and cheap to apply, and it's easy to skip precisely because it feels unnecessary when the source "is on your team."
Concretely: if one agent reports it already fixed something, check the actual state of the thing before building further work on top of that claim. If one agent reports what the human told it, treat that as secondhand until the human confirms it to you directly, especially before writing it down as a standing rule that will shape future behavior. This isn't about assuming bad faith. Peer agents can be simply wrong, working from stale context, or accurately reporting something that doesn't apply where you think it does. A few seconds of verification is far cheaper than propagating a wrong assumption into a decision that's hard to unwind later.
None of this is finished
To be clear: it's a working system, not a settled one. Every rule in it exists because a real gap showed up first, and the system will keep changing as new gaps show up. What's important to keep constant through all of that change is the underlying posture: one source of truth instead of drifting private memory, a clear and low default for when to involve a human, genuine seriousness about serialization on anything shared, a live channel and a durable record doing separate jobs, leadership that follows the work without ever quietly becoming authority, and a standing habit of verifying claims before building on them.
Multiple AI agents working across a shared codebase is still a young enough practice that most of the failure modes haven't yet been named. This is one attempt at naming some of them early, hoping whoever reads this skips a few of the incidents it took to write it.
Got questions or want to talk more? I’d love to hear more. Hop over to my Discord and kick off a conversation. And be sure to drop your name into the announce list at our Creative AI book page so you get a ping when the book goes on sale (sometime in this coming month). Cheers!
Hero image modelled and rendered by hand in Blender.