Justin Francisco
All work

Nia: Natural Interface Agent

An assistant I am building into my own phone, a Motorola Razr. A phone that stays out of the way until I choose to open it, with a small character inside that clears the rest away.

Year
2026, ongoing
Role
Product, design and code
Device
Motorola Razr Ultra, Android 15
Status
My daily phone. Still changing every week.
Nia's desk screensaver, and the same screen over Nia's fishing pier at night

Why I built it

The whole reason I started Nia is that I constantly felt my attention being sucked away on the iPhone. I also had a certain nostalgia for the old flip phones. Wouldn't it be better to be less distracted?

So the phone has two states. Closed, I see only the most important things. If I decide to open it, I'm making a conscious choice to enter the phone's world. Inside that world, Nia strips away distractions too.

It is also a little bit cute, with something of a phone pet about it. I wanted to experiment with personality in software. It is a rare thing these days.

Three beliefs came out of that.

People, not ad revenue. The phone works for the person holding it. Nothing in it exists to be looked at more: no feed, no count to clear, no reason to open it without a task.

Open the phone to act, not to be acted upon. Closed is the normal state, not a lesser one. Closed is review and voice. Open is a choice. Propped on a desk, it is a clock and Nia's room.

Keep the joy. Calm is not grey. A character who fishes, a chip-tune ringtone, a camera that makes accidental art. The devices of 2001 had personality, and then they left you alone.

The desk screensaver at v0.2.0, the reference every new surface is held against.
The desk screensaver at v0.2.0, the reference every new surface is held against.
Keep the joy: the same clock over Nia's pier at night. The greens here are the painting's, not signals.
Keep the joy: the same clock over Nia's pier at night. The greens here are the painting's, not signals.

One colour, and it means live

Dark, cool greys, and one green. The ground is near-black, not black: pure black read as a hole in this screen.

The green is kept for one meaning. If something on screen is green, it is happening right now. On a normal morning no surface has any green on it at all, and that absence is why it works.

Even Nia's own work is not green. Thinking is grey.

Ground to words

#0A0B0D
#101317
#1A1E24
#424A54
#9BA3AC
#ECEFF2

#3FDB5F is live, and only live. Listening, a timer running, a song playing, a meeting starting, charging. Never important, never selected, never branding. Paused, it goes grey.

Down: a real problem, a low battery
Up: data in a chart, a finished to-do
Command: a verb you can press
The music widgets: the bar is green while the song plays, and grey once it is paused. With nothing playing, the widget shows Nia.
The music widgets: the bar is green while the song plays, and grey once it is paused. With nothing playing, the widget shows Nia.

Two voices

Two typefaces, strictly divided. Space Grotesk for anything a person said or would say. Space Mono for what the machine knows: labels, counters, durations.

Size follows distance, not importance. The clock is as big as the space allows because it is read from across a desk.

Space Grotesk · human information

Thursday, Sep 17

12:28

Names, words, the date, what someone said. Light, only for big numerals read from across a desk.

Space Mono · machine state

WORK
PEOPLE
00:42 LEFT

Section labels in capitals, counters, durations. Never on anything read from a metre away; it was unreadable there.

The character

Nia is a pixel art character: black and white, with the live green, and the pose is the phone's state. Listening, thinking, music, asleep, charging. Never a mood made up for effect.

Nia reacts and never asks. A tap wakes Nia up. Play music and Nia sways. Nia never wants attention, never sulks and never keeps score.

Propped on a desk, the phone can show Nia on a pier at night. Tap the water to fish. A catch rises, shows its name and fades. No card, no count, no buzz.

Nia, idle
Idle
Nia, listening
Listening
Nia, thinking
Thinking
Nia, music
Music
Nia, asleep
Asleep
Nia, alert
Alert
Nia, charging
Charging
Nia, low battery
Low battery

The rim: a line round the screen

ListeningGreen, swelling with my voice. The only time it is green.
ThinkingGrey, with one light travelling round.
SpeakingSoft white, the colour words already are.

On the Mac

I wanted my phone to stay closed on my desk while I'm at work, and still be in touch with what needs my attention. It takes the idea one step further: with the phone shut, I'm not distracted by opening, say, Twitter.

So the Mac has a page of Nia, laid out the way Mail and Notes are: the chat, my texts, notes, to-dos and the calendar in one window.

The phone is still the only place anything lives. Each click on the page is a request to the phone, and the phone does it as if I had touched it, with the same rules. A text still waits for my yes; a calendar change still has its Undo.

The same system holds. Dark greys, the two voices, and green only for what is live: the timer counting down, the song playing, a meeting about to start. On a quiet afternoon the page has no green at all.

Shown with made-up demo data.

The calendar: the month, what is next, and what needs me.
The calendar: the month, what is next, and what needs me.
A conversation, answered from the Mac through the phone.
A conversation, answered from the Mac through the phone.
To do, read and changed where it sits.
To do, read and changed where it sits.
The phone's battery, with the charger in the data green.
The phone's battery, with the charger in the data green.
Asking Nia about the day.
Asking Nia about the day.

What I assumed, and what the phone said

Every finding goes into one notebook, measured on the phone and never assumed. It is past 7,700 lines. These eight changed how the whole thing is built.

The pattern is the same each time. The obvious approach reported success, and nothing happened.

A home screen of my own

Assumed
A phone this personal needs its own launcher.
What the phone did
I built one: an app drawer, drag-to-arrange, a widget picker, a gesture layer, about 2,000 lines. Then I spent a day absorbing requests that were all for things the stock launcher already did, better.
What stayed
Stock launcher, Nia as widgets. Nothing unique about Nia ever needed the home screen. It became the ladder below.

Started means playing

Assumed
If Android says the voice started, Nia is talking.
What the phone did
The system logged “started” and played 8 ms of a phrase. Waiting for the audio to drain before letting go: 1,438 ms, the whole thing.
What stayed
A log line proves something was created, not that anyone heard it.

A quiet recording is a quiet room

Assumed
If the microphone hands back nothing, nothing was said.
What the phone did
When the app is not on screen, Android does not refuse the microphone. It hands over digital silence, with no error. The talk button worked exactly once, and every press after it looked like I had said nothing.
What stayed
Silence is now checked, not assumed: a recording of exact zeros is a failure, and says so.

Vibration is vibration

Assumed
Tag Nia's vibration correctly, as a notification.
What the phone did
The correct-looking tag is exactly the one Do Not Disturb silences. The plain, untagged call gets through.
What stayed
This is what makes “vibrate means urgent” possible. The line that looks like a mistake carries a comment saying why it stays.

Let the model decide

Assumed
A small local model can read a request and choose the action.
What the phone did
Asked for actions, it turned “what is the capital of Peru” into a three-minute timer. Asked only to rephrase, it got five of seven right, and a wrong rephrasing can only fail to parse.
What stayed
The parser decides; the model only rewrites. A made-up action cannot run.

Faster is better

Assumed
Keeping a helper process warm saves 33 seconds a call. Free win.
What the phone did
Nobody measured it waiting. It used more than a full processor core around the clock, and 81% of a day's battery.
What stayed
Measure what a thing costs while nothing is happening. It now stops after ten idle minutes.

A bigger model fixes it

Assumed
A smarter model will understand more of what I say.
What the phone did
Side by side on the phone, the bigger model got about 9 of 16 hard sentences against 5, at twice the time. Both made up commands Nia does not have. Every wrong answer was perfectly formatted.
What stayed
Give the model Nia's language and a grammar, so it cannot write a word outside Nia's commands.

Overheard is addressed

Assumed
Anything heard after a wake was meant for Nia.
What the phone did
Two false wakes in a minute. Room talk became a note, and was kept.
What stayed
A model's note now needs my words asking for one. Talk about someone else is let go, and nothing is said, done or kept.

Nia's language

Everything Nia can do has one written form, a short slash command. Whatever I say is read into these, one or several, and shown back as “what Nia understood”, so I can check it.

A language model may only speak this language. Its answer is held to a grammar, so it cannot write a command Nia does not have, and every word in it must be one I actually said. Then the parser reads it, as if I had typed it.

A made-up action cannot run. It can only fail to parse.

What I say · what Nia understood

set a timer for twelve minutes for the rice/timer 12m rice
the timer I just set, add five minutes/timer +5m rice
wake me at 7:30 on weekdays/alarm 7:30 weekdays
what's the weather tomorrow in Toronto/weather tomorrow in “Toronto”
remind me to call the dentist tomorrow at 10/remind “Call the dentist” 2026-10-04 10:00
every weekday at 7 play the radio/auto every weekdays 7:00 do “play 2004 FM”

The ladder

Before building anything: what is the simplest thing that could work, and is it enough? Climb only when the rung below is shown to fail.

The launcher was rung four, built when rungs one and two were enough. It was reverted to stock plus widgets, which is where it should have started.

  1. 1
    A stock settingAndroid or Motorola already does it.
  2. 2
    A widgetThe stock home screen hosts it; Nia supplies what is in it.
  3. 3
    A small app surfaceA screen you open on purpose.
  4. 4
    Custom codeOnly when the three above are shown to fail.

Rules that came out of it

These are product decisions, not preferences. Each one was argued once and is not argued again by accident. Some are enforced in code, so breaking one breaks the build.

  1. Vibration means urgent.Exactly one place can make the phone buzz from arriving messages, and only for the most urgent tier. Anything more and the buzz stops meaning anything within a month.
  2. Never show a backlog count.No “12 unread”, no badges. A number creates pressure to clear it, which is the habit this phone exists to remove.
  3. Green means live, exclusively.On a normal morning no surface has any green, and that absence is why it works.
  4. The parser decides; the model only rewrites.Nothing a model says reaches an action without passing the parser.
  5. Nia does not overstate.Nia may say a message arrived, but not that someone is waiting on a reply, because there is no way to know that.
  6. Nia reports, and does not encourage.No “You've got this.” Calm and dry.

Verify by looking

When designing and iterating, we wanted to be sure we were looking at what was actually live, not just supposedly live. A change counts once it is seen working on the phone.

Screenshot it. Read the stored value back. Check the log.

Next project

Mohawk College