Vesper

Your Mac. Your data. Your assistant.

A local-first macOS assistant that routes natural language to Notes, Reminders, Mail, Calendar and Contacts, on a local LLM. No cloud, no accounts, no telemetry.

Year
2026
Surfaces
CLI + menubar app
Language
Python · Swift
Model runtime
Ollama · MLX
Interfaces
Typer · FastAPI
My role
Solo, design and build
Stack
Python · Swift · Ollama · MLX

vesper (n.): the evening star.

When Gemma 4 came out, it felt like LLMs could finally run on your own computer and still do a decent job. Around the same time Apple kept pushing back the smarter Siri it had promised with Apple Intelligence, again and again, so I figured I’d try building a Siri replacement on a local model. Vesper is built on that premise: it reads your mail, notes and calendar, so it should work offline. These are things we write for ourselves. If we wouldn’t show our notes to another person, we shouldn’t send them to a cloud model either (and yet plenty of people talk to ChatGPT about their love lives?).

Here are the problems I ran into while building it.

One model can’t be both fast and right

I tested two local models with English and Chinese prompts:

Model Size Routing accuracy Avg latency
qwen3:8b 5.2 GB 95% (37 / 39) 9,990 ms
llama3.2:3b 2.0 GB 79% (31 / 39) 613 ms

Ten seconds is too slow for a menubar tool, but the 3B model’s mistakes were the dangerous kind: wrong tool, lost reminder text, garbled Chinese titles. They weren’t random though. Five of the seven failures I traced came from Chinese prompts or long note bodies, so instead of picking one model I split along that line:

  1. Deterministic fast paths: regex rules for the most common commands (“remind me to … tomorrow at 9”, “show me my recent notes”, “take a note: …”), in English and Chinese, with no LLM call at all. One of the 3B model’s short-English misses is now handled at this layer too.
  2. Small model: short English prompts (80 characters or fewer) go to the 3B model.
  3. Reliable model: anything with Chinese, or longer than that, goes to the 8B model, which is exactly where the 3B model broke.

Every rule is checked against a 48-case English/Chinese eval set that measures fast-path hit rate, LLM calls per prompt and latency by language. Each turn also writes a redacted trace (tool, confidence, latency, never the content of a note or email), so a misroute can be debugged without putting private data in a log.

AppleScript is the real bottleneck

With the model sorted, the slowest part was talking to the Mac’s own apps. Adding one reminder took 27 seconds. I timed each property read after the write to find out where it went:

Read after make new reminder Time
id 4 s
name 2 s
remind me date 17 s
creation date 16 s

Reminders.app blocks while it syncs a new item to iCloud, and Vesper was reading back values it had just written. Now it reads only the id and rebuilds the rest from its own input: 27 s → 5.6 s from the CLI.

That finding shaped the other tools too:

Mail is cache-first: queries hit a local SQLite FTS5 index, and a background sync runs only when the question is about recent mail and the cache is older than that window. Calendar gives each calendar its own timeout, and a slow one is skipped and mentioned in the reply. Reminders lists are read with one batched script per list, which holds up with 100+ items.

In the end Vesper never became something I use every day. I’m not much of a planner: I barely use Notes, I don’t look at my calendar, and my inbox is ads and USC newsletters. A month later, after WWDC, the Siri beta got a bit better, and Vesper turned out to be like the evening star it’s named after: the first to show up at dusk, and nobody cared, lol.

A singer at a microphone, a slanting orange stage light across the face
VesperCover: N°01, Procreate
A guitarist in an LA cap looking down at the guitar neck, under blue light
VesperCover: N°02, Procreate
A single red rose in slanted window light, a blurred leaf shadow on the wall
VesperCover: N°03, Procreate
Three sunflowers on a black ground covered in loose grey scribbles
VesperCover: N°04, Procreate
A charcoal drawing of a hand holding a rose and baby’s breath
VesperCover: N°05, Charcoal
A black-and-white calla lily wrapped in loose looping lines, with pixelated blocks
VesperCover: N°06, Procreate
A black-and-white sketch of a curly-haired guitarist leaning into a solo
VesperCover: N°07, Procreate
A dark grey rose emerging from a brushed charcoal background
VesperCover: N°08, Procreate
A candle melting in an open hand, lit against the dark
VesperCover: N°09, Procreate
A sun sinking into dark water, painted with glitchy horizontal brush streaks
VesperCover: N°10, Procreate
$ vesper ask "remind me to call dentist tomorrow at 9am"
→ reminder.add
Got it — I'll remind you on Tue Sep 29, 9:00 AM to your Reminders list.

$ vesper ask "any emails I need to reply to?"
→ email.list
Found 2 emails flagged for reply.

About

I’m an engineer with a background in data analytics and systems engineering. I like building things close to the data: recommendation systems, local-first assistants, analysis pipelines, and interfaces that make a model’s output easier to read.

When I’m not coding, I paint, mostly in Procreate and sometimes in charcoal. This site keeps both in one place.