Approach
Astragentic is built for autonomous coding: a team of AI agents runs the build on its own, while people keep direction and decisions.
Every team works its own way, and no process can be imported intact. So Astragentic is a scaffold: the hard parts are settled, and every component is open for you to adapt.
The six parts below are the six largest design decisions in that scaffold: the mechanism, the evidence on record, and the trade-off. These are my choices on my own projects, not a template you have to follow.
The orchestrator agent model: you set direction, Thomas coordinates
A coding agent today can carry the build: it takes work, writes code, runs tests, returns results.
What is left for you is not writing code. It is two other things, and they eat the time: answering the questions an agent raises while it works, and reviewing the quality of what comes back.
Both share one bottleneck. An agent’s technical questions usually exceed the expertise of the person directing it. The common workaround is to take the question to another AI and relay the answer back. At that point the human is a relay, and the decision has in practice been made by AI.
Astragentic removes that relay with two mechanisms.
Thomas, the team’s representative
Thomas holds the project context and stands between you and the agents:
- Reads the artifacts agents return, instead of pushing raw logs at you.
- Weighs the options and tech stacks they propose.
- Answers technical questions on the spot.
- Escalates to you what is yours to decide: product direction, user experience, priorities.
You work as the client of a development unit: set requirements, follow progress, and step in when the team drifts.
A team operating in the open
Every agent is a named session with its own pane in herdr, and its work history stays in that session. You can watch what each agent does. Thomas can trace an incident. The way agents coordinate becomes data for improving the scaffold itself.
Subagents and agent teams inside a runtime run hidden in the parent process. There is nothing to look at.
Trade-off. One more toolset to install, understand and upgrade, and every upgrade is an event the project has to absorb. So far I have proven that each tool runs correctly; the whole loop from dispatch to merge with every gate firing on real work is still being measured.
The issue tracker holds the state, not a markdown file
The state of the work has to sit outside an agent’s context, and you have to be able to open and read it. An issue tracker is the only place that does both.
The common approach before this was to let the AI slice work into markdown files and track it with checkboxes. That breaks at both ends: the agent has to remember to go back and edit, and you have to open a file to read it.
| Markdown file | Issue tracker | |
|---|---|---|
| Updating status | The agent must remember to tick the box | One status field, changed by one command |
| Checking progress | Open the file, read a few hundred lines | Open the board, look at the columns |
| Dependencies | Written into prose | A blocking edge, queryable |
| Two agents taking one job | Nothing stops them | The assignee is a claim, written and read back |
| Machine access | Free-form text editing | Official CLI and MCP |
| Approving or asking for changes | A message somewhere else | A comment on the ticket itself |
| Several people weighing in | Editing one file, stepping on each other | One comment each, attributed and ordered |
| An agent asking back | Nowhere to ask | It asks inside the ticket, anyone can answer, then it carries on |
| When a session closes | State goes with the context | The board is still there |
Those two comment rows are where the way of working changes most. The agent no longer waits for one specific person: it asks on the ticket, whoever on the team can answer does, and it carries on. The AI works as a member of the group rather than a tool you have to sit and watch.
One detail is easy to miss: the list of work that can start now, called the frontier, has to be written back. Computed only inside an agent’s context, it is invisible when you open the board, and a ticket whose blockers have merged still looks blocked. So the contract carries both halves: once computed, write the answer back to the tracker, and never read a ready label as if it were state.
Trade-off. Astragentic inherits the limits of the tracker you use. No tracker has an assignee field
designed to hold builder/<ticket-id>. GitHub Issues has no real status field, so status lives in
labels and the Project board column is a copy that has to be kept in sync. And because the tracker
holds state rather than passively recording it, it can drift; reconcile-tracker measures the
tracker against git.
Subagents and agent teams are good inside one session; coordination is not
Claude Code has subagents and agent teams. Both work well inside one session, and Astragentic uses them: a Builder spawns subagents for reading and reporting, and Thomas uses both when it needs to survey or plan.
The question that follows is why any coordination layer is needed on top of that.
The line is scope. Subagents and agent teams coordinate work inside one session. What a team needs is coordination across sessions, with each session open to inspection. For the way I want to work, seeing what an agent is doing, where it goes wrong, when it drifts, a hidden process is not enough.
Put the coordination inside subagents and four things go missing, all in the same way: when something goes wrong, nothing signals it.
- A shared checkout. A subagent runs in the same worktree as its parent session, so several
agents drag each other’s HEAD around. I caught a read-only reviewer running
git switchon someone else’s checkout. - A shared context. A fork inherits its parent’s whole context, including what nobody meant to
hand over. A fork once inherited the parent’s model, so a job meant for a cheap model ran on the
most expensive one. Another time, a fork inside a Builder sent the end-of-work report, called a
handback, to the dispatcher under the Builder’s own name, and the Builder never saw it. And a
fork signed a
simplify(increment):marker onto code it had just committed itself, in the permitted form. - No tracker holding state. A subagent’s state lives in the parent session’s context, disappears when the session compacts, and while it exists you cannot read it.
- No pane to look at. A dispatch was once narrated in words and never actually called. A pane in herdr can be counted; an in-process subagent cannot.
And one more: a Claude subagent is still Claude, so there is no cross review from another vendor.
So Astragentic lets subagents do what they are good at, inside one session, under one rule: the
fork must have isolation: "worktree" and must never message the dispatcher.
Trade-off. You have to install herdr and configure a tracker, two dependencies a subagent does not need. Each Builder costs a worktree on disk and a few seconds of setup. Each dispatch costs one write and one read on the tracker. The process is longer and there are more names to remember. I pay that because silent failures cost far more.
The engineering method comes from mattpocock-skills
Astragentic does not write its own method. The craft is mattpocock-skills: wayfinder,
grill-with-docs, to-spec, to-tickets, implement, code-review. Astragentic wraps
coordination around it.
The reason is where the loop sits.
- This method loops at the start.
grillingkeeps asking until no open question is left, so the spec is settled before any code is written. Every review after that is a bounded pass. - The common way loops at the end. Unsettled decisions go into the code and get settled in review. That is the most expensive point, and the number of rounds has no natural stop.
The difference is where the stopping point is. Asking everything up front has one: no open questions left. Settling in review has none, because each round raises new questions, and the later rounds mostly clean up what the earlier ones left behind.
On Superpowers, the question usually asked alongside: it is a good system and my team uses it
on other projects. It packs method and coordination into one session, keeps state in a plan file on
the branch, and has nothing equivalent to to-tickets producing tickets with blocking edges on the
tracker. Running both in one repo is two coordinators managing the same state, so Astragentic does
not combine them.
Trade-off. This is a real dependency. check-requirements.sh stops hard without
mattpocock-skills >= 1.3.1. Skill names sit directly in the contracts, so changing the method
means rewriting contracts. And Astragentic can only patch the seams, not the plugin: when a defect
sits inside to-tickets, the right answer is to have the contract account for it rather than fork
a patch.
Cross review: an AI from another vendor re-reads the diff
After Claude has written and self-reviewed, a model from another vendor reads the diff. Here that is OpenAI’s Codex.
That second read is called the arm, and it is a cross review rather than a debate: the two models do not argue to persuade anyone. Each reads and concludes on its own, and both verdicts are kept.
The mechanism is simple: the arm reads the whole repository while the author only reads the ticket. So the arm catches contradictions with the project’s own declared standards, which the author can hardly see while working to the ticket.
- A defect slipped through the same-vendor round: it put a live secret and buyer PII into a tracked file. The other vendor’s pass caught it and filed it as P1.
- Two lenses catch two classes of defect, so they run side by side rather than replace each other.
- One case on a large diff. 6,904 added lines across 31 files went through a same-vendor read that missed three empty tests. A ticket-scoped read on a smaller diff caught a real deadlock the previous round’s patch had just created.
Trade-off. Friction at call time. Quoting and argv differ between runtimes. codex exec has hung
silently before, so it needs a timeout and a dispatcher watching. The most dangerous part is scope:
if --base and HEAD resolve differently, the companion compares a branch with itself and returns
clean on zero commits. So every read prints its range line before the verdict is trusted.
The scaffold repairs itself, one loop at a time
An incident nobody writes down comes back. That is not a remark about agents; it is a remark about any system whose memory does not outlive the session.
With a team of agents it bites harder than with a team of people, in exactly one place: the session ends and the context goes with it. A Builder that has just made a mistake and just understood why it was wrong carries none of that into the next ticket, because there is no “it” that continues. A person at least half-remembers.
The mechanism is a ledger, and a path from the ledger into a contract.
The ledger. Every incident is one line in an append-only file with a fixed id — AST-136 today
is still AST-136 a hundred entries later. Never renumbered, never deleted, not even once the bug
is fixed. There are 136 entries.
The path. A line that yields a rule does not leave the rule in the ledger. It writes it into a file an agent actually reads: a role contract, a skill, or a hook. The ledger is the evidence; the contract is where the evidence takes effect.
The loop closes at merge, not at the end of a sprint and not when somebody remembers. The merge
commit carries a Ledger: line naming what went in. Ledger: none is valid; its absence is not —
“this one taught us nothing” is a conclusion, while no line at all is a step that was skipped, and
from the outside those look identical unless the declaration is required.
There is no build step and nobody reloads anything. Each role’s system prompt is only a few lines, and one of them is an instruction to read its own contract. The next session opens already carrying the new rule. A hook covers the rest: after a session compacts, the contract is re-armed, because what sits outside the system prompt is the first thing compaction summarises away.
An entry is only promoted once it has happened more than once. AST-136 went in after the same
mistake wore three different faults: an escape that made a script report a confident STOP naming
the wrong cause, a search that read 23 markers as 193, and a path that made a marker which really
existed report as never recorded. Those three were releases apart, and they were only visible as
one thing because all three were in the ledger.
Trade-off. The ledger grows and never shrinks. It is not meant to be read end to end — it is what you consult when a rule in a contract makes you wonder why is this here. And every rule added to a contract is tokens paid on every session of that role, so a rule has to show that it blocks a failure that has happened, not one that could.