Quickstart
From zero to speaking commands at your Mac.
Everything below starts from nothing on a Mac. You need uv and Homebrew. Total setup: about ten minutes, most of it downloads.
1. Get axstream
uv tool install axstream # or: pip install axstreamOr, for hacking on it (the demos below assume the clone):
git clone https://github.com/milind-soni/axstream
cd axstream
uv sync2. See the core trick — 10 seconds, no keys, no setup
uv run python demo_dry.pyThis replays a canned LLM response at realistic decode speed into the real compiler and executor against a mock computer. Watch the timeline: actions execute while the model is still generating, and the summary shows ~37% wall-clock saved vs waiting for the full response. That's the streaming thesis in one command.
3. Install the two local pieces
The matcher — download the fine-tuned model
brew install llama.cpp
mkdir -p ~/models && curl -L -o ~/models/lfm25-350m-axstream-Q4_K_M.gguf \
"https://huggingface.co/milsoni201/lfm25-350m-axstream-matcher/resolve/main/lfm25-350m-axstream-Q4_K_M.gguf"That's axstream-matcher
(219MB) — a 350M model fine-tuned for exactly one job: which known command is
this, and what are the variable words, in ~100ms on Apple Silicon. It scores
94% end-to-end where the stock base model scores 47%. You don't need to
start it manually — axstream up does that for you.
The executor: cua-driver
Delivers keys and clicks to apps in the background — no focus stealing, your mouse stays yours.
/bin/bash -c "$(curl -fsSL https://cua.ai/driver/install.sh)"Grant Accessibility permission when it asks — that's what lets it press keys on your behalf.
4. Start it and try things
uv run axstream upup checks everything (starts the matcher if it's down, wakes the driver),
seeds a starter library of ~180 macOS commands on first run (axstream seed),
and listens. Try typing:
» open my downloads folder
⚡ instant [finder_go_downloads] done · match 75ms · no LLM
» take a screenshot
⚡ instant [screenshot_full] done · match 68ms · no LLM
» quit this app
(refused — risky commands are gated until you allow them)⚡ instant means a known command replayed with no LLM anywhere — that's the tier that makes axstream feel different.
5. Teach it something new
Add a fast-LLM key (either provider) to .env in the repo root:
echo 'OPENROUTER_API_KEY=sk-or-...' >> .env # or GROQ_API_KEY=gsk_...Restart axstream up, then say something it doesn't know:
» create a new tab in firefox
🐢 fast — the LLM watches the screen, does it, and learns it
» create a new tab in firefox
⚡ instant [new_firefox_tab] done · match 101ms · no LLMThat's the flywheel: every command is slow at most once. Learned macros
live in ~/.axstream/macros.json — plain JSON, yours to inspect or edit.
6. Hook up your coding agent
If you use Claude Code or Codex, one command gives the agent the skill + MCP tools (fast screen reading, batched verified actions, the macro flywheel):
uv run axstream installFull story: For coding agents. OCR (text-anchor clicks, outcome asserts) is included by default.
7. Speak to your Mac — the menu bar app
The flagship surface is AxstreamBar, a native Swift menu bar app: hold ⌃⌥, speak, release — the action runs in well under a second of thinking, with a HUD at the bottom of the screen narrating every step.
cd swift/AxstreamBar && swift build -c release && cd ../..
mkdir -p ~/.axstream/models
curl -L -o ~/.axstream/models/ggml-large-v3-turbo-q5_0.bin \
"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo-q5_0.bin"
axstream menu(The Swift build links whisper.cpp statically — see The voice menu bar for the one-time whisper.cpp build and the full story.) Grant Microphone and Accessibility to AxstreamBar when asked. Then:
hold ⌃⌥ … "add a torus in blender" … release
🎤 → "add a torus in blender" → ▶ blender-add-mesh · torus → ✓ 4.8s
hold ⌃⌥ … "open blender and select the shape and delete the shape" … release
▶ 1/3 open-app → ▶ 2/3 blender-select-all → ▶ 3/3 blender-delete-selected → ✓The dropdown lists your recent workflows with trust marks (✓ verified, ○
draft) — a just-recorded macro tops the list. Unknown commands fall through
to the engine, which constructs them with an LLM and saves the result as a
macro with its variables identified — slow at most once, spoken-instant
forever after.
Troubleshooting
uv run axstream --doctor # checks matcher, driver, macro store — with fixes
uv run pytest tests # the suite