OVOSSkill¶
In a nutshell
A "skill" is an add-on that teaches your voice assistant to do one new thing, like telling the weather or setting a timer. Every skill is built on top of a shared starter kit called OVOSSkill, which quietly handles the housekeeping: starting up, listening for commands, speaking replies, remembering settings, and shutting down. The reference below covers that starter kit and its methods. New to all this? Start with Skill Classes or the Glossary.
Module: ovos_workshop.skills.ovos.OVOSSkill
OVOSSkill is the base class that all OVOS skills inherit from. It handles startup, intent registration, resource loading, settings, event management, GUI, and shutdown.
Constructor, lifecycle, and startup/shutdown sequence
The constructor signature, the lifecycle methods to override (initialize(), stop(),
shutdown(), etc.), and the full startup/shutdown sequence are documented once, on
Skill Classes. The sections below cover OVOSSkill's remaining
surface: properties, speaking, user input, scheduling, SkillApi, and the bus events it
handles.
Key Properties¶
Session-aware (read from current Session)¶
| Property | Type | Description |
|---|---|---|
lang |
str |
BCP-47 language of the current request |
core_lang |
str |
Default configured language |
secondary_langs |
list |
Configured secondary languages |
native_langs |
list |
core_lang + secondary_langs |
location |
dict |
Location preferences |
location_pretty |
str |
City name |
location_timezone |
str |
Timezone code |
system_unit |
str |
"metric" or "imperial" |
date_format |
str |
"DMY", "MDY", or "YMD" |
time_format |
str |
"half" or "full" |
Infrastructure¶
| Property | Type | Description |
|---|---|---|
settings |
JsonStorage |
Persistent skill settings |
bus |
MessageBusClient |
messagebus connection |
gui |
SkillGUI |
GUI interface |
enclosure |
EnclosureAPI |
Mark 1 faceplate interface (⚠️ being removed from the base class like self.gui, moves to ovos-mark1-utils, faceplate becomes a GUI plugin) |
file_system |
FileSystemAccess |
Managed local file access |
resources |
SkillResources |
Resource files for self.lang |
dialog_renderer |
MustacheDialogRenderer |
Render dialog templates |
event_scheduler |
EventSchedulerInterface |
Schedule future bus events |
intent_service |
IntentServiceInterface |
Register/manage intents |
intent_layers |
IntentLayers |
Manage intent layer sets |
audio_service |
OCPInterface |
Control audio/OCP playback |
translator |
OVOSLangTranslation |
Language translation (lazy init) |
lang_detector |
OVOSLangDetection |
Language detection (lazy init) |
is_fully_initialized |
bool |
True after _startup completes |
reload_skill |
bool |
Set to False to prevent hot-reload |
Speaking¶
self.speak("Hello world")
self.speak_dialog("my.dialog.file") # uses locale/lang/dialog/my.dialog.file
self.speak_dialog("my.dialog", data={"name": "Alice"}) # Mustache templating
self.speak("Anything else?", expect_response=True) # speak, then listen for a reply
Both speak() and speak_dialog() accept expect_response=False. Set it to True and OVOS
re-opens the microphone as soon as the prompt finishes speaking, so the user's next utterance is
captured without a wake word. This is the basis of a follow-up question. (To capture and return that
reply inside your handler, use get_response instead. See Getting User Input
below and the Skill Cookbook.)
Playing audio files¶
play_audio(filename, instant=False, wait=False) queues (or, with instant=True,
immediately plays) an audio file through ovos-audio. filename must be a path to a real
file on disk or a URI. play_audio does not search skill resource directories for you,
so resolve the path yourself first, typically with self.find_resource(name, "snd") (looking
up <skill>/snd/<name> or a locale-specific variant). Pass wait=True to block until playback
finishes or a 30-second default timeout elapses, or wait=<seconds> for a custom timeout.
Getting User Input¶
get_response, ask_yesno, and ask_selection ask the user a question and capture the
reply. See Asking the User for Responses for the full reference, including
the validator, on_fail, and num_retries options.
Intent Registration¶
# Padatious (intent file)
self.register_intent_file("my.intent", self.handler)
# Adapt (vocab-based)
from ovos_workshop.intents import IntentBuilder
intent = IntentBuilder("MyIntent").require("Keyword").build()
self.register_intent(intent, self.handler)
# Vocabulary keywords
self.register_vocabulary("hello", "HelloKeyword")
self.register_entity_file("food.entity")
Context Management¶
Scheduling Events¶
Skills can ask the event_scheduler to call a handler at a future time,
once or repeatedly:
import datetime
# once, 60 seconds from now
self.schedule_event(self.handle_timeout, 60, name="my-timeout")
# once, at a specific point in time
self.schedule_event(self.handle_timeout, datetime.datetime.now() + datetime.timedelta(hours=1),
name="my-timeout")
# repeating every 30 minutes, starting 30 minutes from now
self.schedule_repeating_event(self.handle_tick, None, 60 * 30, name="my-tick")
# cancel a scheduled event by name
self.cancel_scheduled_event("my-tick")
schedule_event(handler, when, data=None, name=None, context=None): single-shot.whenis either adatetimeor a number of seconds from now. A naivedatetime(notzinfo) is stamped with the assistant's configured timezone (location.timezone.code), not the OS/process timezone. A device on the stock config is in Lawrence, Kansas until its location is set.schedule_repeating_event(handler, when, frequency, data=None, name=None, context=None): repeating.frequencyis the interval in seconds between calls.when=Nonefires the first callfrequencyseconds from now. Pass adatetime/number to control the first firing explicitly.- Both accept an optional
nameused to reference/cancel the event later withcancel_scheduled_event(name). Re-schedulingschedule_eventunder anamethat already has a pending one-shot replaces it, so a skill that re-creates its schedules on every load does not accumulate duplicates.schedule_repeating_eventdoes not replace an existing repeating schedule of the same name. Cancel it first.update_scheduled_eventchanges an existing event's payload without touching its fire time;get_scheduled_event_statusreturnsNone(not an exception) when nothing is scheduled under that name. A repeating schedule survives skill shutdown/restart. It is tied to the skill id, not the running process. - Scheduled events are persisted by the
EventSchedulerso they survive anovos-corerestart. They are not tied to the skill instance staying in memory. See Scheduled Events for the misfire policy and replay guarantees behind this.
Public Skill API¶
Decorate a method with @skill_api_method to expose it over the bus. Other skills or tools can call it via SkillApi. The full RPC mechanism — discovery, call protocol, the SkillApi proxy class, and a worked client/server example — is documented on Skill API: Inter-Skill RPC.
RuntimeRequirements¶
Note
RuntimeRequirements is a deprecated mechanism. See Runtime Requirements for what it does.
Override the class property to declare connectivity needs:
from ovos_utils import classproperty
from ovos_utils.process_utils import RuntimeRequirements
@classproperty
def runtime_requirements(self):
return RuntimeRequirements(
network_before_load=False,
internet_before_load=False,
gui_before_load=False,
requires_internet=False,
requires_network=False,
requires_gui=False,
no_internet_fallback=False,
no_network_fallback=False,
no_gui_fallback=True,
)
All nine fields default True except gui_before_load, requires_gui, and
no_internet_fallback/no_network_fallback (default False), and no_gui_fallback (default
True). This is used by SkillManager to defer loading until the required connectivity is
available.
System Bus Events Handled (per skill)¶
| Event | Description |
|---|---|
mycroft.stop |
Global stop broadcast, cease all activity for the inbound session |
{skill_id}.stop |
Skill-directed stop, cease the stoppable activity for the inbound session |
{skill_id}.stop.ping |
Check if the skill can stop. The base class answers with {skill_id}.stop.response carrying whether it can handle the stop |
{skill_id}.converse.get_response |
Feed user response to get_response |
mycroft.skill.enable_intent |
Enable a disabled intent (the bus-facing counterpart to calling self.enable_intent(intent_name) from Python) |
mycroft.skill.disable_intent |
Disable an active intent (the bus-facing counterpart to calling self.disable_intent(intent_name) from Python) |
mycroft.skill.set_cross_context |
Set cross-skill context |
mycroft.skill.remove_cross_context |
Remove cross-skill context |
mycroft.skills.settings.changed |
Remote settings update |
ovos.skills.settings_changed |
Local settings file changed |
question:query |
Common query pipeline request |
ovos.common_query.ping |
Common query service discovery |
question:action.{skill_id} |
Common query callback (this skill's answer was selected) |
question:action |
Common query callback (generic, any skill's answer was selected) |
homescreen.metadata.get |
Homescreen requesting metadata |
{skill_id}.public_api |
Skill API introspection |
A skill subscribes to both stop topics (OVOS-STOP-1 §9): {skill_id}.stop, the
targeted dispatch that ceases only its own stoppable activity for the inbound session, and
mycroft.stop, the universal broadcast that ceases everything for that session. A duplicate
arrival on either topic while the skill is already stopping is a no-op. See the
Stop Pipeline.
Read next: Skill API: Inter-Skill RPC Related: ovos-workshop Documentation · Decorators · Skill Settings · Session Aware Skills