All posts
Build Notes

A voice app that works everywhere is an architecture problem first

A tiny widget sounds simple. Making it reliable everywhere is not.

Haider PatanwalaChief Architect / Technical Fellow, Lungoor · 7 min read

“Works wherever you type” is doing a lot of work

One of the easiest sentences to put on a website is: works wherever you type. It is also a slightly terrifying sentence if you are responsible for the architecture behind it.

A browser text field is not the same thing as Slack. Slack is not the same thing as Mail. Mail is not the same thing as Cursor. A rich text editor behaves differently from a plain input.

Selection behaves differently. Focus changes. Permissions change. Apps update. Operating systems update.

And the user quite reasonably does not care about any of this. They pressed the shortcut. They expect Lungoor to work.

That expectation changes how you architect the product

If we were building a traditional application, the boundaries would be relatively comfortable. Open Lungoor. Enter something into Lungoor. Process it. Show the result inside Lungoor.

But that is not the product we wanted. Lungoor Voice is more interesting when it is not the place where work happens. It is something that appears inside the workflow you already have.

That sounds like a UX decision. It quickly becomes an architecture decision, because now the product has to understand its environment without owning the environment.

A great demo happens once. A good architecture survives the 800th ordinary Tuesday.

The widget is deliberately small. The system behind it cannot be.

The visible Lungoor interaction might be a small listening state. A waveform. A style picker. A result. The temptation is to assume the technology should therefore also be simple. Usually the opposite is true.

Simple surfaces often need fairly sophisticated systems underneath them. The architecture has to manage application state, text selection, keyboard triggers, focus, permissions, network conditions, speech processing, model response, insertion behaviour and failure recovery.

The user should ideally experience almost none of that. That is the contract.

Latency changes behaviour

One lesson from working on voice systems is that latency is not merely a performance metric. It changes how the product feels.

If an analytics dashboard takes another second to load, the user may tolerate it. If you finish speaking and nothing happens for several seconds, something strange occurs. You start wondering: did it hear me? Should I press the key again? Is it processing? Did I do something wrong?

Now the product has created hesitation. And once people stop trusting the interaction, they alter their own behaviour to compensate. They speak differently. Wait longer. Repeat themselves. Look for indicators.

So reducing latency is not simply making the app faster. It protects the natural behaviour the product was designed around.

Reliability beats cleverness

There are always impressive things you can add to an AI product. More context. More automation. More inference. More transformations. Architecture has to be the boring person in the room occasionally.

What happens when the network is weak? What happens when the target application behaves unexpectedly? What happens if processing succeeds but text insertion fails? What happens when the user switches windows mid-request? What happens when an OS update changes an integration point?

The product still has to behave sensibly. This is why I care more about predictable systems than impressive demos. A great demo happens once. A good architecture survives the 800th ordinary Tuesday.

Every abstraction eventually meets the desktop

When you build cross-application software, abstractions are useful until reality arrives. You can create a beautifully clean internal model of “selected text”. Then one application exposes selection one way and another behaves completely differently.

You can define “insert output”. Then an editor has its own formatting behaviour. You can define a keyboard trigger. Then discover a conflict with an application shortcut.

This is normal. Architecture is not about pretending those inconsistencies do not exist. It is about containing them so they do not infect the whole product. When an application behaves strangely, that complexity should end at the appropriate boundary.

The architecture should preserve product freedom

Today’s product decision should not make tomorrow’s product impossible. Voice begins with dictation. Then comes text selection. Styles. Voice commands. Multilingual behaviour. Different processing modes. Potentially new products sharing authentication, usage, models or user context.

You cannot predict every future requirement. Trying to predict everything produces a giant architecture nobody can change. Ignoring the future entirely produces something that collapses the first time the product grows.

The useful middle is to identify the things that are genuinely foundational: identity, usage, processing contracts, context, application interaction, privacy boundaries, failure states. Those deserve careful interfaces. Everything else should remain easier to change.

The best technical decision is sometimes to do less

Engineering teams love solving difficult problems. That can be dangerous. Not every solvable problem deserves a system. Not every edge case deserves a new abstraction. Not every capability deserves a setting.

The architecture should support the product, not become the product. If a piece of complexity does not create reliability, speed, safety or meaningful user value, it deserves suspicion.

That principle sounds obvious. It becomes much harder when the clever solution is sitting right there.

What I want Lungoor to feel like

Ideally, a user never thinks about any of this. They hold a key. They speak. Lungoor responds. They select something. The relevant actions appear. They continue working.

That quiet experience is not the absence of engineering. It is usually the result of a lot of engineering being placed in exactly the right places.

Architecture is successful when the product can grow more capable without making the user feel that growth as complexity. Not how many systems we built. How little of them you have to notice.

Download Lungoor Voice and judge the architecture the way users should: by how rarely you have to think about it.

Try Lungoor Voice