Skip to content
All builds

ParleyRealtime Chat

What it does for you

Slack-lite team chat with rooms, DMs, threads and presence over a hand-written WebSocket server, zero npm.

Parley screenshot

Screenshots

Parley screenshot 1

In more detail

Parley is a small Slack-style team chat. Messages, typing, reactions, and who is online show up for everyone instantly. It has public and private rooms, DMs, threads, @mentions with an inbox, unread badges, and search within a room.

Honest limits

History and search are rebuilt in memory at boot. That's fine for a team, not for years of messages. Browser push notifications and file uploads were cut for time. The demo runs three simulated teammates on a fictional team. It's never been under real load.

How I built it

This was another row from Codex's list that Claude Code took over on the final day. I set the spec and the order: pure core, then tests, then server, then UI. Claude Code wrote it all in small files on Node 24 with node:http and built-in node:sqlite, vanilla ES modules in the browser, no npm, no build step.

Realtime apps look simple until the network misbehaves: a dropped socket, a retried send, a tab that was asleep for a minute. So I wanted to prove the parts that make chat trustworthy (no duplicates, no missed messages, no leaks from private rooms), not just a demo on a perfect connection.

Accounts use scrypt password hashes and httpOnly session cookies, and the WebSocket only opens if the session cookie checks out during the upgrade. A live test boots the server on a spare port, opens real WebSocket connections with cookies, and proves delivery, typing, private-room isolation, retry, rate limiting, and reconnect replay. Then Claude drove headless Chrome over the DevTools protocol to click through the real UI: send, autocomplete, drop and reconnect, thread reply, search. That run caught a bug every unit test missed.

What I learned

  • One global change counter (rev) that every post, edit, delete, and reaction bumps solves three problems at once. Reconnect replay is "everything with a higher rev in rooms you belong to," stale updates get dropped, and a client-generated id makes sends safe to retry.
  • The reconnect cursor has to start at the server's rev from the welcome message. We only advanced it on live events, so a quiet client reconnected with no cursor and would have missed everything. The server tests were all green. Only the browser run caught it.
  • Check membership when each event goes out, not when the socket connects. Invites, joins, and DMs change membership while sockets stay open.
  • A presence grace window is a state-machine problem, not a timer problem. With a fake clock, the flicker cases (second tab, quick reconnect, heartbeat timeout) became plain assertions.
  • Safe Markdown was easier by escaping everything first, then letting the renderer produce only a short whitelist of tags, with link URLs checked against an allowlist.

What carried forward

We didn't write a WebSocket layer from scratch. The handshake, frame codec, SHA-1, parser, and rate limiter are imported by relative path from project 91 (the multiplayer game, Veer), which was built earlier that day with its own tested core/ and server/ws.js. That's the reuse pattern paying off: a hard protocol piece got written once and trusted twice. The browser-driven click test over the DevTools protocol is a pattern that also shows up across the RAG builds (64, 65, 66) and the bookkeeping app (67).

If I took it further

I'd keep the pure core and the rev design, but move history and search into SQL queries so it scales past a small team. Then I'd add push notifications and file uploads.

#063 Built with Claude Code September 24, 2026 446 automated checks

Want one like this?