← ALL POSTS

26 SEP 2026

Building a Meta-Harness

agentic-aimulti-agent-systemsplatform-engineering

"Agent teams" went from demo to product this year. As of writing, xAI's Grok Bot puts always-on AI teammates right in your group chat.

Those teammates live in a chat. I wanted a team that ships: coding agents I could leave on real code for days, and still trust what came back.

Trust is the hard part. Someone has to decide who picks up the work, what counts as done, who's allowed to ship it, and what happens when an agent dies halfway. That's a control plane's job, so I built one. It's called Illustrious, and a small company of agents runs on it. I call it a meta-harness, because it sits one layer above the agent harness and owns all of those decisions.

Illustrious is private. It holds credentials and deploys to my own server, so I can't hand you a login. Consider this post the tour. The app images are faithful recreations of its interface.

The Office view: a pixel-art office floor where named agent characters sit at desks or in a common room, above a strip of decisions waiting for the founder and a list of current work.The Office. A character only types at a desk when an attempt is really running. The animation never invents work.

Ideas are everywhere. Access isn't.

I'm a technical person. I can build things, and these days almost anyone can: describe what you want, and a model like Opus 5.5 will happily vibe-code it for you.

There's still a barrier to entry, though, and it's money. Using a model like that properly means a premium plan, and the one that gives you enough of it (Claude's Max 5x) costs US$100 a month. That's about S$130. Most people won't pay that to try out an idea. My friends certainly won't.

They do have the ideas. Each of them is an expert in their own field, and they spot problems I'd never see from where I sit. What they don't have is a way to build.

Illustrious is how I close that gap. Each group of friends gets its own space, sees only its own projects, and can bring an idea for the company to build. One platform, lots of different groups, each with their own ideas and expertise. Maybe one of those ideas becomes a hit. At the very least, it'll be useful to someone.

For that to work, the agents have to be trustworthy without me watching every step. That's exactly where the harness stops and the meta-harness starts.

What the harness doesn't do

First, what a harness is. A harness (pi, Claude Code, Codex) runs one agent loop. It sends context to a model, runs the tools the model asks for, feeds the results back, compacts the history when it gets long and saves the session. Good harnesses do this extremely well. I had zero interest in writing another one.

What a harness doesn't know is everything around that loop:

  • Which of eighteen colleagues should pick up this task?
  • What does "done" actually mean?
  • Who is allowed to approve a deploy?
  • What happens to half-edited files when the process dies at 3am?
  • How does accepted work reach a live URL?

Those are meta-harness questions, and in Illustrious the app owns every answer in its own database. Agents act only through narrow, checked tools. There's no free-text path from a model's opinion to a change in workflow state.

For the loop itself, Illustrious embeds exactly one harness, pi, as a library inside its own worker. That's a choice, not a limitation I'm waiting to fix. One harness I can hold to account lets the control plane own execution end to end: the sandbox, the credentials, and a session saved after every turn.

Layer diagram, top to bottom: the founder, the Illustrious control plane, a task host started for each attempt, the pi harness, and finally the model with its sandboxed tools.Where the line falls. The harness runs the agent loop; everything above it is the meta-harness.

Picking one small harness is also a bet about where the value is going. The harness is becoming a commodity. The domain lives one layer up.

The core loop (model, tool, result, keep the context in budget) is small, and the good harnesses are converging on it. What changes from one domain to the next is everything around it: which tools an agent may touch, what "done" means, which gates stand in the way, and whose data it works on. A harness that tries to contain every domain just bloats.

I have the numbers on that. Illustrious started on a general-purpose harness of the better part of a million lines of Python. Moving to the small pi library, embedded in the worker instead of baked into the sandbox, took the sandbox image from 3.21 GB to under a 1.3 GB limit.

The flip side is that there's no universal meta-harness either, because the layer above has to know its domain. Illustrious is built for delivering software, on top of a small general harness, and that's deliberate.

Same idea, different domain: I also built Folio, an advisory workspace for my own portfolio. On screen it's a chat box, and show anyone a chat box and they'll tell you they already have ChatGPT. But the chat box is the least interesting part. The rules underneath are what make it Folio: what it can read, what it can never touch, and when it has to ask me first. Take that layer away and yes, you'd have a ChatGPT clone. More on that one in its own post.

Underneath, the loop is nearly the same everywhere now. Each of these products is a bet about the layer above it. Here's what Illustrious's layer looks like.

A company you can actually see

It starts with a company: 18 roles in 6 groups. There's an executive, research, product, engineering, games, and an independent assurance desk of one. Every role has a name, a remit, editable instructions and a sprite in the Office.

  • Charlotte leads product, Alpha leads engineering and Iris leads games.
  • The specialists under them (a backend engineer, a UI designer, a browser-game engineer and so on) build.
  • Clara reviews. The app never lets a reviewer judge work they were assigned.
  • Alpha deploys.

Those instructions are mine to edit, and editing them mid-week is safe. Every run pins a snapshot of the company's configuration, so a change never touches work already in flight.

My own job, as the founder, is to describe outcomes, not tasks. "Make this game worth coming back to tomorrow." "Let a group of friends share one trip ledger." The accountable lead turns that into a plan, and the app enforces its shape. A plan has to name:

  • the audience, and what they do in their first 30 seconds
  • the promise that brings them back
  • at least four genuinely different ideas considered before choosing one
  • what a returning user will notice
  • the acceptance criteria the work will be judged against

A game also needs a design of record: core loop, controls, camera and look. A plan that skips the product thinking is rejected before any work exists. No brief, no build.

I can also chat with any colleague from their drawer, and that chat is deliberately powerless: one model reply, no tools, no workspace. A colleague can tell me what they'd do. They can't start a task, approve anything or read anyone else's conversation. It's a water-cooler chat, not a back door.

The Team page, with agents grouped by department and a side drawer open on one specialist, showing their current assignment, next action and comments from colleagues.The Team page. Roles have durable identities, reporting lines and instructions I can edit.

Done means reviewed, merged and deployed

So what happens when I actually ask for something? A run starts with a goal and a mode (Standard or Auto, more on those later). Its board begins with exactly two tasks: delivery, owned by the accountable lead, and deployment, owned by Alpha. Every two seconds a worker checks which tasks are eligible (prerequisites done, approvals in place, board not paused, workspace free) and claims them.

The lead's first move is a single plan_work call. It records the brief and the acceptance criteria and makes one decision: build the work directly, or split it into packages for specialists. Packages become real tasks with dependencies. A package can even go to another lead, who plans it the same way.

Each specialist checks its own change and submits it, and the app merges it without a second review. That's on purpose. Review happens once, on the assembled release, and nothing reaches production until that review passes.

When every package is in, the lead resumes, assembles the result and submits a candidate: a clean Git commit with real product changes, not a status message.

That candidate goes to Clara. She reviews it in a disposable copy, with the candidate mounted read-only, so nothing she does can change the work she's judging. She uses the product in a browser, takes screenshots, runs checks and records a verdict against each acceptance criterion. Rework goes back to the lead with her written findings, for a bounded number of rounds.

Once Clara accepts, the work merges only if the project's main branch is still exactly where the app expected it. If anything moved, nothing fast-forwards, and a conflict keeps both sides for the lead to repair.

Then comes the deployment gate, and Alpha publishes that exact commit. The platform packages it, health-checks the running container, records a verified receipt and keeps the previous release for rollback.

Flowchart of a delivery: founder request, the lead's plan_work call, specialist packages, lead assembly, independent review with a rework loop, integration at the expected HEAD, the deployment approval gate, and a verified deploy.The life of a delivery. Every arrow is a state change the app records.

Notice what's missing from that path: a chat reply. An agent saying "done" is just a sentence. Agents say it a lot. The app doesn't count it.

The agents don't chat with each other either. There's no tool for messaging a colleague and no way to read another agent's session. Everything passes through records the app owns:

  • A package arrives as a task carrying the brief, the acceptance criteria, the paths it owns and the paths its siblings own. Two specialists settle an interface through the requirements, not a conversation.
  • Finished work comes back as a merged commit plus a summary on the package, which the lead's next attempt reads.
  • Clara's verdict is a record with a finding per criterion. A rejection also lands in project memory as a lesson tied to the files it touched.
  • Alpha learns what to ship the same way: the release is the commit recorded on the delivery task.

The nearest thing to a message is a progress note on an agent's own task, and a note never approves anything. That's what makes a run auditable end to end. It's also why a crash costs so little: a replacement agent starts from the same records the first one read, not from a conversation that died with it.

Here's a run that went all the way through. TripSplit is an account-free group travel ledger with multi-currency expenses and settlement guidance, live on my server. The team planned, built, reviewed and deployed it, and every commit in its history came from a run.

The run page for a TripSplit delivery: shipped and verified with its live link, what was asked and shipped, then each acceptance criterion marked met with the reviewer's evidence.What I read when a run finishes: the outcome first, then Clara's evidence against every criterion.

All that machinery exists for one reason: so a group of friends can open TripSplit on a phone and settle a dinner bill.

TripSplit on a desktop browser: a four-person trip ledger with expenses in yuan, saved SGD conversion rates and who pays whom.TripSplit on desktop, as the team shipped it.

TripSplit on a phone-sized screen, showing an estimated settlement in Singapore dollars with the reference-rate date and coverage.On a phone: the estimated SGD settlement that the run above shipped.

A yes covers exactly what you saw

Back to that deployment gate. In Standard mode, deployment waits for me. When I approve, the approval isn't a flag on the task. It's a record bound to three things:

  • the task's revision
  • the exact scope text I read
  • a gate generation

If the scope changes, the generation moves on and every earlier approval stops counting, even if the scope is later changed back. At deploy time, the app checks again that the release it accepted is still the commit on the main branch. Nothing gets quietly swapped in after I say yes.

Auto mode exists for projects where I'm happy to pre-authorize deployment within the agreed scope, and I pick it per run.

Pausing follows the same rule: nothing counts as a yes unless it is one. Pausing a board stops new work from being claimed, and resuming it approves nothing.

The other half is knowing when not to ask. I only get asked about consequential decisions: destructive actions, security, spending, credentials, contacting anyone outside, or a product call only the founder should make. Routine technical failures stay with the team. I'm the founder, not the on-call pager.

A deployment approval card for TripSplit: the task owner, the exact scope to be approved, and the approval form.A Standard-mode deployment waiting on the founder. The approval binds to this scope, this revision and this generation.

Designed for the agent that dies mid-edit

Everything so far assumes an agent finishes its job. Plenty don't. Providers time out, hosts restart, budgets run out, and processes vanish halfway through an edit. I designed Illustrious assuming all of that happens, and it comes down to four rules.

1. Contain before you retry. Each attempt carries a secret token and a lease. Before anything is retried, reassigned or merged, the app requires proof that the old process and its containers have stopped, then fences the attempt so it can never write back. A process is identified by its boot, its PID and its start time, so a recycled PID can't pass for the original. No zombie agent gets to write over its own retry.

2. Work survives. When an attempt stops, its uncommitted files are snapshotted into a Git commit through a throwaway index, without touching the branch or anything staged. The next attempt, or a different agent, picks up from that snapshot. A checkpoint is never mistaken for a submission.

3. Replays are harmless. plan_work stores a receipt keyed to the task's revision and generation. A host that crashes after committing and replays the call gets the same receipt back, not a second set of tasks. Background jobs carry idempotency keys, plus an honest uncertain state for "we can't prove whether it happened".

4. Recovery is a table. Not logic scattered across the codebase, but twelve typed stop reasons, each with an owner, a retry budget and a backoff. For example:

  • A lost host retries twice, after 15 and 60 seconds.
  • An approval stop never clears on its own.
  • Routine failures pass to the lead at most twice per revision, then end as an honest failed outcome instead of a loop.

One privileged door

Crashes are the boring failure. The scarier one is an agent that's running perfectly well and doing something dumb. An agent with a shell can do whatever that shell can reach, and this server also holds credentials, a database and live sites. So rather than trusting agents to be careful, I kept their reach small. A confused agent can wreck its own sandbox, not the server.

That starts with how the app itself is split. Illustrious runs as three services around one SQLite database:

  • Web serves the interface and the API, and sees project files read-only.
  • Worker runs the scheduling loop and starts one task host per attempt. That host embeds the harness and holds the model credentials.
  • Helper is the only process that can touch Docker. It has no network, answers a fixed set of routes over a local socket, and checks every request against the app's own records. Callers can't hand it an image, a mount or a Docker flag.

Architecture diagram: the browser talks to the web service; web and worker share one SQLite database; the worker starts task hosts; only the helper talks to Docker, which runs the per-attempt sandboxes and the published project containers.Three services, one database, and a single process allowed to touch Docker.

The helper is also where agents get their sandboxes. Every attempt's commands run in a fresh container on a Git worktree of its own:

  • The filesystem is read-only.
  • Every Linux capability is dropped, privilege escalation is off, and the user isn't root.
  • Memory, CPU and process count are capped.
  • It sits on a separate execution network, away from the one that serves the app and the public sites. It can still reach the internet to install packages.
  • The model and its credentials never enter it. Its environment holds nothing but a home directory, and the database holding the keys isn't mounted.
  • Commands go in one at a time with capped output and a time limit. One that overruns has its whole process group killed inside the container, so nothing outlives the call.

File reads and edits run outside the container, held to the worktree by a path check.

Git access is narrower still. A builder can add commits on attempt branches, but the repository's config, hooks and main branch are read-only to it. Only the app's integration step moves main. Alpha has no shell at all: one tool publishes the accepted commit to a target the app configured. No agent ever picks an image, host, mount or port.

Parallel work gets one more guard. The app rejects a plan in which two packages' owned paths could touch the same file. Git only notices a clash after the fact, and only a textual one, so the overlap check runs before any work starts.

Where this sits

That sandboxing is also the clearest difference from the best-known project in this space. Paperclip is, as of writing, the best-known open-source control plane for agent companies. It popularized the org-chart model and orchestrates whatever harness you bring. Its own docs put it neatly: the control plane doesn't run agents, it orchestrates them.

Illustrious makes the opposite bet: one embedded harness, and a control plane that owns execution, credentials, integration and deploy. That shows up in the defaults. Paperclip's docs describe its local adapters as running "unsandboxed on the host machine", with hosted sandboxes as an option. In Illustrious, every attempt's commands run in their own locked-down container with no credentials inside.

Neither bet is wrong. Paperclip is broader. Illustrious is narrower and goes further down.

Where it stands

I built it solo, and around 450 tests guard the boundaries that matter: authorization, atomic claims, approval gates, recovery and isolation.

It's one company with one founder, and friends only get in when I add them. It's also honest about its limits. The product doc says it plainly: recovery is bounded and keeps its evidence, and the platform "does not claim that every external dependency or arbitrary software problem is automatically solvable."

The models were the easy part. The hard part, and the part I'm proudest of, is deciding what counts as done, who may say yes, and what survives when an agent dies halfway through a job.

Harnesses run an agent. Illustrious runs the work.

© 2026 ETHAN

OCCASIONAL WRITING