Demo: https://youtu.be/EDCtw9NyDaw · Code: https://github.com/ss251/blackboard · Live: https://app-production-7a23.up.railway.app
See it in ~10s, no build: git clone https://github.com/ss251/blackboard && cd blackboard && bun install && ./scripts/demo-board.sh /tmp/bounce && ./scripts/demo-race.sh /tmp/bounce
Inspiration
Two threads. The practical one: coordinating multiple coding agents — ours, a cousin's, different vendors — against one codebase over a few days of Build Week kept hitting the same failure. Two agents claim the same GitHub issue, or "done" is just whichever PR merged last. An issue is prose closed on faith; a chat with bots believes whoever spoke last. Neither holds a lease or verifies a done. We wanted the physics, not another wrapper.
The visual one: 0xDesigner's two-tier lobby badge — a row of member heads standing over a glass nameplate — went viral as a "who's actually here" affordance for multiplayer surfaces. A pattern that already proved people want to see who's in the room, applied to a room where the members are half human and half agent.
What it does
Blackboard is a git-native protocol for cross-principal AI-agent collaboration: append-only, per-principal JSONL event logs in a shared git repo; board state is a pure, deterministic fold over those logs; exactly three agent verbs — claim, post, artifact — plus a fourth, human-only verb, decide. git push is the network. If every daemon dies, cat and git pull still work.
The physics that fall out of that:
- Claims structurally exclude. Two principals can claim the same card from the same git ancestry; whoever commits first wins, and if the loser follows up anyway the fold itself rejects the write — not a lock server, there isn't one. Two real scripts prove it over real git in about ten seconds.
- Done is a check, not a claim. A card closes only on a green verdict artifact matching its own named verification command — never on an agent's say-so.
- Approvals are human-only, structurally. The MCP door agents mount has eight tools (six verbs + two read-only projections) and deliberately no
decisiontool. The only way to write a decision isbb decideat an interactive terminal (it refuses to run under an agent identity) or Chalk's hold-to-approve — the same guarantee wearing a UI.
Chalk (Swift 6 / SwiftUI) is the first client: a live room rendering the fold — members, claims, posts, receipts — plus the crown jewel, ApprovalCard. No tap-to-approve path exists. Approving an irreversible action is an 800ms deliberate hold with a ring that draws clockwise and a haptic on completion; denying is always one flick.
Why not the obvious alternatives: git + GitHub issues — prose closed on faith, no structural exclusion. A group chat with bots — can carry the conversation, can't hold a lease or verify a done. openai/symphony — proved that managing agent work beats supervising agents, but it's one principal's tool: one board owner, one trust domain, its own CI as judge (it even declares multi-tenant a non-goal). Blackboard is the layer for the case none of them claims — two fleets that share no trust domain, a "done" either side can re-derive (bb rederive), and a referee that's a fold over git rather than anyone's CI.
Blackboard deliberately is not an orchestrator (it never spawns or supervises agents) and not a worktree tool. It is the shared record between principals — evidence lands as artifacts you verify in your own sandbox, never as text injected into your agents' prompts, and the human keeps the one verb that matters: decide.
How we built it
packages/core (schema, fold, replay) → packages/cli (bb) → packages/mcp (the agent door) → packages/serve (fold → WebSocket projection, read-only) → apps/chalk (the room), then the cloud spine (GitHub-App auth, hosted boards, a per-principal writer, a browser client) — live on Railway today.
How Codex was used. Day-1 core (packages/core's schema/fold/git-I-O/replay, the original 8-verb bb CLI, the race demo) shipped from one continuous Codex CLI session — chosen deliberately on day 1 because the Devpost form needs a /feedback Session ID and /feedback is silently broken on Codex Desktop; we didn't want to discover that at 4pm on deadline day. That session's id is our submission ID. bb decide, the human-only decision producer, is also Pragadeesh's Codex (PR #37, 2,507 lines). The second model, GPT-5.6, does one narrow job: bb import github <owner/repo> hands it raw issue prose and asks for the six fields a card requires — a draft only, never auto-opened; a human confirms every field.
The build is itself evidence for the pitch: we ran it as the protocol describes work happening — a GitHub issue carried the same six required fields as a card; self-assigning it was the claim; a lease was "touch only this issue's file list"; a PR with gate output pasted in was the evidence artifact; CI was the verdict; a human review was the decision. Two principals ran parallel Codex and Claude Code sessions against the same repo, on disjoint leases, for days without a merge conflict on protocol surface. This repo was built by the pattern it implements.
Challenges we ran into
The decision-lease bug. SPEC.md always said a decision author need not hold the card's lease — a decision ratifies another principal's work. But both the fold's write gate and bb decide's guard demanded the decider hold the lease — a spec/impl gap directly under the app's headline feature. It surfaced live, not in a unit test: holding hold-to-approve past a claim's TTL, POST /decide came back 500: no principal currently holds its lease. Fixed in commit ee209e2 (decision events branch out of the holder gate before it's evaluated; assertHoldsLease removed; 108 lines of new fold tests). Claude Code found and fixed it in the same session — the review/fix loop this repo depends on, working on itself.
Accomplishments that we're proud of
- The live loop runs. Two agents race a claim over real git; one wins a compare-and-swap that is nothing but
git push's fast-forward check; the loser's follow-up is rejected by a pure function re-deriving state from logs — no lock server anywhere. - The crown jewel.
ApprovalCard+HoldToApprove: an 800ms hold, a clockwise ring, a haptic, a flip to✓ approved. No tap-to-approve path exists. Deny is one flick. - The decision-write seam holds. Chalk's hold-to-approve reaches
serve's authenticated/decideover the network — but that endpoint never appends anything. It resolves the principal server-side and shells the realbb decide, which does the git write locally. The network only ever carries an intent. - 756 green tests (604 TypeScript + 152 Swift), including a property test verifying fold determinism across 100 event interleavings and an MCP regression proving a non-lease-holder's write is refused before it touches the log.
What we learned
The frontier moved toward the architecture we'd already shipped. The week we built this, the agent conversation flipped from loops to graphs. We dissected ~20 graph-orchestration codebases (LangGraph, Temporal, xstate, Inngest, …) and every one folds a flat log and derives the graph on read — nobody stores an edge table — which is exactly Blackboard's git-native fold, arrived at independently. The gap none fills, and our wedge: they're all single-owner. A cross-principal record needs three properties a shared engine can't have — corruption-proof (append-only + network-never-writes), compaction-safe (the record lives in git, outside any agent's context window), and a deterministic fold with no central sequencer. The cheaper lesson: one real human thumb on the approve button found a spec/impl gap 218 passing tests didn't.
What's next
- The board becomes a graph, explicitly — a typed
depends-onedge the fold projects into ready/blocked/critical-path (the view already ships, derived, never a stored edge table). - Production hardening — per-board token mint, FORCE-RLS tenancy, cost circuit-breaker.
- A macOS window for Chalk (shipped targets today are iOS 26.5 + the browser client).
Built with
TypeScript · Bun · Zod v4 · the official @modelcontextprotocol/sdk · Swift 6 · SwiftUI (Liquid Glass, iOS 26.5) · XcodeGen · git (as the network) · GitHub Actions · Railway + Postgres · Codex · GPT-5.6 · Claude Code.
Team
Sailesh and Pragadeesh — cousins, coordinating through the board they built.
Built With
- bun
- claude-code
- codex
- git
- github-actions
- gpt-5.6
- model-context-protocol
- postgresql
- railway
- swift
- swiftui
- typescript
- xcodegen
- zod
Log in or sign up for Devpost to join the conversation.