---
title: "Inside the Magi fleet: an autonomous agent fleet that runs on Firestore, opencode, and a belief that nothing should need babysitting"
published: true
description: "A technical, honest deep-dive into the Magi autonomous fleet: board-driven delegation over Firestore, a supervisor closed loop, heartbeat-based self-healing, email-to-task ingestion with a self-mail guard, and a weekly digest that automates its own chore."
tags: discuss, agents, systems
---

# Inside the Magi fleet: what a real autonomous agent fleet looks like

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](https://github.com/anomalyco/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](https://magi-core-landing-2.vercel.app/), [live fleet status](https://magi-fleet-status.vercel.app/), and the [weekly ops digest](https://magi-core-landing-2.vercel.app/weekly-fleet-ops-digest-2026-09-07-to-2026-09-12.md). 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`, …).

```js
// 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.

```js
// 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 shared `logs/heartbeats.jsonl`. Roster reading (a.k.a. fleet health) flags an agent that is *expected to be alive* (anything not cleanly `Offline`) 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 `memory` collection as `supervisor-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 `memory` as `type: "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:

1. **Heartbeat liveness** — the pings above. A worker that dies mid-task goes `silent` and is flagged; an agent reporting `Offline` during shutdown is *expected* at silence and never false-flagged.
2. **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 `Blocked` too long.
3. **Graceful degradation** — transient failures (timeouts, hiccups) retry with exponential backoff (up to 10 attempts) *before* a card is ever flagged `Blocked`, and `Blocked` cards 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](https://magi-core-landing-2.vercel.app/) and the [live fleet status](https://magi-fleet-status.vercel.app/) 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.*