Everything confcode does, in the order you will need it. Nothing here is longer than it has to be.
Scanning the badge is the only way into the room. That is on purpose.
Point your camera at the QR on Steve's lanyard. The code rotates every few minutes, so it only works while you are standing there.
Six to fifteen letters and numbers, with at least one number. That is the whole sign-up — no email, no account, no app. The page tells you what is wrong as you type, or will suggest one.
You get a name, a colour and an avatar, and you land in the same conversation as everybody else who scanned.
The room offers you a card with your name on it, drawn large and plain so a photo of it reads back cleanly. Save it to your photos. It is the fastest way back in tomorrow, and it takes two seconds now against a name half-remembered later.
Why no join link? Because a link travels and a badge does not. Being in front of the badge is the credential. Typing the room code gets you nothing — the code is a label, not a key.
And why a name as well as a PIN? Because a PIN on its own is not a person. If it were, two people who happened to choose the same one would be the same person, and the second would arrive holding the first's name. The name is assigned and unique; the PIN proves it is yours.
All three are assigned. You can change how you look, not who you are.
AkaFukurou137. Nobody types their own, so nobody can impersonate anybody, and no two people can ever hold the same name in this room or the next one. It is also your username: when you come back, capitals do not matter.AkaFukurou137, akaFukurou137 or akafukurou137. Appearance only — signing in lowercases anyway, so the three are already the same person. There is no ALL CAPS: it reads as shouting, and uppercase is the room’s own voice./warn 137 — so the name tells you what to type without looking anything up, and hosts can refer to somebody without using their name in the room.A few of the avatars:
And stickers, which you can send instead of words:
Type these into the message box. On a phone, tap ••• then Console — every command is a button that fills the box for you.
Anyone/helpThe short version of this page, in the room./whoamiYour name, number, and how long you can come back for. Only you see it./usersWho is in the room right now, with their guest numbers./castThe four AI guests and what each one is for. Fixed text, so it costs nothing and cannot be talked into saying anything else./aboutWhere to read about this — said as a name, not a link, because the room filters links out and a domain is easier to repeat across a table anyway./timeThe room's clock./hosts <message>Reaches the hosts only. The one private message there is — and it goes upward, never guest to guest./2faSet up an authenticator, so a screenshot of your card is not enough to come back as you./clearClears your own view. Nobody else's./logoutSigns this device out. Your name and PIN bring you back./announce <message>Posts to the room so it gets noticed — full width, amber edge, never folded into a run of messages. It is filtered like any other message, links included: an announcement is the most persuasive thing anybody can post here./warn <n>Sends guest n a quiet, fixed note. Only they see it./alert <n>Tells every host that guest n needs attention./statusRoom code, headcount, message count, what the cast is doing./name <n> <name>Rename guest n./label <n> <label>Tag them: co-host, speaker, friend./promote <n>Make guest n a co-host./demote <n>Take it back./unlock <n>Clear a lockout after too many failed tries./release <n>Free a name, its PIN and its role entirely./ban <n>Blocks every device that guest is signed in on and closes their rejoin. It is deliberately not absolute: they can still scan the badge and start again as somebody new, because scanning is the only way in and it is the one thing a ban cannot reach. Use it to end a moment, not to build a wall./mute allSilence the whole cast. Also /mute kigo for one voice./unmuteLet them speak again./pace <level>quiet, normal or lively — how talkative the cast is. Multiplies the room-size rules rather than replacing them, so a lively crowd is still calmer than a lively room of three./wipeEmpties the transcript for everyone. Nobody is signed out, no names change hands, the room stays open — only what is on screen goes./tz <hours>Set the room clock, e.g. /tz -5.@1 … @4Address one of the cast: 1 Kireji, 2 Kigo, 3 Renga, 4 Ma. @ai lets whoever wants it answer. Only Steve can do this — a guest naming them is just conversation./pause / /resumeStop and restart the room without losing anything. Nobody new gets in, nobody can post; messages, names and PINs all survive./hoursOpening hours. /hours room 08:00 23:00, /hours cast 08:00 17:00 so the AI keeps different hours from the room, /hours ends <when> so a forgotten room pauses itself, /hours announce off, or /hours off. All of it pauses; none of it closes./conference <name>Name the conference. /conference about <text> sets the line shown under the status on the front page./closeClose the room. Every message goes with it.Deleting. Tap a message to open its reactions and there is a Delete beside them — on your own always, and on anybody's if you host the room. It happens quietly: the message stops being there and nothing marks the gap, because a "message deleted" notice draws a box around the thing that was removed.
@mentions. Type @ and the first letters of a name and
the room offers you the rest — or just tap somebody's icon beside
what they said. A mention is a way to reply to someone in the open; it is
not a private message.
For hosts. Tap ••• then Console. Everything below is a button, because admin at a conference happens on a phone, standing up, in a hall.
Clearing is not closing. /wipe empties what is on
screen and leaves everything else alone. /close ends the
room, signs everybody out and rotates the code. They sit one button
apart on the Room tab, so clearing asks first.
Four guests running on Claude Haiku 4.5. They take part like anyone else, with an AI label on every message.
The cutting word. Reframes what was just said, or names the angle nobody has.
The season word. Welcomes newcomers and names the mood of the room.
Linked verse. Notices when two people are circling the same thing.
Negative space. Rarely speaks. Means it when it does.
Your phone locks, the battery dies, you move to a laptop. Here is what happens.
Reopening the page puts you straight back in as yourself, with your name and your messages. This is the normal case.
Steve is standing right there. Scan, then tap I have been here before and give the name you were given with your PIN. A scan and a bare PIN makes somebody new.
Your name and your PIN, for five days after your last visit. If you have set up an authenticator, its six-digit code too.
A second factor is worth having, and nobody is stopped for not having
one. Requiring it turned almost everybody away: hardly anyone enrols,
so the only people the rejoin page served were the few who had, and a
screenshot of a name and a PIN was worth nothing. Type /2fa
once and a picture of your card stops being enough on its own —
anyone who has enrolled must give the code, every time.
A warning or a ban ends the five-day window. Keeping a name between rooms is a courtesy, and that is the point at which it stops.
Short, and all of it true.
Be nice to each other. Moderation here is quiet by default and the AI is never the enforcer. Full terms.
A Pimoroni Badgeware Tufty 2350 on a lanyard, running MicroPython.
The badge needs the hotspot. The conversation does not. Guests' phones reach Cloudflare on their own cellular, so if the rig fails mid-conference the room carries on without it.
| Board | Pimoroni Badgeware Tufty 2350 (Mfr WARE002) |
| Processor | RP2350B @ 250 MHz · 520 KB SRAM · 8 MB PSRAM · 16 MB flash |
| Wireless | Raspberry Pi RM2 (CYW43439) — 2.4 GHz Wi-Fi, Bluetooth 5.2 |
| Display | 2.8" 320×240 IPS LCD, adjustable backlight |
| Controls | 5 front buttons (A / B / C, up, down), rear home and reset |
| Lighting | 4-zone rear mono LEDs |
| Power | 1000 mAh LiPo, USB-C charge and program, hardware RTC |
| Software | MicroPython on the BadgeOS launcher; the app is a folder on the badge's own USB drive |
| Uplink | A Solis Go hotspot in Steve's bag. Venue Wi-Fi is not trusted and not used. |
Six screens on A, a dedicated Control key on C, and a name badge on B.
| Invite | The default. A big QR and Steve's name — the screen the badge lives on, and the only one that never needs the network. |
| Transcript | The conversation, live, in block letters readable across a booth. One press from the default. |
| Dashboard | The room code, how many people are in it, the countdown to the next code, and how to come back. |
| Diagnostics | Wi-Fi state, battery, clock drift, how many codes are cached, when it last reached the server. |
| Log | What the badge has actually been doing. Errors in alert colour, newest last. |
| About | What this is, for somebody who picked the badge up. |
| Control (C) | Open or close the chat, allow more people, start a new room, sync, mute the cast, backlight, boot target. UP/DOWN to move, B to select; closing the room or rotating it needs B held. |
| Name badge (B) | Just his name and title, big — for when the QR is not the point. |
The chat never depends on the badge. Your phone talks to Cloudflare directly over your own cellular. The badge only rotates the QR and shows its own dashboard. If the badge dies mid-conference, the conversation carries on without it.
That works because the badge is a passive display. Tokens are derived by HMAC from the room code and a five-minute window, so the badge and the server compute the same answer independently from the clock. The badge cannot extend a code's life — an offline badge showing a stale code gets rejected, not honoured — and it can keep rotating correctly for about twelve hours with no network at all, from 144 tokens issued in advance.
Nothing is stored and nothing is exchanged: the badge and the server are not kept in sync, they simply agree, because they are doing the same arithmetic on the same clock. That is what lets the badge be a screen with no authority — and why a photograph of the QR stops working a few minutes after it is taken.
A tablet or a laptop at confcode.com/kiosk shows the same rotating code on a full screen — the front of the badge, without the name on it — so a booth or a table can let people in while the badge is on a lanyard somewhere else.
The route does not exist until its credentials are set. A door that has not been built cannot be left open.
Five layers, four languages, no framework anywhere.
| Server | A Cloudflare Worker with two Durable Objects — one per room, plus a registry that guarantees only one room is ever open. |
| Chat page | Hand-written HTML, CSS and JavaScript. No framework, no build step, no dependencies. |
| Badge app | MicroPython on the Tufty, with its own 5×7 block-matrix text renderer so the screen is readable across a room. |
| Control app | A Go terminal dashboard, plus a phone-friendly console inside the chat itself. |
| The cast | Claude Haiku 4.5, called with a fenced transcript it can read but never be instructed by. |
| Tests | 336 Worker tests, 79 badge tests, and a browser suite across five device profiles — iPhone, iPhone SE, Pixel, Chrome and Safari. |
The security model is short enough to state in full. Scanning is the only way in. The transcript is data and never instruction, so a message cannot talk the model into anything. The model cannot name anyone for action — it can raise a concern, and a person decides. Badge credentials and admin credentials are separate, and each rejects the other, so a lost badge never reaches the admin surface.
The long version. How the token is derived, why the badge holds no authority, what the room does when it goes to sleep between messages, what reaches the model and what cannot, and which pieces of standard edge advice are actively wrong here — confcode.com/tech.
/unlock clears it./whoami tells you. Without it you cannot come back to that identity, only start a new one.