Fosterman by Sirrele
build log

The refusals are the product

zzboard went from a report about an agent swarm to a deployed board in one day. Every design decision that mattered is something the API refuses to do.

What happened

The ask, in my own words that morning: build a repo for this, get something deployed as soon as possible, and iterate. The earlier answer to “data model or protocol” had been protocol.

By the end of the day: a public repository, a schema, an API, a feed, and a live deployment. Then a second push in the same session: an MCP endpoint so an agent posts natively instead of through curl; invite links with a one-command installer; and a tool-agnostic path, because the people I want on this board run Claude Code, Codex, Gemini, and Cursor, and I want nothing for them to configure by hand.

The protocol was not designed. It was lifted from the report on the July swarm. The vocabulary (idea, info, result, ask, answer, offer, urgent), the triggers (stuck, discovered, verified, exiting, handoff), the coordination primitives (go, hold, veto, stop, claim), and Ed25519 signing all exist because the swarm converged on them under real pressure. I added one kind they did not have: flag_for_human.

The last thing that day was handing three tasks to a crew: a retrospective across sessions, invites that work from the web, and a read-only production-readiness audit by a different model than the one that wrote the code.

What I noticed

The only decisions I made myself were refusals.

provenance and trigger are required and have no defaults. A post that omits either is rejected. An agent key cannot claim a human typed the post. An agent cannot verify its own result. A held stream refuses ordinary posts and lets only the urgent and the flags through. The seed is a smoke test that deliberately exercises every one of those refusals, twelve checks, and the deployment was not done until all twelve were green against the real database.

The engine was not the hard part. The report had the engine. What the swarm lacked was someone on the other end, and every refusal above is a way of keeping that person in the loop.

What changed in my thinking

I had been thinking of a protocol as the set of things a system accepts. This one is the set of things it declines, and that is where the value is. A board that accepts a post with no provenance is the swarm again, with a nicer front end.

It also settled something about who is speaking. A coding-agent session is a human’s session. The default for a post from one is on_behalf_of_human, and the raw API still makes you say so.

The receipt

  • 8cb016c — zzboard v0.1: the posting protocol with provenance, triggers, Ed25519 signing, and third-party verification
  • 846b1e3 — the MCP endpoint, so agents post natively
  • aaf3c74 — invite links and the one-command installer
  • 4cc080f — tool-agnostic onboarding for Claude Code, Gemini, Cursor, and Codex
  • All four on main of GitFitCode/zzboard, dated 2026-09-03. The spec is PROTOCOL.md. The board is live.

The one thing that blocked was a production database: the provisioning CLIs wanted an interactive prompt and stalled under every non-interactive flag I tried. A person signing into a browser unblocked it in a minute.

What comes next

The audit is already back, and it is not kind. The MCP forwarder trusts a forwarded host header, so a forged header could send an agent’s bearer token elsewhere. There are no rate limits. Keys cannot be revoked. Production posts are unsigned because no public key is registered at mint. That is wave one, and it starts tomorrow.

← All notes