Skip to main content
The developer path — everything the no-code quickstart does, built by hand. You’ll build Coffee Tracker: say “log a flat white” and VoiceOS records it after a confirmation card; ask “how’s my coffee habit?” and the notch shows a stats card with a weekly chart. Two tools, native UI, no VoiceOS internals. Prerequisite: bun. That’s all.
1

Scaffold a folder

During the developer preview the SDK ships inside the VoiceOS repository. If the package isn’t available to you yet, run bun voiceos-integration-sdk/src/cli.ts init "Coffee Tracker" from a checkout.
You get a complete, standalone folder:
Standalone means it imports nothing from the SDK — the one glance helper it needs is inlined. It runs anywhere with bun, and an AI coding agent pointed at the folder learns the entire contract from AGENTS.md.
Three templates: confirm-and-send (default — an acting tool with a confirmation card), fetch-and-show-list (a read-only lookup), and background-task (long-running work). Pick with --template.
2

Declare the tools

Replace the tools array in voiceos.integration.json with two tools — one that acts (and so declares a confirmation), one that only reads (and so must not):
voiceos.integration.json
Two things to notice:
  • Descriptions are routing rules. The agent reads them to decide when to call your tool — say what it does and when to use it.
  • The confirmation is data, not code. It renders before your server runs. {{drink}} binds the text field to the tool argument; whatever the user edits it to is what your handler receives.
A 'Log coffee' confirmation card in the notch with an editable Drink field containing 'flat white' and Cancel / Log it buttons.

The confirmation card you just declared — the Drink field is live, bound to the drink argument.

3

Implement the handlers

Replace server.ts. It’s a standard MCP stdio server; the only VoiceOS-specific part is spreading glanceResult([...]) into the JSON result — that’s your card in the notch.
server.ts
Every result carries data for the model (logged, todayCount, …) and a card for the user. Never put information only in the card — the model narrates from the JSON.
Those two glanceResult calls are these two cards:
A Coffee Tracker card in the notch with a coffee-cup icon, a 'Logged' trailing label, and two key-value rows: Drink 'flat white' and Today '3 coffees'.

log_coffee — header block + keyValue block.

A Coffee Tracker stats card in the notch showing 12 this week, 87 all time, and a labeled bar chart Monday through Sunday.

coffee_stats — header, two stat tiles, and a week of bars.

Finally, point the preview fixtures at the new tools so verify.ts can call them:
voiceos.integration.preview.json
4

Verify

verify.ts speaks real MCP over stdio to your server exactly the way VoiceOS does — handshake, tools/list, then a tools/call per preview fixture:
Run it after every change — it’s also the feedback loop AI coding agents use when you point them at the folder.
5

Install into VoiceOS

Settings → Agent Mode → Integrations → Install from folder, then pick coffee-tracker/.After later edits, hit the integration’s Reload — it re-reads the manifest and restarts your server. Tools update on the next turn.
6

Talk to it

  • “Log a flat white” → the Log coffee confirmation card appears. Edit the drink if you like, approve — the handler runs with the edited value, and the “Logged” card confirms it.
  • “How’s my coffee habit?” → the stats card renders: header, two stat tiles, and a bar chart of your week.
That’s the whole loop: manifest → tools → confirmation → glance.

Make a common command faster

Add this top-level field to Coffee Tracker’s manifest, alongside its existing tools array, to make the stats command eligible for fast intent selection:
Reload the integration and try one of the phrases. The existing coffee_stats handler still returns the same stats card. Intent selection runs alongside the normal agent, which continues if no intent wins. See Fast intents for slots, dynamic choices, availability, and testing.

Where next

Defining tools

Descriptions the agent routes on, input schemas, sync vs background execution, honest errors.

Result cards

The full glance vocabulary — lists, stats, charts, progress, badges.

Setup fields

Ask for API keys and options; VoiceOS injects them as env vars.

Custom widgets

When blocks aren’t enough: sandboxed HTML with a strict message bridge.