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.

Four Layers, One Harness An architecture diagram generated by Archify. Claude Code · runtime · RUNTIME Claude Code runtime Codex · cross-vendor arm · RUNTIME Codex cross-vendor arm Grok Build · junior pane (optional) · RUNTIME Grok Build junior pane (optional) Roles · Thomas · Shaper · Builder · QA · Junior · HARNESS Roles Thomas · Shaper · Builder · QA · Junior Skills · 18 packaged skills · HARNESS Skills 18 packaged skills Memory / Ledger · what actually happened · HARNESS Memory / Ledger what actually happened Hooks · 4 lifecycle hooks · HARNESS Hooks 4 lifecycle hooks Tracker · GitHub · Jira · Linear · COORDINATION Tracker GitHub · Jira · Linear herdr · one pane per agent · COORDINATION herdr one pane per agent git worktrees · one checkout per ticket · COORDINATION git worktrees one checkout per ticket Your Project · repo · GLOSSARY.md · ADR · YOUR PROJECT Your Project repo · GLOSSARY.md · ADR Thomas asks frontier Builder claims worktree blocks a dangerous command RUNTIME HARNESS COORDINATION YOUR PROJECT Legend Frontend Backend Database Security External

Scroll sideways for the whole diagram

Open the full diagram ↗opens in a new tab
Role colours in this figure

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.

The Frontier Query A data-flow diagram generated by Archify. 01 / Tracker fields 02 / Query 03 / Board 04 / Consume Open Tickets · all tracker items · 01 / Tracker fields Open Tickets all tracker items Blocking Edges · blocked_by graph · 01 / Tracker fields Blocking Edges blocked_by graph Assignee Field · empty or held · 01 / Tracker fields Assignee Field empty or held Frontier Query · asks what is ready · 02 / Query · not remembered Frontier Query asks what is ready not remembered Claimable Board · claimable, unclaimed · 03 / Board Claimable Board claimable, unclaimed Thomas · reruns after merge/handback · 04 / Consume Thomas reruns after merge/handback Builder · claims and works the ticket · 04 / Consume Builder claims and works the ticket Owner · looks at the board · 04 / Consume Owner looks at the board every open ticket state read blockers all done? graph read assignee empty? state read answer written derived session start + ticket closes polled reviews readiness read-only claim, then dispatch writes assignee issue found → new ticket writes Legend data store data flow

Scroll sideways for the whole diagram

Open the full diagram ↗opens in a new tab
Role colours in this figure

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 switch on 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.

Every Agent Gets Its Own Pane An architecture diagram generated by Archify. Thomas · resident router · HERDR WORKSPACE Thomas resident router ticket:TRA-139 · Builder · HERDR WORKSPACE ticket:TRA-139 Builder ticket:TRA-142 · Builder · HERDR WORKSPACE ticket:TRA-142 Builder spec:TRA-87 · Shaper · HERDR WORKSPACE spec:TRA-87 Shaper qa:TRA-125 · QA · HERDR WORKSPACE qa:TRA-125 QA rin:TRA-125 · Rin · HERDR WORKSPACE rin:TRA-125 Rin dispatch dispatch dispatch dispatch-qa review HERDR WORKSPACE Legend Frontend Backend Security External

Scroll sideways for the whole diagram

Open the full diagram ↗opens in a new tab
Role colours in this figure

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. grilling keeps 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 Cross-Vendor Arm A sequence diagram generated by Archify. commit range <base>..HEAD adversarial-review --wait --base <ref> Focus text carries the owner intent blocking / non-blocking Only the output file is trustworthy, never the exit code arm(ticket): receipt Findings folded by class first; empty commit, parent is the tree the gate read branch, SHA, markers Fire the arm Verdict Receipt + handback Builder · own worktree · Sequence participant Builder own worktree Codex · adversarial-review · Sequence participant Codex adversarial-review Ticket Branch · HEAD · Sequence participant Ticket Branch HEAD Thomas · resident router · Sequence participant Thomas resident router Legend request return async trace default message

Scroll sideways for the whole diagram

Open the full diagram ↗opens in a new tab
Role colours in this figure

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.