AI Commander 2026
August 9, 2026 · View on GitHub
A gag voice assistant for the Ubuntu desktop.
It listens to you — genuinely, with real speech recognition. It answers out loud in a confident synthetic voice. It fills the screen with a retro-futurist console that scrolls status lines, draws progress bars and chirps at you.

It does not do anything.
That is the entire joke. You say "Claude, fix the home internet", the room hears
"ACKNOWLEDGED. RUNNING NETWORK DIAGNOSTIC SWEEP.", the console probes a gateway,
resolves DNS, stalls a progress bar at 68% and chirps its way to
UPSTREAM LINK RECALIBRATED — and nothing whatsoever happens. Played at full volume
in front of someone who has never seen it, it reads as an alarmingly advanced piece
of kit.
You talk to it by holding R — no wake word, because the key already said you
were talking to it. --always-on brings back the original, which answers to
"Claude".
Why it's funny
Seamless voice-to-action on the Linux desktop is still, in practice, not a solved problem. Films have depicted it as solved since 1968. AI Commander 2026 closes the gap by implementing the half that Hollywood actually shows: the acknowledgement.
What is real and what is not
| Layer | Real? |
|---|---|
Microphone capture, push-to-talk on R | Real |
| Speech recognition (transcript of what you said) | Real |
| Intent classification — deciding which theatrical response fits | Real |
| The city on the map at boot | Real — an IP lookup, and usually right |
| Spoken response, beeps, console readout, progress bars | Real, and entirely cosmetic |
| Any effect on your computer | None. By design. |
There is no execution path in this codebase. Not a disabled one, not a
--dry-run flag — the module that would run a command does not exist, and the
intent router maps a transcript straight to a performance script. Nothing can be
misconfigured into actually launching Chrome.
There is exactly one shell-out in the package, and it is the voice: espeak-ng,
invoked with a fixed argument list, with the text to speak written to its stdin so
it can never be read as arguments. The only module that writes a file is the
first-run setup wizard, which saves the settings and key it just asked you for and
which nothing in the running console can reach. A test walks the syntax tree of
every module and fails on anything else, with both allowances named explicitly so
they cannot quietly grow.
Three things do leave the machine, all obvious but worth stating: what you said
goes to your chosen speech-recognition provider while the talk key is down; with
the default voice, the scripted lines it speaks go to Microsoft's TTS endpoint;
and at boot it asks a keyless geolocation service where its own IP address is.
--voice espeak-ng, a local faster-whisper model and [geo] enabled = false
make the whole thing offline.
The look
Retro, and in a terminal — because a wall of scrolling monospace reads as "high-tech" to a bystander in a way that a window with buttons never will. The target is the Hollywood command centre, roughly 1979–1995: WarGames, MU-TH-UR from Alien, sonar consoles, NORAD big-boards.
- Full-screen console, neon phosphor green on near-black (amber and war-room alternates)
- Box-drawing borders, blocky uppercase headers, monospace everything
- Character-by-character typewriter output with a blinking block cursor
- Neon loading bars that stall convincingly at 68% before finishing
- Subsystem lights that flick between
OK/WORK/WARN - Telemetry that never stops moving, including at idle — buffer levels, link latency, a core temperature that means nothing
- A biometric scan at boot: a beam of light crosses the screen, a wireframe face
resolves behind it, and it lands on
MATCH — <YOUR NAME> CONFIDENCE 99.4% - A world map at boot with a blinking marker on your actual city, under
TRIANGULATING UPLINK … LOCKED
Sound does at least half the work. Beeps, sweeps and data-stutter are synthesised procedurally rather than sampled, so no two are identical, and the machine occasionally narrates itself unprompted into the silence.
The voice is a deep, slow neural one (edge-tts, en-GB-RyanNeural), because a
bystander has to actually parse what the machine claims to be doing — the
specificity of "PACKET LOSS WITHIN TOLERANCE" is most of the joke. espeak-ng is
there for anyone who wants the 1983 formant-synth version, and takes over
automatically when the network is not available.
Install
From a .deb
scripts/build-deb.sh
sudo dpkg -i dist/ai-commander-2026_*.deb
ai-commander --check
Self-contained: a bundled virtualenv under /opt, a launcher in /usr/bin, and a
menu entry. Build notes and the interpreter-version constraint are in
docs/packaging.md.
From source
Needs Python 3.11+ and uv.
sudo apt install espeak-ng # the fallback voice
uv venv .venv
source .venv/bin/activate
uv pip install -e .
Speech recognition runs through a provider interface, so pick one — or none, and type at it instead:
uv pip install -e '.[openrouter]' # OPENROUTER_API_KEY — recommended, any audio model
uv pip install -e '.[gemini]' # GEMINI_API_KEY or GOOGLE_API_KEY
uv pip install -e '.[openai]' # OPENAI_API_KEY
uv pip install -e '.[local]' # faster-whisper — no key, no network, slower first run
OpenRouter is the default because one key reaches every audio-capable model,
Gemini's included, so changing provider is changing a model string. Note that its
provisioning keys look identical to inference keys and fail with 401 User not found, which reads like a dead key rather than the wrong kind — curl -H "Authorization: Bearer $KEY" https://openrouter.ai/api/v1/key tells you which one
you are holding.
Then let it ask you for the key:
ai-commander --setup
It writes your choice to ~/.config/ai-commander/config.toml and the key to
~/.config/ai-commander/credentials, which is loaded into the environment at
startup — an exported variable always wins, so nothing changes if you would
rather keep the key in your shell profile. (If a stale export is shadowing a key
you just saved, --check says so under key source.) The first plain
ai-commander on a machine with nothing configured runs the same wizard, and
ctrl+k reopens the same questions inside the running console, applied
without a restart. --asr auto (the default) takes the first provider that has
what it needs.
Check what you have:
ai-commander --check
Run
ai-commander # full-screen console, push-to-talk armed
ai-commander --demo # perform every script in turn — start here
ai-commander --always-on # listen continuously for the wake word instead
ai-commander --no-mic # typed input only
ai-commander --theme amber # phosphor (default), amber, warroom
ai-commander --script network.reset # perform one script, then exit
The voice:
ai-commander --voice espeak-ng # offline, and the original aesthetic
ai-commander --comms-filter # neural voice, band-limited to a console speaker
ai-commander --no-voice # beeps only
Run it maximised, on a large font, ideally on an external display. The gag scales with screen area.
Hold R and say "fix the home internet." Let go and it answers — releasing
the key is the send, there is no confirm step.
Tapping space works too — tap to start, tap to stop — because a terminal cannot tell the program that a key came back up, so a hold is inferred from the keyboard's auto-repeat and both idioms end up meaning the same thing. No wake word is needed: pressing the key already said you were talking to it. Nothing is recorded, and nothing is sent anywhere, unless the key is down.
--always-on restores the original behaviour instead: the console listens
continuously and answers to "Claude, fix the home internet."
| Key | Does |
|---|---|
r | Hold to record a message — or tap to start, tap to stop |
tab | Focus the typing box (which takes r with it, so you can type it) |
escape | Leave the box, giving the talk key back to the mic |
ctrl+k | Settings — provider, key, model, mic mode. Applied live |
ctrl+t | Cycle theme |
ctrl+g | Mute / unmute the microphone |
ctrl+r | Perform a random script |
ctrl+s | Abort the current performance |
ctrl+c | Quit |
Making it say new things
Responses are TOML, not Python. A new gag is a [[script]] block with a list of
keywords and a list of theatrical steps — beeps, spoken lines, log lines with
results, subsystem lamps, and progress bars that stall.
[[script]]
id = "network.diagnose"
match = ["internet", "wifi", "packet loss"]
steps = [
{ sfx = "ack" },
{ say = "ACKNOWLEDGED. RUNNING NETWORK DIAGNOSTIC SWEEP." },
{ log = "PROBING GATEWAY", result = "OK", dots = true, delay = [0.4, 1.2] },
{ progress = "RECALIBRATING UPSTREAM", duration = [6, 11], stall_at = 0.68 },
{ sfx = "confirm" },
]
Full reference, including why every delay is a range and not a number:
docs/performance-scripts.md.
Configuration
--setup writes the few settings it asks about. For anything else, copy
ai_commander/data/config.toml to ~/.config/ai-commander/config.toml and change
only the lines you care about — your file is layered over the defaults key by key.
Worth knowing:
| Setting | Does |
|---|---|
[mic] mode | push_to_talk (default) or always_on |
[mic] ptt_key | The talk key. r by default; space, f, ctrl+space all work |
[mic] ptt_release_ms | Raise it if a held key keeps cutting itself off |
[asr] provider | auto, gemini, openrouter, openai, local, none |
[geo] enabled | false to boot without the map, and without the lookup |
[biometric] identity | The name the face scan matches. Blank = your account name |
[biometric] enabled | false to skip the scan and boot faster |
Status
Working. Boots, locates itself, listens, transcribes, classifies, performs. Real telemetry on the rail, procedural audio, seven domains of scripted response.
Packaged and tested as a .deb on Ubuntu / Python 3.14.
docs/design.md— architecture, aesthetic reference points, and the decisions taken while building itdocs/performance-scripts.md— writing new gagsdocs/packaging.md— building and testing the.deb
The silero VAD path is present but only lightly exercised, and it now matters
less: it only runs in --always-on.
Licence
MIT.