TL; DR: The code is here - sidebar — a private intercom for a few kids.
Skanda is eleven. He's starting to make more friends and those relationships may last long - outlive my life. I wanted to provide an experience that may strengthen/extend this relation he's building. A different spark that could solder (pun intended) this. There is always the phone he doesn't own, and I would like to keep it to a minimum - I am not against the phone, I am just trying to postpone it.
That spark or other thing — the walkie-talkie, the ham set, the intercom on the wall. That was my childhood excitement watching Hollywood movies where kids huddle and plot things. You press it, it rings somewhere else, a friend answers. No account, no feed, no algorithm, nobody selling anything.
Some points up front: I am a product manager by profession. While I am an Electrical and Electronics Engineer by degree, I do not do hardware (and my father always asks if I know how to change a tubelight or the choke). I am comfortable on the software side, but I had never written firmware, never touched an I2S bus, never soldered anything I would admit to. I built this with Claude — Fable and Opus — as the engineering partner. This post is as much about what that collaboration actually looks like as it is about the device.
So did I build it? I am a Product Manager - I put-it-together or assembled it. I cannot claim I built it. Not any more. For him and his 4 friends.

<!-- Mix of human voice and AI slop begins -->
What it does
Tap a friend's name. Their unit rings. They tap Answer and they are talking to each other. Tap Everyone and all of them ring at once. That is the whole product.
There is no dialling, no contacts to add, no search, no usernames. The list of names is whoever is on the roster, and the roster lives on a server I run. If a kid is not on it, the device will not ring for them, because it has no way to express them.
Under the hood
Each unit is a Nextion ONX2432G028 — an ESP32-S3 with a 2.8" touch LCD, a PDM microphone board and an I2S speaker. You could ask me why I did not start even more barebones. I am stuck-in-between being too-lazy and this-much-lazy.
Six boards — five in use, one spare — plus mics and speakers came to about CAD $250. It sits in a nice gap: more capable than a Pi Zero for this job, cheaper and far less fussy than a Pi 3/4/5, and it boots in under two seconds because there is no operating system to wait for.
kid's unit ──outbound WSS (control)──┐
├──► relay on a VPS I own
kid's unit ──outbound UDP (audio)────┘
The design constraints came from being a parent before being a builder:
- Nothing listens at anyone's house. Every unit dials out. No port forwarding, no inbound connections, nothing exposed on a friend's home network. A parent hosting one of these takes on zero attack surface.
- Voice is encrypted end-to-relay. Uncompressed 16 kHz PCM in 20 ms frames, sealed with AES-256-GCM using a fresh key for every call, sent over UDP with an encrypted-WebSocket fallback when UDP cannot get through.
- No passwords for an eleven-year-old to lose. A parent types a secret join code once at setup; the device stores a token after that.
- Nothing is recorded, ever. Audio is forwarded and forgotten. There is no disk path for it anywhere in the system.
- Has OTA Updates. Ensured that the system is capable of receiving and applying updates.
I should be precise about one thing, because it matters and it is easy to overclaim: this is encrypted to a relay I run, not end-to-end. I could, in principle, decrypt audio on my own server. I do not, and there is no code that does — but "no third party in the loop" is the honest claim, not "nobody can ever hear this." A system for children should be described accurately.
Watching without listening
Later I added a monitoring dashboard for myself: who is online, who is talking to whom, how long calls run, history over weeks.
This is exactly the feature that turns into surveillance if you are lazy about it, so it is built to make eavesdropping structurally impossible rather than merely forbidden:
- The relay writes only names, call IDs and timestamps. The audio paths never touch that database, and there is no column capable of holding a payload — a test asserts the schema contains no blobs.
- The dashboard is a separate process that opens the database read-only, holds no connection to the relay and has no access to the per-call keys. A test asserts it cannot write.
- It binds to loopback. It is not on the public internet, because the list of who my child talks to and when is itself sensitive.
I wanted to know that the thing works and that they are using it. I did not want the ability to listen to my son's conversations with his friends, and I did not want that ability sitting one commit away either.
What went wrong
This is the section that makes the rest of it believable.
I bricked my son's unit. I shipped v1.2.0 — a new clock feature — as an over-the-air update without testing it on hardware first. It boot-looped. The new code did date formatting inside a network callback on a task whose stack could not take it, and the device crashed, rebooted, crashed again. Skanda's board was dead on the shelf.
Two things saved it from being worse. The OTA is consent-based — the device offers the update and a parent taps Install, so nothing installs itself silently. And there is a health gate: a new image must prove it can reach the relay before it is marked good, otherwise the bootloader rolls back. The other two units were never at risk. I pulled the update within minutes and recovered the bricked unit over USB.
The rule that came out of it is now written into the repo: never publish an update you have not run on real hardware. Obvious in hindsight. Every hardware person already knows it. I had to earn it.
I diagnosed an outage that did not exist. Publishing a later update, I tested the download URL and got a wall of HTTP 403s. I concluded Cloudflare was blocking firmware downloads and wrote it up as a blocker. It was not. I had been testing from the server itself, looping back through Cloudflare from its own datacentre IP, which gets challenged. Real devices on home broadband downloaded it without a hiccup — as we found out when all three updated successfully minutes later.
The lesson is not about Cloudflare. It is that I verified from the wrong vantage point and trusted the result. Now the rule is: confirm delivery on an actual device, never from the box that serves it.
We are working on solving echo. You hear your own voice come back at the end of a sentence. The physics: your voice reaches their speaker, their microphone picks it up, and it returns to you delayed by the round trip. Moving the microphone and speaker apart in the enclosure helped and did not fix it. The next step is half-duplex gating — closing the microphone while the speaker is active, which is how real ham radio works anyway.
The enclosure, which is not mine
For two weeks the electronics sat bare on a table. Then Skanda sat down to design a case.
We argued about it. I deliberately stepped back from imposing my ideas, which was harder than it sounds. He worked in pencil and paper first, then FreeCAD, from scratch. He measured the board, the speaker and the microphone with a ruler, measured screws with vernier callipers, and punched the holes into the design himself.

One real constraint shaped it: the microphone connects over a flat ribbon cable, which cannot be coiled into a handheld fist-mic the way a proper ham set has. A disappointment that turned useful — the constraint pushed him toward a different design instead of a copy of something he had seen.
We do not own a 3D printer. We submitted his files to our community library and picked up the prints. Everything fit on the first try. The board seated, the speaker seated, the screw bosses lined up.
He got it right with his first designs! And was he proud. The microphone is at the top centre and the speaker at the bottom right — as far apart as the face allows, which is the correct first move against echo. The speaker sits in its own walled chamber instead of firing into an open box. The stand is a separate part, so it can be reprinted at a different angle without touching the enclosure. There is a slot in the side for the USB cable, so you never open it to charge it. The front is yellow and the tray is black, so the black recedes and the yellow face reads as the device.
We named it sidebar.

Because he was designing something, I handed him Don Norman's The Design of Everyday Things. He is three-quarters through and seems to like it, which puts it alongside his hundred-plus rereads of Randall Munroe's How To? and What If?.
What this says about building with AI
In a pre-AI world, this wouldn't have been possible. This would have been a outright purchase. Or I could have introduced him to Ham - but his friends wouldn't have been there. I could not have built this alone. That is not modesty, it is scope: firmware in C on an RTOS, PDM microphone capture, I2S playback, jitter buffering, AES-GCM key handling, NAT traversal, an OTA pipeline with rollback. Each of those is someone's specialism. I have none of them.
What I did have turned out to be the part that mattered: knowing what to build, who it was for, what "done" meant, and what was unacceptable. No recordings. No public rooms. No searchable users. Nothing that listens at a friend's house. Those are product decisions, and no model produced them.
What I learned about the collaboration:
- The AI is confidently wrong as always, and hardware punishes that. The boot-loop and the phantom Cloudflare outage both came from plausible reasoning that nobody checked against reality. Software lets you iterate out of that. A bricked board in another kid's house does not.
- Testing is the human's job. Not because a model cannot write tests — it writes excellent ones — but because someone has to plug the thing in, listen to it and say "that is echo." The physical world is not in the context window.
- Requirements do not move. This is the real difference from software product work. There is no negotiating scope with an eleven-year-old. He does not ask for a roadmap. He asks "does it work yet," and there is no PRD that survives that question — only a board that either rings or does not.
Where it stands
Version 1.3.1. Three units live, two more being brought up, roughly a dozen over-the-air releases so far. The relay runs on a Hetzner VPS behind Cloudflare and nginx, with systemd keeping it honest. Kids call each other with it, which is the only acceptance test that counts.
Still on the list: firmware signing so a device only accepts images I signed; echo suppression; and enclosures for the other four, which Skanda will print for his friends.
The code is on GitHub and is not open yet: sidebar — a private intercom for a few kids.