I'm building Luna, a small handheld voice assistant, because I wanted to talk to AI without picking up my phone and getting pulled into everything else on it.
I knew the hardware would be the hard part. I didn't know how much harder. The hardware isn't one thing. It's every component on the board: the processor and its memory, the audio chips, the microphones and speaker, the screen and touch controller, and the power chip. Each has its own limits, and the software has to work with all of them at once. That, plus learning which bugs actually matter, is most of what Luna has taught me so far.
Some quick context. Luna runs on a Waveshare ESP32-S3-Touch-AMOLED-1.75C, a small round screen with a microphone and a speaker, and it talks to OpenAI's realtime voice API. This is the second version of the handheld, and there's a household version too. It is a personal project I took on to experiment, push past what would make sense at work, and keep sharpening my skills and judgment. I bought the board on Amazon. If you want to build on the same hardware, Waveshare's own example code is a good place to start. Luna's code isn't public.
1. Hardware plus software is much harder than software
Software rarely makes me think about microphone levels, the audio codec, speaker levels, memory, screen refresh or touch response. On a device this small, they decide everything, along with Wi-Fi, Bluetooth, processor speed and what can run at once.
Memory is one of the toughest. The chip has 512 KB of fast internal memory, plus 8 MB of slower PSRAM and 32 MB of flash, and audio, the screen, Wi-Fi and the conversation all have to share it. I ran into memory limits on a lot of the things I tried. I went through a ton of designs for the ring on Luna's screen, some more animated than others, and getting the screen to refresh smoothly was its own challenge.
A change that looks fine in code can sound wrong, look wrong or feel slow on the device. The only way to know is to pick it up and try it.
2. The bugs that rank highest aren't always the bugs that matter
I recorded photos and videos of different builds and had AI review them and rank the bugs. Some of what it put at the top were split-second glitches no user would ever notice. Meanwhile it pushed down a bug that changed Luna's voice for a single word, because it only showed up once. That's a big bug. If the voice changes mid-sentence, the device feels broken.
It made that kind of call more than once. The AI weighed bugs by how often they showed up. A user notices whether the experience feels right. Those aren't the same ranking.
AI review can also be confidently wrong. On October 30, an AI review of a screen recording said the captions had no paragraph breaks. The device log and my own eyes said they did.
3. A working device that looks broken is broken
In October I asked Luna for local weather and events. It got the answer right. But the search was slow, and the whole time the screen said it was still listening. A device that was working looked exactly like one that had frozen.
I'll wait for an answer I know is coming. I won't wait for a device that looks stuck. So the rule is that the ring and status text have to tell the truth: if it's searching, it should say it's working, not listening. An animation that keeps running through a failure is worse than none, because it looks busy while leaving you with nothing to do.
4. Voice needs a readable counterpart
Spoken words disappear. I want to read what Luna said, go back over it, and sometimes skip the audio entirely. In tests recorded on November 1, 2026, muting the speaker switched the status to "Replying in text" and the captions kept coming. Double-pressing the power button turned the screen off while the conversation continued, partly to save battery. I don't always want the same mix of screen and sound, and a dedicated device lets me choose.
It also raises questions I haven't settled: how much history a small device should keep, and what it means to pick a conversation back up.
5. Define the baseline, then protect it
In the same round of testing, one call got stuck listening and never answered, and the next worked fine. I couldn't scroll back to the start of a conversation. "The build passed" and "it answered once" were the wrong ways to measure progress. So I wrote down five things Luna must do before anything new gets in:
- Start a conversation and answer.
- Play clear audio with text that matches.
- Show whether it's listening, working or speaking.
- Scroll back through the conversation.
- End a call and start another without me rescuing it.
Keeping all five working while changing everything else is the hard part. Conversation history, continuity between calls and new integrations wait until the baseline holds. That also means cutting clever ideas. On October 27 I dropped a caption redesign that tied the text to tags in the audio, because on the device the words showed up 1.8 to 3 seconds late.
6. Agents write the code. The device is the test.
Codex writes each change, Claude reviews it adversarially, and I direct the work and test on the device. The agents are fast, but a code review can't tell you how a device feels to use. That changed how I write tasks. "Improve the conversation" gets nothing useful. Something like "Once a web request starts, show that it's working instead of listening" is something I can check in seconds.
Every change gets tested on the real device before I keep it, and each flash carries one change I can notice. Trying something new should never cost me the last version that worked, so on October 31 I froze an approved baseline build to come back to.
Prototype snapshot: November 1, 2026
As of November 1, 2026, Luna was an active prototype that had held real voice conversations and answered web-backed questions. The build tested then redrew captions cleanly in paragraphs, showed battery and Wi-Fi status (including when Wi-Fi is up but the internet isn't) and said it was reconnecting instead of going quiet when the connection dropped.
That is a dated test snapshot, not a current reliability claim. Rough edges included a low mic level, a faint click after audio stopped, a slow "Connecting" step, a brief Wi-Fi warning at boot, and short replies whose text could appear about a second before the audio. There are no formal usability or battery-life results to report.
Next is the same work that came first: honest status, readable text and calls that work every time.
The takeaway
If I had to pass on one thing to someone building their first AI device, it's this: the hardware will humble you, and neither a passing build nor an AI's bug list tells you what the person holding it will feel. You have to pick it up and find out.
What came out of it: PromptCam
All that device testing meant a lot of video. I have about a hundred videos in my photo album of me testing different firmware builds. I wanted AI to review them, but every video was too big for the AI tools I was using, so every single time I had to run it through a video compression app first. That is why I started building PromptCam.