DemosShared system demo

The Village Hall

An application that needs nothing outside the room. The example is a bingo night.

No server to reach, no database to query and no account to create — not as a simplification for a demo, but because a program that keeps its own record of what happened does not need them. Keeping that record is what Puppeteer, the substrate we build on, gives every phone.

The example is a parish bingo. One phone leads the evening, the phones that sell cards and call the balls attach to it, and every player's phone keeps its own game, over whatever Wi-Fi the hall already has: a distributed system that fits in one room.

Phones only·A journal on each·Join with a code

Get the code

The question

What does an application still need from the outside world, when everyone using it is already in the same room?

The room

Everything that takes part is in the room.

The same evening, drawn twice: as people with their notebooks, and as the topology underneath.

As people
Organizer here: every sale and every ball goes through the one writer.THE HALL'S WI-FIover irohRitacaught up, in orderCallerthe same copyPlayerown notebookPlayerPlayerin a web pagePlayerSellera copyOrganizerthe only penSomeone at home,on another networkB-12…Card 23, for Rita

Organizer here: every sale and every ball goes through the one writer.

THE HALL'S WI-FIover irohRitacaught up, in orderCallerthe same copyPlayerown notebookPlayerPlayerin a web pagePlayerSellera copyOrganizerthe only penSomeone at home,on another networkB-12…Card 23, for Rita
As a topology
THE HALL · ONE WI-FIOrganizer here: every sale and every ball goes through the one writer.THE EVENING · ONE JOURNAL ON THREE PHONESasksOrganizerone writerSellerat the door · notebookCallercalls each ballPlayerapp · own journalPlayerapp · own journalPlayerapp · own journalPlayerweb page · own journalaway for nowone journal on three phones: Puppeteer's Stage Managerthe same entries, replicateda write, sent to the one writera tell: each ball, to each player on the appasks: a web page cannot be called, so it asksreads its own copy, even without the organizerthe rest of the players in the hall

Organizer here: every sale and every ball goes through the one writer.

THE HALL · ONE WI-FIONE JOURNAL ON THREE PHONESasksCallercalls ballsOrganizerone writerSellerat the doorPlayerown journalPlayerown journalPlayerown journalPlayerweb pageaway for nowone journal on three phones: Stage Managerthe same entries, replicateda write, sent to the one writera tell: each ball, to each player on the appasks: a web page cannot be called, so it asksreads its own copy, even without the organizerthe rest of the players in the hall

Every phone works on its own copy. Take the organizer's phone away and the journal of the evening is still on two phones, and every player still has its game.

Ncubo.Puppeteer 3.0 · iroh over QUIC · Android

What Puppeteer gives this app

The operations did not go away. They stopped being machinery.

Every phone here runs on Puppeteer, which keeps the program's own record of what happened. With that record, four operations stop needing machinery of their own, and two more capabilities come with it. Each one is shown as it happened on the phones.

“For a journaled program, deployment is replay, replication is sharing history, backup is copying the program, and offline operation is delayed replay.”

Paper 05 · The Journal as Substrate

Deployment is replay

A program opens an evening by replaying its journal, and a new version does the same with an evening the old one created: the rules gained a constructor rather than changing one, because the journal re-runs what it already wrote.

Restart the organizer. The night is still there.

The organizer's app is killed and reopened from its own journal. The next ball reaches the caller and the player, who reconnected on their own.

Three Android emulators · 25 Sep 2026 · cut: about 38 seconds passed between the close and the next ball

Replication is sharing history

A phone that joins the hall receives the journal from entry zero and is current, without writing a line of its own.

The phone that joins gets the whole story

The organizer adds a phone and gets its code; the phone enters with it and fills with everything that already happened. From then on it reads its own copy.

Two Android emulators · 25 Sep 2026 · pauses between gestures cut; the join itself is in real time

Backup is copying the program

The evening is a folder in the app's private storage. Copying the folder is the backup.

Offline operation is delayed replay

A player that was away is sent what it missed when it presents itself again; a seller that cannot reach the organizer keeps selling into a notebook of its own, handed over and checked when it reaches the organizer again.

Offline for a minute. Nothing lost.

A player's phone goes into airplane mode while two balls are called. When it comes back they arrive on their own, in order, and the card marks itself.

Three Android emulators · 25 Sep 2026 · cut: coming back took about 15 seconds

And two more that come with the same record

A message is an operation

When a ball is called, every phone receives the operation and runs it on its own journal — the same one the organizer ran — instead of receiving a board.

One call, applied on every phone

A ball is called on the organizer's phone. About a second later it is the last ball on the caller's board and marked on a player's card.

Three Android emulators · 25 Sep 2026 · one continuous take, in real time

A browser is another stage

The player's page runs the same subject on the same substrate, compiled for the browser, with nothing installed.

No install. A page is the player.

A first visit in a phone's browser opens the player's card, and a ball called on the organizer's phone is marked on the page about two seconds later.

Android emulators · 25 Sep 2026 · a local build of the web player, not the published page; the engine's start-up was cut

None of these was built for this application. They come with keeping the program's own record of what happened, and this is what they look like when the thing keeping it is a phone in a parish hall rather than a datacenter. The recordings were made on Android emulators and edited for length; what was cut is written under each one.

What is running

Three programs, and only one of them knows there are phones.

The game

BingoEngine

The card, the balls, the figures in play, the round, and the correction when a ball is keyed wrong. It knows nothing about phones.

256tests, green
The evening

Village

The rules of the evening: who runs it, who sells at the door, who bought which cards, the prizes promised and the requests to undo a sale. The part a hall recognizes and a game engine has no business knowing.

216tests, green
The staging

The app

An application for Android. It hosts the Puppeteer actors, holds the journals, draws the screens and carries messages between handsets over iroh.

1binary, three roles

Neither domain project references Puppeteer. Both compile against the base class library and nothing else, so Puppeteer enters at the application and never reaches the rules.

What Puppeteer is
01Where the authority sits · single writer

No server. The room is the network.

The organizer's phone makes itself the one writer. Every other phone connects to it over iroh, which dials a phone by its public key rather than its address: there is no server in the middle, and the code a phone scans says how to find the organizer.

The handshake is a QR code on the organizer's screen: how to reach it, its public key — which also authenticates and encrypts the link — and invitations good for a single connection each. That is the whole of what one phone needs to know about another.

Once a phone is through the door it receives the entire history from entry zero, and arrives current without replaying a decision of its own. It does not recompute the evening. It receives it.

That pass is for the phones that work the evening: selling cards at the door or calling the balls. A player joins with the code the seller shows at the sale — one link that opens the app, or the same screen in a browser when the app is not installed — and gets something different: not the history, but each ball as it comes out.

“cloud and microservice ecosystems become libraries the program invokes rather than habitats the program inhabits”

Paper 07 · After the Substrate
02Where the evening is kept · replicated journals

No database. A folder on each handset.

Every phone in the room keeps its own journal, and a journal is a directory in the application's private storage. There is no schema to migrate, no connection string, no engine to install and nothing to be reachable.

This is what makes the operational questions collapse into one another. Backing up the evening is copying the folder. Handing it to another phone is sending the same entries. Coming back after the signal dropped is replaying what arrived late.

And the journal is small, because of what it records: each operation by name, not the state it left behind. In Puppeteer's published laboratories an entry encodes to between 33 and 96.7 bytes, where the same operation written out in full takes 118 to 910.7 — and compressing the written-out form afterwards closes the gap only to fourfold, because the saving is in how the operation is named rather than in how the bytes are packed. A night of bingo is a small file.

Written once, by the organizer · the same entry lands in every folder, in the same placeHANDSETFOLDERENTRIES, IN THE ORDER THEY WERE WRITTEN →Organizerthe one writerCallerthe same entriesSellerthe same entriesPlayerits card and each ballPlayer, web pageasks for each ballcard 23card 2B-12N-35card 24G-54I-21card 23card 2B-12N-35card 24G-54I-21card 23card 2B-12N-35card 24G-54I-21card 23B-12N-35G-54I-21card 2B-12N-35G-54I-21No database: each handset keeps its own journal, in a folder of its own.

Written once, by the organizer · the same entry lands in every folder, in the same place

ENTRIES, IN THE ORDER THEY WERE WRITTEN →Organizerthe one writerCallerthe same entriesSellerthe same entriesPlayerits card and each ballPlayer, web pageasks for each ballB-12N-35card 24G-54I-21B-12N-35card 24G-54I-21B-12N-35card 24G-54I-21B-12N-35G-54I-21B-12N-35G-54I-21No database: each handset keeps its ownjournal, in a folder of its own.
03What never has to travel

The card is not stored. It is derived.

The number printed on a card is not a key into a table of cards. It is the card: twenty-four numbers fall out of it by a keyed hash, the same way on every phone, so a phone that has never heard of that card draws it correctly the moment it has the number.

So a card is never transmitted, stored or synchronized. A player's phone is told which numbers they bought — which cards are whose was written when the sale happened — and rebuilds the cards from them.

Cardface Of(CardNumber number)
    stream  = HMACSHA256("bingo75.cardface.v1", number)
    columns = five bands drawn from that stream
The version string is part of the key, so a future change to the layout is a different name rather than a silent change to every card ever printed.

The card is computed, never sent.

The browser shows card 2. The app receives only the number and draws the same card by itself: the same 24 numbers, in the same order.

Android emulators · 25 Sep 2026 · two builds of the rules, one in the app and one in the browser; a wait was shortened

04What travels instead · event sourcing

The players are told verbs, not state.

When a ball is called, no phone receives a board. Each one receives the fact that a ball came out, and applies it to its own journal — the same operation the organizer performed, performed again locally.

A phone that closes and reopens presents itself again, and the answer carries every ball it missed; what it had already marked was never only in memory. And a ball carries the round it belongs to: keying the wrong number twice in one evening is two corrections, not a repetition of the first.

ListenAs(role)
    .Told("Ball").With<int>("number")
        .Command("game.RegisterDraw(@number);")
    .Told("Correction").With<int>("wrong").With<int>("right")
        .Command("game.CorrectDraw(@wrong, @right);")
There is no switch over message types. What arrives is bound to the operation it names, and the operation is the same one the rules already had.

“Recording cross-actor messages as program operations preserves continuity edge by edge, without orchestration.”

Paper 04 · Preserving Semantic Continuity Across Actors
Replayed, every phone shows 43 · nothing was editedTHE JOURNAL · IT ONLY GROWS AT THE ENDBALL7BALL21BALL34keyed wrong, left as it isCORRECTION34 → 43refers to itBALL58next entryreplayed on every phoneWHAT EVERY PHONE SHOWS721344358Nothing is edited: a wrong ball is fixed by a new entry,and every phone that replays the journal shows the same board.

Replayed, every phone shows 43 · nothing was edited

THE JOURNAL · IT GROWS AT THE ENDBALL7BALL21BALL34keyed wrong,left as it isCORRECTION34 → 43refers to itBALL58next entryREPLAYED, EVERY PHONE SHOWS721344358Nothing is edited: a wrong ball is fixed by anew entry, and every phone that replays thejournal shows the same board.
Beyond the hall

The room turned out not to be a requirement.

Everything above works because everyone is on the same Wi-Fi. On 23 September the same evening ran with players in four different homes, each behind a different router, and nobody opened a port or arranged a tunnel.

One player's phone changed network in the middle of it. The link dropped, came back as the same device with the same cards, and the evening carried on.

Nobody else in the round noticed.

What changes when a phone moves from Wi-Fi to mobile dataA remote player's phone carries an identity that does not change. Its address changes from home Wi-Fi to a carrier address, and the path it takes to the organizer changes with it, passing through a relay that acts as a meeting point. The connection itself is one unbroken line from the player to the organizer.Remote playeridentityhome Wi-Ficarrier addressthe address changesrelaymeeting pointsame connection, new pathsame connection,new pathOrganizer

Measured on Android emulators. In the round itself the phone dropped and came back as the same device.

What carries this is iroh: it reaches a device by the identity it holds rather than by the address it happens to have.

What this does not claim

The boundary of the demonstration.

A system is credible in proportion to what it declines to assert. Four things this page is not saying:

  • The byte figures quoted are Puppeteer's own, measured in the laboratories published with Paper 05 — not measurements of this application.
  • This is not a resilience result from a hall. The recordings above were made on Android emulators: players come back on their own and are sent what they missed, and sellers keep selling while the organizer is away.
  • The 472 green tests cover the two domain projects: the rules of the game and the rules of the evening.
  • Everyone is on one network, for everything demonstrated above. That is not a limitation working around the absence of a server — it is the claim: the hall is the network. The band before this one is where it stops being the limit.

Follow it further.

The app

Velada, on Android

The evening as the hall uses it: one application, and the phone decides whether it leads, works the door or the balls, or plays.

Coming to Google Play
The basis

The Journal as Substrate

The paper that states the four equivalences, with the laboratories that measure them.

Read the paper
Beyond the hall

Peer to peer, across any network

What changes when the devices are not in one room: connected over iroh, found by identity rather than address, with nothing opened on a router.

Read it
The mechanism

The Stage Manager

Five cases on the two mechanisms this evening is built from: one character standing on several machines, and two characters speaking.

See the series

If this bears on what you are building, tell us which part.

Start a technical conversation