The Magi fleet is three named agents — Casper, Melchior, and Balthasar — that run on a single machine, coordinate over a shared Firestore "board," do their work through the headless opencode SDK, and report results as board comments. There is no web UI, no job queue server, no orchestrator lockfile. Just three node server.js processes, one Firestore database, and a shared idea of what "Done" means.
This post is the technical deep-dive the launch deserves. If you build agents, you already know that the hard 90% of an "autonomous agent" is not the model, it's the scaffolding around it: how work is discovered, how a task is owned exclusively, how a crashed worker is noticed, how feedback loops close, and how the system stays observable without a human watching. Here is how Magi solves each of those — and honestly, which of it is built and which is still aspirational.
The project is live and observable: landing page, live fleet status, and the weekly ops digest. The source runs from private repos and is available to collaborators on request — the public proof is the live surfaces, not an open-source release.
The board is the boss
Everything funnels through a single Firestore collection, tasks. Each worker boots by opening a realtime listener on a query — where('assigneeId', '==', <my agent id>) — and reacts to document changes. Firestore streams those changes over a websocket; the worker never polls. A task is a document with a title, description, status, tags, a comment array, and a timeline array recording every state transition (claimed, reworked_from_comment, marked_done, …).
// server.js
const query = db.collection('tasks').where('assigneeId', '==', AGENT_ID);
query.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
const data = change.doc.data();
if (CLAIMABLE_STATUSES.includes(data.status)) enqueue(change.doc, 'work');
else if (hasNewHumanComment(data)) enqueue(change.doc, 'reply');
});
});
Two statuses are claimable (To Do, In Progress) — which is how rework works: a freshly-created card starts To Do, a card that comes back for changes is set back to In Progress, and the same worker picks it up again. Done and Blocked are terminal until a human reopens them.
The board is the only shared state, and it is the only interface. Workers never call each other. To know what the fleet is doing, you read the board. To change the fleet's direction, you write a task. This is deliberate: Firestore realtime snapshots give you pub/sub, CRUD, and an audit log with zero infrastructure, and every card ships its own full history so an agent picking up a task inherits context instead of asking "what was I doing?"
Claiming work the single-writer way
The subtle part is ownership. Two workers don't share a task, and a worker must not double-run a task that just flapped. The claim is a Firestore transaction: read the card, verify you're the assignee and the status is still claimable, then atomically write status: 'In Progress', append a "Claimed by …" comment and a timeline entry.
// server.js — the claim, atomic so two workers can't race into the same card
return db.runTransaction(async (tx) => {
const snap = await tx.get(taskRef);
const data = snap.data();
if (!snap.exists || data.assigneeId !== AGENT_ID) return false;
if (!CLAIMABLE_STATUSES.includes(data.status)) return false;
tx.update(taskRef, { status: STATUS_IN_PROGRESS, ... });
return true;
});
Firestore transactions give you optimistic concurrency for free: if two events race, exactly one claim commits. Paired with a per-worker serial queue and an inFlight set, a claim can't double-fire even when a snapshot arrives mid-work. The "single-writer" discipline is then carried through the whole system: the coordinator is the single writer of new assignments, and each worker is the single writer of its own card. Coordination collapses to "who owns this document," which is the cheapest coordination primitive that exists.
The outcome-weighted pickWorker — a coordinator that learns which worker succeeds on which task types and routes work accordingly — is on the roadmap, not in the code. Today assignment is done by hand on the board: whoever creates the card sets assigneeId. The machinery that would feed the weights (task tags, finished/blocked outcomes, per-agent completion counts on the agents roster) is all there and steadily accumulating; the learning itself is a stated goal in the supervisor's own memory, not a shipped feature. By design, I'm not going to claim it's running when it isn't.
The supervisor closed loop: observe → decide → act → remember
The fleet works best understood as a loop, not a pile of scripts.
- Observe. Every agent writes a heartbeat every 60 seconds onto its
agents/{id}doc and into a sharedlogs/heartbeats.jsonl. Roster reading (a.k.a. fleet health) flags an agent that is expected to be alive (anything not cleanlyOffline) but has been silent past a threshold (~3 minutes) — the "nobody pings, nobody noticed" failure mode, caught before work stalls. - Decide. The supervisor layer — a separate overseer process the workers don't depend on — reads the board and the roster, and decides. Its own heartbeat and current goals live in the
memorycollection assupervisor-state, so the fleet's brain is itself observable. - Act. The outcome of a decision is written back to the board: a new task, a re-assignment, a "supervisor resolution" comment on a card, an auto-recover trigger, or an operator alert.
- Remember. Learnings get appended to
memoryastype: "learning"entries, and the weekly digest surfaces them. The fleet literally keeps a diary and reads it back.
The loop is human-readable by design — every decision lands as a comment on the relevant card, with the same tooling a human reviewer would use. When the fleet health monitor once flagged a silent agent that was actually running an old binary, the supervisor's resolution comment on that card explains the root cause and the fix. That auditability is a feature as important as the automation itself.
Self-healing without a health-check prayer
Three pieces make the fleet survivable rather than fragile:
- Heartbeat liveness — the pings above. A worker that dies mid-task goes
silentand is flagged; an agent reportingOfflineduring shutdown is expected at silence and never false-flagged. - Watchdogs — a worker-level auto-recovery kicks in on stale heartbeats, and a coordinator self-monitoring watchdog watches the supervisor itself (the supervisor must not be its own only watchdog). Operator alerting emails the operator when auto-recovery fails or a task sits
Blockedtoo long. - Graceful degradation — transient failures (timeouts, hiccups) retry with exponential backoff (up to 10 attempts) before a card is ever flagged
Blocked, andBlockedcards carry the actual error as a comment so a human or supervisor can unblock rather than guess.
Every task also resumes its opencode session: the session id is persisted on the card, so a rework continues the exact same context instead of a fresh memory-less run.
Email as an input, defended from itself
Email is a first-class tool (Tools/email.js: Gmail SMTP send + IMAP read). The fleet mailbox doubles as an ingestion channel: mail becomes board tasks. And this is where the system learned its sharpest lesson. When the fleet emails itself, or emails the operator about its own digest, that mail can come right back in as a new task — a self-mail echo loop. The ingester had to be patched twice to stop re-ingesting the fleet's own outbound mail. The guard that finally worked: only externally-originated messages are candidates for task creation, and outbound confirmation mail is explicitly excluded — plus the design rule of thumb that surfaced from it, quoted from the codebase: "No self-email can ever be re-ingested as a task."
Case study: the weekly digest that automated away its own existence
The fleet's weekly ops digest is the best exhibit of the whole design, because it demonstrates the feedback loop applied to the fleet's own operations.
It used to be a chore: a worker composed the digest, emailed it to the fleet mailbox and the operator — and every single week the service risked re-ingesting that email as a task. Instead of patching the guard again, the fleet removed email from the loop entirely. Tools/weekly-digest/generate.js now reads the board straight from Firestore (status distribution, done-this-week outcomes with each card's Finished. summary, blocked cards with reasons, agent roster with heartbeat staleness, top tags, funding ledger, memory learnings), renders a markdown report, and posts it to the board as a Done task with no assignee — assigneeId: null, so no worker can ever claim it, and a periodKey like 2026-W36 that makes the post idempotent per ISO week. It's scheduled by cron; the board is the surface; no email is sent; therefore no self-mail can be re-ingested. Recurring ops reporting became self-owning.
What's real now vs. what's the dream
Readers deserve the honest line, so here it is in black and white.
Built and running today: board-driven delegation over Firestore with transactional, single-writer claims; the opencode worker runtime with session resume and comment-driven rework-or-reply decisions; heartbeat liveness, fleet-health monitoring, worker auto-recovery, the coordinator watchdog, and operator alerting; tags as a shared vocabulary (a tags collection whose usage counts back every task); the weekly digest tool; and the x402 funding module — a coordinator wallet, a payment URL for top-ups, and a raw fetchPaid() spend flow wrapped in spend-discipline guards (per-txn cap, fail-closed balance floor, daily cap, network/asset/payee allowlists).
Roadmap, truthfully: outcome-weighted pickWorker (learning which agent to delegate to is a goal written in supervisor-state, and the data is accumulating, but it is not running); the marketing distribution itself (this very launch — the landing page is live, the launch posts are the work-in-progress); and live funded operation — the wallet module exists, but the current funding ledger is empty and a fresh production wallet with a testnet spend dry-run is an in-progress task, not a done one.
I'd rather ship this post than a pitch. The fleet is real, it works without a human in the loop on day-to-day ops, and the parts of the ambition that aren't true yet are the most interesting parts to build next.
Want to poke around? The live surfaces are public: landing page and the live fleet status page. The source runs from private repos and is available to collaborators on request. The worker runtime is ~600 lines of server.js — no framework, no queue server, just Firestore and a strong opinion about who owns each document.