Skip to content
Console

What Can My Hub Be Asked?

A connected client can ask its hub what it can be asked. The hub answers with every intent its skills registered, per language, and the sentences a person says to reach each one.

The answer travels over the client’s own session. No API token, sign-in, or workspace role is involved. A voice client, a kiosk, an installer, or an agent can show a person what to say, or confirm that a new skill answers, with nothing more than its connection.

  • you want to show people what a hub understands, in their language;
  • you installed a skill and want to confirm the hub answers to its intents;
  • an SDK call raised a policy error naming ovos.intent.list or ovos.intent.describe;
  • an intent list came back with names but no sentences;
  • listing the intents failed with an error the hub sent back;
  • a language you expected is missing from the list.
Question Simple answer
What is an intent? One thing a skill can do, such as current.weather.
What does the hub return? Every intent, grouped by skill, with the sentences that reach it, per language.
Who can ask? Any connected client whose connection may publish ovos.intent.list, and ovos.intent.describe when it has to ask for the sentences separately.
What does it cost in credentials? Nothing beyond the connection itself.
What does a refusal look like? A policy error naming the refused message type, at once, not a timeout.
Where do I fix a refusal? The connection’s message types in the dashboard.

The inventory groups intents by skill. Each intent carries:

Field Meaning
skill_id The skill that registered the intent, such as thalovant-skill-weather.thalovant.
name The intent name, such as current.weather. The full id is skill_id:name.
engine How the hub matches it. padatious matches whole sentences; adapt matches keyword sets.
enabled Whether the hub answers to it right now.
phrases The sentences that reach it, keyed by language.

Sentences appear as the skill wrote them. A word in braces is a slot the person fills in: what is the weather in {location} matches “what is the weather in Montréal”. Keyword intents carry keyword sets rather than sentences, so they list without phrases.

A weather skill that speaks English and French looks like this in the JSON form the SDKs and the thalovant intents --json command print:

{
"languages": ["en-us", "fr-fr"],
"source": "intent-manifest",
"denied": [],
"skills": [
{
"skill_id": "thalovant-skill-weather.thalovant",
"languages": ["en-us", "fr-fr"],
"intents": [
{
"id": "thalovant-skill-weather.thalovant:current.weather",
"skill_id": "thalovant-skill-weather.thalovant",
"name": "current.weather",
"engine": "padatious",
"enabled": true,
"phrases": {
"en-us": ["what is the weather", "what is the weather in {location}", "how is it outside"],
"fr-fr": ["quel temps fait-il", "quelle est la météo à {location}", "quelle est la météo"]
}
}
]
}
]
}

source says how the inventory was read. intent-manifest carries sentences per language. engine-manifests is the names-only fallback described below, and denied then names the query the hub refused.

Ask for each language you want to show. Language tags compare without regard to case, and _ and - count as the same character: fr-fr, fr_FR, and fr-FR name one language. The hub answers with the tag it stores, so a request for fr-fr can come back labeled fr-FR.

A skill lists only in the languages it ships. A skill with English sentences and no French ones appears in the English list and has no French phrases. The hub registers only the languages its runtime loads. If a whole language is missing, check the primary and secondary languages in Runtime.

The hub answers two queries, and the connection needs only the ones its client sends:

Message type What it does When the client sends it
ovos.intent.list Lists every registered intent for one language. Always.
ovos.intent.describe Returns one intent’s registration, including its sentences. Only when the client has to ask for the sentences separately.

A client that only wants to know which intents a hub registered needs ovos.intent.list alone: it gets the names, engines, and enabled state, and no sentences. Every SDK asks for the sentences unless you turn that off, and in Python the switch is client.intents(["en-us"], describe=False).

Asking for the sentences does not always mean sending ovos.intent.describe. The SDKs ask the hub to attach each intent’s definition to the listing itself, with include_definitions. A hub whose runtime honors that answers the listing with the sentences already in it, no describe is ever sent, and the connection never needs that second type. The SDK falls back to describing intent by intent only when the listing came back without definitions, and that is when the connection needs ovos.intent.describe too.

Which of the two happens depends on the runtime, and today no shipping runtime attaches them: OpenVoiceOS keeps its listing free of definitions by design, and Thalovant hubs run a runtime built from those same sources. A runtime that does not recognize include_definitions ignores it and answers the plain listing, and the SDK then describes intent by intent. So in practice the connection needs both types. Allow both unless you have measured otherwise; that is what Thalovant’s own connections do.

Both are read-only. They reveal only intents the connection can already trigger, so allowing them adds no privilege. Connections that Thalovant creates for SDK clients and Thalovant Voice include both by default.

To check or change them, open Connections in the dashboard, select the connection, and open its access settings. The list of message types the connection may publish (allowedTypes in the client spec) must contain each type the client sends. Add them when a connection was created before this feature shipped, or when its access was narrowed by hand, then reconnect the client.

A connection that may not publish one of the types gets no reply. Instead the hub answers hive.policy.denied at once, naming the message type and the types the connection may publish:

{
"denied_type": "ovos.intent.list",
"code": "acl_disallowed_type",
"reason": "ovos.intent.list not in allowed_types",
"data": {
"msg_type": "ovos.intent.list",
"allowed": ["recognizer_loop:utterance", "speak"]
}
}

The SDKs turn that answer into a typed policy error the moment it arrives, rather than waiting for a timeout. The error names the refused type and carries code, reason, and the allowed list. In Python it is ThalovantPolicyDeniedError, and its message tells you where to fix it:

The hub refused 'ovos.intent.list': ovos.intent.list not in allowed_types.
Allow this connection to publish 'ovos.intent.list' in the dashboard's connection settings.

A refusal is not the only unhappy answer. The hub can also answer a query it accepted with ok: false and an error of its own, and the two queries do not mean the same thing by it.

When ovos.intent.list answers with an error, the listing failed. The hub has not said what it registered, so the SDKs raise their runtime error carrying the hub’s error text. A listing that failed is not an empty hub, and reporting it as no intents would show a person a device that can do nothing. In Python it reads:

ovos.intent.list failed: intent manifest unavailable

Ask again once the hub is healthy. If it keeps failing, check the hub’s live state and its runtime on Hubs.

When ovos.intent.describe answers with an error, that is a normal, empty answer: the hub does not know that registration. The intent stays in the inventory with its name, engine, and enabled state, and has no sentences. Nothing is raised, and the rest of the inventory is unaffected.

When the hub refuses ovos.intent.list, the SDKs fall back by default to two older queries, intent.service.adapt.manifest.get and intent.service.padatious.manifest.get. These return intent names only, in the form skill_id:intent_name, with no language and no sentences.

A names-only result says so. source is engine-manifests, denied lists ovos.intent.list, and no intent carries phrases. It is enough to confirm that a skill registered; it is not enough to show people what to say. When the fallback queries are refused as well, the policy error is raised.

Turn the fallback off when your client should fail rather than degrade. In Python that is client.intents(fallback=False).

Voice clients and kiosks

Show a “what can I say” screen in the person’s language, built from the hub rather than typed by hand.

Installers

Confirm that a newly installed skill answers, in every language the runtime loads, before handing the hub over.

Agents

Let an agent read what the hub can do before it chooses a phrase, instead of guessing.

The Python SDK 0.4.36 and newer reads the inventory with client.intents([...]), and the thalovant intents command prints it:

Terminal window
thalovant --identity _identity.json intents --lang en-us --lang fr-fr

See List What the Hub Can Be Asked in the Python SDK guide. The Node.js, Go, Rust, Kotlin, Swift, and .NET SDKs have the same three calls under their own spelling, and the embedded C library builds and reads the two frames. Each SDK page names them and gives a working example.

Symptom Check first
A policy error names ovos.intent.list or ovos.intent.describe Add that message type to the connection’s message types in the dashboard, then reconnect the client.
Names but no sentences, and source is engine-manifests The connection may publish only the fallback queries. Add ovos.intent.list, and ovos.intent.describe when the hub does not attach the sentences to the listing.
Listing failed with an error from the hub The hub could not read its intent manifest. It is not an empty hub. Check its live state on Hubs, then ask again.
One intent has no sentences It is a keyword intent, the hub does not know that registration, or its description did not arrive in time. Raise the timeout or describe that intent on its own.
A whole language is missing The runtime does not load that language. Check Runtime.
A skill is missing Check its install state and live status on Skills.
The call times out with no policy error The client is not connected. Check its live state on Clients and Connections.

The inventory is ready to show people when:

  • every installed skill appears under the skill_id you expect;
  • each intent has sentences in every language the runtime loads;
  • source is intent-manifest and denied is empty;
  • the example sentences read like something a person would say.
Read it with the Python SDK Review permissions