intents alongside tools in voiceos.integration.json to make
common voice and typed commands eligible for faster selection. An intent maps a
clear request, such as “Show Hacker News”, to one of your existing MCP tools
and the arguments it needs. You keep the same handler, confirmation, and result
card.
VoiceOS starts its normal agent and a dedicated intent selector in parallel.
If the selector finds a valid action before the agent commits to an answer or
action, VoiceOS runs that tool through the usual hooks and confirmation policy.
If selection is uncertain, invalid, or too slow, the normal agent continues.
Fast intents require a supporting VoiceOS desktop and an enabled server
rollout. Declaring an intent makes it eligible; it does not guarantee that
every request takes the fast path or finishes within a particular time.
Keep
schemaVersion: 1 and continue declaring ordinary tools.Add your first intent
The Defining tools example already declares atop_stories tool with an optional numeric count. Add this top-level field to
that integration’s manifest, keeping its existing tools array:
name identifies the intent within your app. tool is the original name in
your manifest and MCP server, without a VoiceOS namespace. fixedArgs supplies
values the selector cannot change. utterances gives localized examples;
response supplies a short localized acknowledgement. VoiceOS displays the
acknowledgement after successful execution and renders your usual result card.
Reload the installed integration after changing its manifest. You do not need
to register a second MCP tool for the intent.
Extract arguments with slots
A slot names a property in the tool’sinputSchema. Use string for free text,
number for a numeric argument, or enum for a limited set of strings. For
example, this alternative intent lets the user specify the story count:
minimum: 1 and maximum: 8 in the tool’s input
schema. VoiceOS validates extracted arguments against that schema. Every required
tool input must come from either fixedArgs or a slot with required: true.
Every utterance must include each required slot as a single-brace placeholder,
such as {count}. Confirmation views still use double braces, such as
{{count}}.
For a tool with a string input named bot, a static choice list looks like this:
minConfidence field does not affect selection.
Keep choices current
For recipients, devices, or other names that change, declare an enum withvaluesFrom: "tool" instead of static values:
tools/list metadata. Here,
registeredTool is the handle returned by your existing
server.registerTool(...) call:
voiceos/intent-slot-values. Each slot’s list must contain
1–30 nonempty strings of at most 200 characters. Publish at connection and when
your app’s data changes. MCP’s registeredTool.update() emits
notifications/tools/list_changed, so VoiceOS can refresh its cached choices.
If metadata for a slot is absent, VoiceOS can use a string enum from that
property in the live tool input schema. Missing, empty, invalid, or oversized
choices make the entire intent ineligible; they do not turn it into free text.
When both the intent choices and the tool schema restrict values, only their
intersection is allowed. A changed choice list invalidates pending proposals.
VoiceOS also sends the optional
notifications/voiceos/refresh_intent_values notification when Agent recording
is triggered. The SDK exports this as INTENT_REFRESH_NOTIFICATION_METHOD.
If you handle it, start a read-only background refresh; recording and the
normal agent do not wait for a reply. Recheck the selected entity in your tool
handler before acting, because cached choices can become stale.
Choice names are sent to the selector provider. Do not put credentials or
secrets in them. Intent restrictions also apply to edited confirmation
arguments; your ordinary tool schema can remain broader for normal agent or UI
calls.
When the normal agent continues
Fast intents work best for a short request with one clear action and all its required inputs. Current selection is limited to 300 characters and has a 600 ms selection budget. That budget excludes speech recognition, tool execution, and time spent waiting for user confirmation. The selector can use up to two recent user messages to resolve clear context. It is instructed to abstain for negation, hypothetical or how-to questions, separate actions in one request, ambiguous targets, or missing inputs. Requests with attachments, selected text, explicit screenshots, pending confirmations, or transcript-hook rewrites/context use the normal pipeline. Background tools are excluded from the intent catalog. Only one path wins the turn. Normal tool availability, schema validation, pre/post hooks, and the user’s confirmation settings still apply. A failed intent action can return control to the normal agent with the failure context and a replay guard. Cancellation or declined confirmation does not trigger that recovery. Report failures honestly through MCP errors orisError: true;
never return a success result for an action that failed.
Help speech recognition with app vocabulary
If your app uses unusual names, add optional recognition hints alongsidetools and intents:

