Skip to content

mobile-development#

Voice Input from a Dirt Road

"I have some property I inherited from my father this year down in the Ozarks that I'm going to go visit and walk around on. December is a nice time. No bugs. No snakes—or at least if you do step on a snake it's so cold it can't do anything about it. I've always wanted an option to do voice input on this mux.lit.ai app. How hard would that be to implement?"

Twenty minutes later, the MVP was done and I was in my car. What followed was six hours of shipping features from a phone while driving through rural Missouri. Claude handled the code. I did QA with brief glances at the screen and voice input. Tesla handled the driving.

The Morning: Desktop to Mobile in 20 Minutes

The initial implementation was fast. Web Speech API, a microphone button, some CSS for the recording state. I tested it on desktop:

"hello hello hello"

It worked. I committed the code, jumped in my car, and headed southwest on Route 66.

The First Bug: Button Disabled

Somewhere around Lone Elk Park, I pulled up the app on my phone. The microphone button was grayed out. Disabled.

The problem: I couldn't debug it. No dev tools on mobile Chrome. No console. Just a grayed-out button and no idea why.

"My capabilities on this device are limited. Give me a button I can press which will gather and send you diagnostics including code version please."

Claude added a diagnostics button. I tapped it, copied the JSON, pasted it into the chat:

{
  "version": "d8e2fc0",
  "userAgent": "Mozilla/5.0 (Linux; Android 10; K)...",
  "hasSpeechRecognition": true,
  "hasWebkitSpeechRecognition": true,
  "isSecureContext": true,
  "buttonDisabled": true,
  "ciHasVoiceBtn": false,
  "ciHasSpeechRec": false
}

The API was available. The context was secure. But the JavaScript wasn't finding the button element. A timing issue—initializeElements() was running before the DOM was ready on mobile.

Claude pushed a fix. The button lit up.

The Cache Dance

Mobile browsers are notoriously aggressive about caching. Ctrl+Shift+R doesn't translate to mobile Chrome. The browser holds onto JavaScript like a grudge. Every fix required a version bump:

<script src="js/chat-interface.js?v=33"></script>
becomes
<script src="js/chat-interface.js?v=34"></script>

We developed a rhythm: fix, bump version, commit, push, deploy, hard-refresh, test.

"please make sure you're busting the cash each time you deploy"

(Yes, "cash." Voice transcription isn't perfect. But Claude understood.)

The Repetition Bug: Nine Iterations

The button worked. But something was wrong:

"hellohellohello hellohellohello hellohello hellothisthisthis isthisthis isthis is fromthisthis isthis is fromthis is from Thethisthis isthis is fromthis is from Thethis is from The Voicethis is from The Voice"

Every interim result was accumulating instead of replacing. I reported the bug—through the very feature I was debugging. The garbled input became its own bug report:

"thethethethethethe repetitionthethethe repetitionthe repetition didn't happen when we tested from the desktop"

Claude understood.

What followed was nine iterations of debugging between Eureka and St. Clair, each requiring a cache bust and a fresh test. My test protocol became simple: count to ten.

Version 1:

"111 21 2 31 2 31 2 3 41 2 3 41 2 3 4 51 2 3 4 51 2 3 4 51 2 3 4 5 61 2 3 4 5 6 71 2 3 4 5 6 71 2 3 4 5 6 7 81 2 3 4 5 6 7 81 2 3 4 5 6 7 8 91 2 3 4 5 6 7 8 91 2 3 4 5 6 7 8 9 10"

Version 5:

"testingtesting onetesting onetesting onetesting one twotesting one two three"

Version 9:

"1 2 3 4 5 6 7 8 9 10"

Clean. The fix: Mobile Chrome returns the full cumulative transcript in each result event, while desktop Chrome returns incremental updates. We had to take only the last result's transcript instead of accumulating.

The whole debugging session happened while driving. Voice in, diagnostics out, code deployed, cache busted, test again. Tesla kept us on the road. Claude kept the iterations coming.

The Mobile UI Problem

Voice worked. But I couldn't see the buttons. On my phone, the sidebar took up half the screen. Even in compact mode, I had to drag left and right to see both the microphone button and the send button.

"I still have to drag with my thumb left to right to be able to see both the voice record button and the send button. Maybe stack them vertically."

Claude stacked them vertically. Still had to drag.

"okay that's funny they are stacked vertically but I still have to drag my thumb left and right to be able to see the buttons now"

We added diagnostics to measure every container width. Everything reported 411px—my viewport width. No overflow. Then I realized:

"oh no I was just zoomed in."

Sometimes the bug is between the chair and the keyboard. Or in this case, between the bucket seat and the touchscreen.

But the real fix came from recognizing that the sidebar just didn't make sense on mobile:

"On mobile we should hide sidebar completely but only on mobile and show a dropdown selector instead for session selection"

Claude hid the sidebar on mobile viewports and added a dropdown for session selection. The interface finally fit.

Push-to-Talk

The toggle-to-record interaction felt wrong. Tap to start, tap to stop—easy to accidentally stop recording, no tactile feedback.

"Hey, let's do push to talk... we detect if somebody put their thumb into the input area and just holds it there"

Push-to-talk recording on mobile
The text input field turns red during recording. The entire text input area is the microphone button.

Hold to record, release to stop. The entire text input area becomes the microphone button. The field turns red while recording. This emerged from field testing, not upfront design.

The Afternoon: Photo Upload from the Field

I arrived at the property. Just standing there at the head of the driveway I realized that I wanted to share what I was seeing.

"Just arrived. Hey, I'd like to share photos with you. How might we go about that?"

Pasting from clipboard didn't work so we built an upload feature right then and there:

"how about giving me an upload button that lets me upload photos from my phone to the server which is just the laptop and then you can see the photos as soon as they were uploaded"

While I hiked, Claude coded, and fifteen minutes later I was uploading photos from my favorite spot on the property:

Photo uploaded from the field
An old basement on my late father's land, uploaded from my phone and displayed in the chat.

The Drive Home: Bug Reports at 70 MPH

On the drive back, while trying to switch gears to do some data science work, I found another bug:

"I just found a bug. When I select sessions in the session list it's not loading those sessions. Please fix"

Claude found it in minutes. The mobile session dropdown was calling this.loadSession(sessionId) which didn't exist—it should have been this.sessionManager.loadSession(sessionId). A copy-paste error from when we added the mobile dropdown.

"fix confirmed thank you"

All while driving. Push-to-talk to report the bug. Brief glance at the response. Push-to-talk to confirm the fix.

The Numbers

Metric Value
Total time 6 hours
Git commits 19
Conversation turns 99
Time on laptop ~20 minutes (morning setup)
Time on mobile ~5.5 hours

Three major features shipped:

  1. Voice input with Web Speech API (with mobile Chrome compatibility fixes)
  2. Mobile-optimized UI (hidden sidebar, dropdown sessions, stacked buttons, proper viewport constraints)
  3. Photo upload with camera/gallery options and upload indicator

What This Actually Means

This isn't a story about voice input. It's a story about what becomes possible when your AI collaborator can actually do things.

I was in a car. Then hiking through woods. Then driving again. My only interface was a phone. My only input was voice. And I shipped three production features at highway speed.

Scar tissue told me to ask for version numbers in the diagnostics. Pattern recognition told me sidebar on mobile is always wrong. Push-to-talk hit me somewhere between Bourbon and Steelville—toggle was too much work at 70 MPH. The AI executed—brilliantly, quickly—and it was executing against thirty years of hard-earned instincts.

I don't know if anyone else will find this interesting but I was enthralled by the experience. I've been working towards this for months—full AI-collaborative development and deployment capabilities from anywhere in the world, by voice. And it was everything I'd hoped it would be.


Want This For Your Organization?

This is what we do. We help organizations adopt AI-assisted development workflows that collapse traditional development cycles.

Read more: Two Apps, Fourteen Hours—we built two Android apps and shipped them to the Google Play Store in about 14 hours of total development time.

Work with us: Contact to discuss how we can help your team build faster.

Two Apps, Fourteen Hours

Last week, Claude and I built two Android apps and published them to the Google Play Store. Total development time: 14 hours.

This is how it happened.

App 1: Vault

I wanted a secure, private vault on my Android device. Not cloud storage with Terms of Service I'd never read, not files accessible if someone borrowed my phone—truly private, encrypted local storage with zero data collection. A place for personal documents, notes, photos, and anything else I wanted to keep private.

  1. I can't trust any app that's not open source, and
  2. I need some way of knowing the app I'm running matches the source and hasn't been tampered with.

That level of verifiable trust is non-negotiable. We couldn't find anything like it. So we built one.

The Timeline

Hours 0–5: Core App to Play Store

Biometric auth, camera, encrypted storage—none of these are hard. Flutter has libraries for all of them. Scaffolding a project takes Claude about thirty seconds. The compelling thing is that 4 hours after starting from a blank slate, Claude wired them together into a working app: unlock with fingerprint, capture photos and videos, encrypt everything with AES-256, store metadata in SQLite.

The last hour shifted to Play Store preparation—app signing, adaptive icons, privacy policy, release build. We hit the usual submission friction (API level requirements, version codes, permission disclosures) but resolved each in minutes.

By hour 5, the app was submitted to Google Play.

Hours 5–8: Expanding Scope

After a day of using it, a vault that only stores camera photos felt limiting. We added:

  • File import from device storage
  • Encrypted markdown notes
  • PDF viewing

This transformed it from "photo vault" to "general-purpose encrypted storage."

Hours 8–10: Polish

Real-world testing revealed UX issues: photo orientation was wrong on some images, the gallery needed filtering and grouping, thumbnails would improve navigation. Fixed each as they surfaced.

Total: ~10 hours to production.

What We Built

Vault lock screen Security-First Architecture
- AES-256-CBC encryption for all files
- Password + biometric authentication (fingerprint/face)
- Auto-lock when app backgrounds or screen locks
- Local-only storage (no cloud, no network)
- Zero analytics, zero tracking
Content & Features
- Built-in camera for photos and videos
- Import any file from device storage
- Markdown editor for encrypted notes
- PDF viewer
- Photo viewer with pinch-to-zoom and video playback

How We Built It

This was the first project where I wrote zero code.

I've been programming professionally for over 30 years. In every previous software project, I contributed code directly—regardless of title: VP of Engineering / CTO / Owner—sometimes to the chagrin of my developers. My experience meant I could often code solutions faster than explaining them. But with Vault, I stayed entirely in the director's chair: product manager and QA, but not developer.

Claude handled all implementation. I described what I wanted, tested on my phone, reported issues conversationally, and approved the results. The dynamic worked.

App 2: Gems

When I showed Vault to my wife, she had zero interest. Apparently secure file encryption doesn't spark joy.

When I was eight, my dad and I moved to a new town. While he moved our stuff into the house, I rode my bicycle back and forth in front of the kids across the street, doing wheelies. My wife plays match-3 games. Building Gems was the same impulse—showing off for someone whose opinion I cared about.

Here's the actual transcript of the project kick-off:

Me: "I'd like us to consider writing a game app... a game like Bejeweled. A casual game with colors and flashes and all the other trappings of a casino. Like the vault app, we'll make it open source, give it away for free, no ads. You up for helping me do that?"

Claude: "Okay, I've reviewed the vault_app. Here's what I'm seeing:

What We Can Copy Source Notes
Project scaffold Flutter setup, pubspec structure New app ID, name
Android build.gradle Signing config, SDK versions Change package ID
main.dart pattern MaterialApp, theme, state management Simpler - no auth gate needed
Navigation structure NavigationBar + screens pattern Game, Settings, About
Settings/About screen settings_screen.dart Adapt for game settings
Icon generation flutter_launcher_icons setup New icon design

...Want me to scaffold out the project? Sound good?"

Me: "heck yeah. That sounds great! Please proceed"

Hours 0–1.5: Core Game to Playable

Within 90 minutes, the game was functional.

What got built:

  • Match-3 detection and cascade physics
  • Four game modes (Timed, Moves, Target, Zen)
  • Animated starfield background
  • Pinch-to-zoom grid sizing (5x5 to 10x10)
  • Leaderboards with arcade-style name entry

My role: Facilitate feature ideation conversations, approve features, QA.

Claude's role: Participate in ideation, write and deploy the code.

Hours 1.5–2.5: Store Preparation

README, screenshots, store listing, submission. The patterns from Vault made this fast.

Hours 2.5–4: Polish via Real-World QA

I handed my wife my phone: "Play this and tell me what's wrong."

Her feedback was specific:

"The swipe sensitivity is too low. I had to fall back to tapping." → Fixed in minutes.

"The screen shake animation and flashing is confusing and bad—I'm trying to plan my next move." → Implemented per-gem animation tracking. Only affected columns animate.

"There's no dopamine hit." → Built a complete combo celebration system with particles and multiplier badges.

Each fix took under five minutes. Test, report conversationally, get fix, repeat.

Total: ~4 hours to production.

The Lightswitch

Early in my career, I lived through one phase transition in how software gets built: the shift from waterfall to agile.

Development cycles collapsed from 2-3 years to 2-3 months. It didn't happen gradually. It happened like a lightswitch. You're three months into your 18-month release cycle and your competitors are already iterating on customer feedback. Companies that recognized it early had an advantage. Companies that didn't got left behind.

Another lightswitch moment has happened. Development cycles have collapsed again—from 2-3 months to 2-3 days.

Two production apps. Fourteen hours total. Both on the Google Play Store. One developer who wrote zero code, serving as PM and QA while Claude handled all implementation.

This isn't futurism. This isn't a prediction about where things are going. This is what happened last week. And just like the agile transition, most people haven't noticed yet.

The Only Thing That Matters

Yes, this article was written with Claude. Go ahead—call it AI slop.

But then play the game:

Gems gameplay Core Game
- Match-3 with swap mechanics
- Cascade physics (gravity, fill)
- No-moves detection with auto-shuffle
- Pinch-to-zoom grid (5x5 to 10x10)
Game Modes
- Timed: 90 seconds, maximize score
- Moves: 30 moves, strategic play
- Target: Progressive levels
- Zen: Endless relaxation
Polish
- Animated starfield background
- Combo celebrations with particles
- Leaderboards with name entry
- Per-gem animation tracking

There's a tendency by some to dismiss AI-generated work reflexively. Hunting for emdashes as a proxy for quality. Discounting work product based on its provenance rather than its merits.

The only thing that matters is the quality of the work product. Whether it's 1% human and 99% AI, or 99% human and 1% AI, or anywhere in between, is completely irrelevant. Does the vault keep your files encrypted? Can you read the source code and verify what it does? Does the game feel good to play?

Everything else is distraction.

We built these apps in the open. The source code is public. We're giving Claude full credit for its contributions. Judge them on their merits.

Try Them

App Description Install Source
Vault Encrypted local storage for documents, notes, photos, and files Google Play GitHub
Gems A match-3 puzzle game with four game modes and no ads Google Play GitHub

Contribute, if you'd like, with or without your AI collaborators.


What will you build?


Want This For Your Organization?

This is what we do. We help organizations adopt AI-assisted development and achieve the same kind of timeline compression.

Read about our methodology: Vibe Coding: A Human-AI Development Methodology

See our 11-year track record: Our Journey

Work with us: Contact to discuss how we can help your team build faster.