LUCIANO CARRIZO
All articles Programming

Three roles, not twelve: the agent system that remained

An orchestrator that writes prompts and verifies what comes back, a research role accountable for its sources, and an implementation role accountable for leaving the repository green. This is the system I now use to delegate work to AI agents, after trying an entire org chart of managers and specialists.

Delegating a task to an agent is easy. Delegating work to several agents on the same repository, and getting something useful back without having to redo it, is a different problem. I have been assembling and dismantling systems for that purpose for quite a while. One version had a company org chart—area managers, specialists, an agent dedicated to creating agents—and others were much smaller. What remained is considerably smaller than what I began building, and it works better.

An agent system does not improve by having more agents. It improves by making clear who decides, who executes, and what each one can see.

One clarification before starting: this is not chronological. I worked on several projects in parallel and do not remember the actual sequence, so what follows describes conceptual stages, not a journal. The focus is the system as it exists today. Earlier versions appear because they explain why today’s system has its current shape.

The real problem with delegation

It almost never failed because an agent did not know how to perform the task. It failed because the agent did not know where its authority ended.

Who defines the scope? Who decides something is finished? Who can merge and who cannot? Who needs to know what happened? A highly capable agent given a poorly delegated task does not return an error. It returns work that looks finished but is not. That is much worse: you discard a visible error in a minute, while plausible work follows you until the moment you touch it.

That is why my problem stopped being how to write better instructions and became how to distribute responsibility. They are not the same. Instructions explain the task; distribution explains what happens when the task turns out differently from what you expected.

The org chart that did not scale

The most ambitious version I built was literally a company. There was an orchestrator I spoke with and a chain below it: an agent owning the API contract, a frontend area manager, a backend area manager, and specialists reporting to them by kind of work—schema design, component construction, routes, pages, API mocks. The orchestrator worked in phases and always began with the API contract, because both managers depended on it to start in parallel without stepping on one another.

Above all of that was a meta-agent, the only one authorized to modify other agents’ files. It could not modify the orchestrator; only the orchestrator modifies itself. It also classified agents as permanent or temporary and verified that a new agent did not overlap an existing one. That detail says a great deal: even in the largest version, the problem requiring supervision was duplicated roles.

The principle they all shared appears verbatim in my working memory for that project: “define WHAT, not HOW.” It was not a bad principle. There was an even heavier version in another e-commerce project, where the system declared context packages, a stack of skills and workflows, and roles beyond technical ones: SEO strategist, legal compliance, design critic, cross-track auditor, wireframe renderer.

It died for one reason, and not because it was badly made: it served large projects with heavy structure. Applied to a small project, preparation cost more than execution. Building the org chart, keeping it coherent, and feeding it context was more work than doing the task by hand. There was also a stage before all this organized around which model did what. No trace of it remains on disk, and I will not reconstruct it from memory.

Three roles, and why three

What survived has three roles: the one who coordinates, the one who researches, and the one who implements.

The coordinator is the orchestrator, and it is the one I speak with. I have kept its definition since the version in which the system began to stabilize, written in the orchestrator’s own voice. I quote it because the end of the sentence is what matters: “I act as ORCHESTRATOR: I write prompts, dispatch agents, and VERIFY their deliverables independently (I do not take the agent’s word for it; I run the gates myself).” An agent saying it finished is not evidence that it finished.

Here is the detail that makes three enough, and it is almost never mentioned when people show their agent systems: each role has a different gate. A gate is the condition under which the work is accepted, not the task the agent performs.

  • Research is accountable for its sources. It has a source contract: invented URLs are forbidden, current and legacy material must be distinguished, and a major decision cannot rest on one source. Its deliverable is a document.
  • Implementation is accountable for the repository. Its gate is Git plus a definition of done that can be verified by running something: not “I tested it,” but a command that either succeeds or fails. Its deliverable is a PR.
  • The orchestrator has no gate of its own; it is the gate. It does not deliver code. It delivers the verification of what the others delivered.

Seen this way, the question “how many agents do I need?” changes shape. Two agents accountable to the same gate are not different roles; they are the same role with two names. The org chart had twelve names for what, at the level of accountability, was a handful of answers. Component, route, and page specialists had different tasks and the same acceptance criterion. That is not organization. It is the same responsibility spread across more files that must remain synchronized.

Every prompt comes from a master guide with a shared core and variants for each kind of work: research, feature, fix, documentation. The core is what never changes; the track is the small part that does. Making the difference between prompts small and explicit is precisely what prevents a new role from appearing every time a new task appears.

One clarification about distribution is as important as the roles themselves: the researcher is not always used. If the answer is already in the repository, sending out a research round is a round trip that adds nothing but context. The system does not require every role on every task. Having three roles available does not mean dispatching all three.

One last detail about the distribution matters more than it appears: deliverables are versioned; prompts are not. Research documents live in the repository. The prompts that produced them are excluded by .gitignore, except for the base guide. The prompt is scaffolding; the deliverable is the structure that remains. Saving the scaffolding for every finished task helps nobody read the project months later.

The coordinator does not pull the trigger

One rule looks like a pointless limitation at first and has prevented more problems than most: the orchestrator finishes the prompt but does not launch it.

It writes the entire prompt and leaves it ready, then I open it in another terminal. I recorded that decision verbatim when I made it—the implementation prompt remained ready and marked not dispatched because I launched it myself—and it still works that way today. That friction buys a person standing between “the plan is written” and “the work has begun.” It is the only point where someone can read the entire assignment before it becomes commits, and reading it costs less than reverting it.

The other half of the asymmetry is what really matters: the orchestrator may launch specialized agents; a delegated agent never launches another agent. If a delegated agent believes delegation is needed, it requests authorization and stops.

That rule has a concrete origin, recorded on the day I wrote it: a delegated agent launched subagents with its own prompt, recursively. I did not record exactly what broke, so I will not embellish it; the mechanism is enough. A prompt that contains an instruction to delegate and delegates itself has no internal reason to stop. The rule is not there to make the system tidier. It is there to give it a floor.

What the coordinator sees—and does not see

This change produced the most value of all and is the least showy because it adds no piece. It only changes who can see what.

A delegated agent sees its prompt and nothing else. The directory containing the system is gitignored, so agents literally do not see it. That sounds like a defect and acts as a useful constraint: everything necessary must travel inside the prompt. A prompt that says “as we discussed earlier” is broken because the agent was not in that conversation. When a prompt must be self-contained, gaps in the assignment appear while you write it, not halfway through the task.

The orchestrator sees the summary, not the transcript. It used to reread everything each agent did to learn the state of the work, which is exactly how you spend on one side what you save on the other. Today every prompt ends with a mandatory close: the agent saves a summary to memory before opening the PR, and its final message lists the commits, the PR number, and confirms it merged nothing. The orchestrator reads that and the delivered files—which it verifies independently rather than accepting on trust—and that is enough.

Agents do not see one another; memory is the channel. The clearest example in this project is the component catalog page. Implementation agents do not write it. They leave a component sheet in memory in a fixed format and continue with their work. Later, one agent reads every sheet and writes the page. That solves two problems at once: documentation follows one criterion instead of one per agent, and a file that was becoming a merge-conflict magnet is no longer modified from multiple branches at once.

This is where memory stops being a convenience and becomes structural. It is not there to make the system more pleasant to use. It lets two agents that never speak work on the same thing and lets the coordinator know the state of everything without rereading anything.

This is what the system looks like in this project, the shortest way to show the distribution:

.agents/
_continuar.md      # state: where everything stood between one session and the next
cicatrices.md      # errors already made, so they are not made again
_prompts-guia.md   # template: how to build a delegable assignment
prompts/           # one-task assignments, launched by me in another terminal
agents/            # reusable agents, launched by the orchestrator

I pay the cost of all this in one place, and it is worth stating here: the orchestrator remains, by far, the agent that consumes the most context, even after reducing it considerably. It is the only one that must hold the complete state. Distributing the work does not distribute that burden; it concentrates it.

The rules came from mistakes

None of the system’s hard rules came from a good idea. Every one came from something that happened.

The record that began the current version is titled not for what it builds but for what it prevents: it is the orchestration system created “so the problems do not happen again,” and those problems are listed there—an agent finishing without leaving a summary, scope creep, recursive subagents. It is a list of mistakes, not an architecture. What was established that day remains almost unchanged: nobody merges the stable branch—it only receives a PR from integration, and a person authorizes that merge case by case; only orchestrators merge the integration branch, always through a PR; normal agents open a PR from their own branch and save their summary before opening it; and commits contain no AI self-reference.

Those rules addressed concrete failures: agents that did not follow good commit practices, agents that did the work but did not open a PR, and more than one implementer merging when it had no authority to do so. They also produced the scars file, which is exactly what its name says: construction gotchas for this project, things already broken once. It differs from behavioral rules—it does not say how to work, but where you will get hurt—which is why it lives in its own file.

It worked, and it carries a cost I do not want to hide because it remains an open, unsolved problem: agents begin already loaded before reading one line of code. Continuity and scars weigh more than the project rules, and then the prompt adds the design documents it requires them to read first. Every avoided mistake leaves a paragraph, and paragraphs accumulate faster than solutions. Today I consider that a fair price—I prefer a loaded agent to one repeating a mistake we already made—but it is far from solved, and it is the next thing I need to address.

The three irreducible pieces

If I had to move the system to a clean machine and could take only three things, I know exactly which ones.

The orchestrator. It must always be there. It is the role that cannot be distributed: as soon as more than one agent is deciding, you do not have a distributed system; you have competing criteria acting on the same repository. And it is not only who decides but who verifies. An agent system with nobody running the gates accepts work based on the declaration of whoever performed it.

The delegation template. One file containing the assignment’s structure so that the contract is not rebuilt every time. This is not about saving keystrokes. It makes the assignment complete even when you write it in a hurry. The template always forces you to state who the agent is and which project it is in, what it must read before touching anything, the task and its definition of done, what is forbidden, how the result is verified, and how the work closes. Without it, the first thing that disappears—always—is the definition of done, precisely what separates an agent that delivered from an agent that ran out of turn.

Memory. The orchestrator’s continuity file, or a persistent memory system directly. It comes third deliberately, not by importance but by dependency order. Without an orchestrator, nobody delegates. Without a template, every delegation starts from scratch and the system does not survive haste. Without memory, the system works just as well—for one session. Memory is not what makes the system exist. It is what makes it last longer than one session, and that is the part people consistently underestimate. The orchestrator fills its context, and when it fills up, you either lose the state or had it written somewhere.

This order only becomes visible when something fails. With memory but no template, you have a great deal of saved context about poorly formulated assignments. With a template but no orchestrator, you have immaculate assignments that nobody verifies.

I know these are the three, and not others, because they reappear. In another version of the system—one with an entirely different distribution and different names—the central agent was explicitly told not to write code except for very small, surgical changes. Its work was to maintain the global project context, write subagent prompts, verify through Git and the actual files that work was truly finished, and recover state from memory at the start of every session. Coordinate, delegate through a written contract, remember: the same three pieces in a system I later discarded. Everything else is what each rewrite removed.

What actually improves

This is my assessment, not a measurement, and the cost belongs beside the benefit: the system is paid for in preparation time and collected in structure.

What I notice is that work returns in the shape of team work rather than prompt output. There are branches per task, readable atomic commits, PRs explaining what was done, issues framing why it was done, and a review before anything touches the stable branch. None of that happens because an agent is smarter. It happens because the assignment requests it and someone verifies that it happened. The final quality I gained did not come from better answers; it came from answers arriving within a frame.

There is also a side effect I value more than expected: if the system does not serve me, I change it immediately. The orchestrator is the role allowed to modify the system while it runs, and because everything lives in plain-text files, nothing has to be redeployed. A rule that becomes annoying can be rewritten in the same session in which it caused annoyance. That keeps the system from aging through the accumulation of obsolete rules nobody dares to touch.

I will not claim it is free. Preparation costs, and the cost arrives before the return begins. The difference from earlier versions is not that this one costs nothing. It is that it costs little enough to pay off in small projects too, exactly where the org chart collapsed.

What is still manual

Here is the uncomfortable part, and I prefer to end with it.

There is no real automation. When I begin a new project, I ask an agent to copy the system from the previous project and adapt it. It works, and it is exactly the kind of thing a system about delegation should first solve in its own home.

I built an initialization skill for that, and I want to be precise about how I present it because it is neither a failure nor a solution. It installs the system’s skeleton by delegating installation to its own agent, using versioned templates. Its policy is the most successful part: synchronize what is managed while always preserving local state. Existing continuity, scars, and prompts are never overwritten. It validates Git and remote state before writing anything, and if a managed file differs from its recorded version, it requests approval before replacing it. I built it during this project and have not yet applied it to a new one. It saves initialization time but does not fix what was missing—and that distinction led me to what comes next.

What comes next is a separate system that is designed and unbuilt. I will not describe features that do not exist. I can state the motivating idea because it is the one I find most convincing: record an immutable parent-child relationship whenever a branch is created, then use it as the source of authority for opening PRs. Today that authority lives in written rules an agent can misread. There it would live in repository state, which cannot be misread.

No dates and no promises. The honest ending is this: I built a system that makes delegation easy and is still difficult to install. Neither half surprises me. I worked on one for months and never worked on the other. It is the same mistake I criticize in the org chart—preparing too much, starting too late—committed one level higher.

Next step

The article explains the decision. The technical case shows the code.

The portfolio projects are documented end to end: architecture, decisions, and what remains unfinished.

or directly → LuchoC.dev@gmail.com