Skip to content

Skill Classes Reference

In a nutshell

This page is the per-class reference for every specialized skill base class in ovos-workshop beyond the universal OVOSSkill: converse-aware skills, fallback skills, media/game skills, auto-translating skills, and standalone applications, plus the skill launcher and the decorator quick reference. For OVOSSkill itself and guidance on which class to pick, see Skill Classes.

ovos-workshop provides all base classes needed to write skills for OpenVoiceOS. Every skill ultimately inherits from OVOSSkill.

Package: ovos-workshop | Entry point group: opm.skill


ConversationalSkill

Module: ovos_workshop.skills.converse.ConversationalSkill

Extends OVOSSkill with explicit converse support: activate(), deactivate(), and @conversational_intent decorated handlers. The skill registers itself in the active-skills list after handling an intent.

from ovos_workshop.skills.converse import ConversationalSkill

class MySkill(ConversationalSkill):
    def can_converse(self, message):
        return True

    def converse(self, message):
        utterance = message.data["utterances"][0]
        if "help" in utterance:
            self.speak("Here to help!")
            return True   # consumed
        return False      # pass to next handler

can_converse is abstract on ConversationalSkill and is what the framework actually calls on the ping/pong broadcast that determines active-skill status; leaving it unimplemented raises NotImplementedError there, so converse() is never reached.

Additional bus events registered:

  • {skill_id}.converse.ping: capability advertisement (plus the broadcast ovos.converse.ping, answered only when the skill is named in the session's active_handlers, since ovos-workshop 9.4.0a1)

  • {skill_id}.converse.request: converse request from pipeline

  • {skill_id}.activate / {skill_id}.deactivate


ActiveSkill

Module: ovos_workshop.skills.active.ActiveSkill

Extends ConversationalSkill. Always present in the converse active-skills list. The skill never deactivates unless explicitly told to. Useful for always-on assistants or global command handlers.

from ovos_workshop.skills.active import ActiveSkill

class AlwaysListeningSkill(ActiveSkill):
    def can_converse(self, message):
        return True

    def converse(self, message):
        utterance = message.data["utterances"][0]
        # handle every utterance
        return False  # let other skills also process

FallbackSkill

Module: ovos_workshop.skills.fallback.FallbackSkill

Handles utterances that matched no intent. Must implement can_answer() and provide at least one @fallback_handler.

from ovos_workshop.skills.fallback import FallbackSkill
from ovos_workshop.decorators import fallback_handler

class MyFallback(FallbackSkill):
    def can_answer(self, message: Message) -> bool:
        # utterances are read from the message internally
        return True   # always willing to try

    @fallback_handler(priority=50)
    def handle_fallback(self, message):
        self.speak("I don't know, but I tried.")
        return True   # consumed: stop checking other fallbacks

Priority determines which internal pipeline stage checks the fallback first (lower runs earlier). These are the dispatch stage boundaries, verified in FallbackService (ovos_core/intent_services/fallback_service.py). This is a separate fact from which priority you should actually pick for a handler, covered in Fallback Skill:

Range (exclusive start, inclusive stop) Pipeline stage
0–5 fallback_high
5–90 fallback_medium
90–101 fallback_low

A priority of exactly 5 lands in fallback_high, and exactly 90 lands in fallback_medium, since the stage boundary itself is included in the lower stage.

Priority can be overridden in config:

{"skills": {"fallbacks": {"fallback_priorities": {"my-skill-id": 10}}}}

CommonQuery: @common_query on OVOSSkill

There is no dedicated CommonQuerySkill base class. Decorate a method on a regular OVOSSkill with @common_query() to join the question:query / ovos-common-query-pipeline-plugin pipeline. The handler answers a natural language question and returns a confidence score. The pipeline collects responses from all skills and speaks the highest-confidence answer.

from ovos_workshop.skills.ovos import OVOSSkill
from ovos_workshop.decorators import common_query

class MyQuerySkill(OVOSSkill):
    @common_query()
    def handle_query(self, phrase, lang):
        if "capital of france" in phrase.lower():
            return "Paris", 0.9   # (answer, confidence)
        return None, 0

Under the hood

On startup OVOSSkill scans for a method tagged by @common_query (in ovos_workshop/skills/ovos.py) and wires up the CommonQuery ping/answer bus handlers automatically. Only one such handler per skill is supported.


OVOSCommonPlaybackSkill

Module: ovos_workshop.skills.common_play.OVOSCommonPlaybackSkill

Integrates with OCP (OpenVoiceOS Common Play) for media playback. Uses @ocp_search, @ocp_play, and related decorators to respond to play requests and appear in the OCP media browser.

from ovos_workshop.skills.common_play import OVOSCommonPlaybackSkill
from ovos_workshop.decorators.ocp import ocp_search, ocp_featured_media
from ovos_utils.ocp import MediaType, PlaybackType, MediaEntry, Playlist

class MyMusicSkill(OVOSCommonPlaybackSkill):
    @ocp_search()
    def search_music(self, phrase: str, media_type: MediaType):
        if media_type == MediaType.MUSIC:
            yield MediaEntry(
                title="My Song",
                uri="https://example.com/song.mp3",
                playback=PlaybackType.AUDIO,
                media_type=MediaType.MUSIC,
                match_confidence=80,
            )

    @ocp_featured_media()
    def featured(self) -> Playlist:
        pl = Playlist(title="My Playlist", playback=PlaybackType.AUDIO,
                      media_type=MediaType.MUSIC, match_confidence=90)
        pl.add_entry(MediaEntry(uri="https://example.com/song.mp3",
                                title="My Song",
                                playback=PlaybackType.AUDIO,
                                media_type=MediaType.MUSIC,
                                match_confidence=90))
        return pl

OVOSGameSkill

Module: ovos_workshop.skills.game_skill.OVOSGameSkill Source: ovos_workshop/skills/game_skill.py

Extends OVOSCommonPlaybackSkill. Structured base for OCP-integrated voice games. Subclasses must implement all six abstract methods: on_play_game, on_pause_game, on_resume_game, on_stop_game, on_save_game, on_load_game.

from ovos_workshop.skills.game_skill import OVOSGameSkill

class TriviaGameSkill(OVOSGameSkill):
    def __init__(self, *args, **kwargs):
        super().__init__(skill_voc_filename="trivia_game", *args, **kwargs)

    def on_play_game(self):
        self.speak("Starting trivia!")

    def on_pause_game(self):
        self._paused.set()

    def on_resume_game(self):
        self._paused.clear()

    def on_stop_game(self):
        self.speak("Game over.")

    def on_save_game(self):
        self.speak("Save is not supported.")

    def on_load_game(self):
        self.speak("Load is not supported.")

ConversationalGameSkill

Module: ovos_workshop.skills.game_skill.ConversationalGameSkill Source: ovos_workshop/skills/game_skill.py

Extends OVOSGameSkill. Adds a converse loop: every utterance that does not match a registered intent is piped to on_game_command() while the game is playing. Also adds auto-save support, default pause/resume dialogs, and on_abandon_game().

Remaining abstract methods (you must implement these): on_play_game, on_stop_game, on_game_command. on_save_game and on_load_game get a default implementation that just speaks a "can't save/load" dialog. Override them if your game supports saving. on_pause_game, on_resume_game, and on_abandon_game also get working default implementations (pause/resume dialogs gated by the pause_dialog setting, and a no-op abandon hook) that you can leave alone or override.

from ovos_workshop.skills.game_skill import ConversationalGameSkill

class AdventureSkill(ConversationalGameSkill):
    def __init__(self, *args, **kwargs):
        super().__init__(skill_voc_filename="adventure_game", *args, **kwargs)

    def on_play_game(self):
        self.speak("You enter a dark room. What do you do?")

    def on_stop_game(self):
        self.speak("Adventure ends.")

    def on_game_command(self, utterance: str, lang: str):
        if "north" in utterance:
            self.speak("You walk north.")
        else:
            self.speak("I don't understand that command.")

UniversalSkill

Module: ovos_workshop.skills.auto_translatable.UniversalSkill Source: ovos_workshop/skills/auto_translatable.py

Extends OVOSSkill. Automatically translates incoming utterances to self.internal_language before the intent handler runs, and translates self.speak() output back to the user's language. Requires a translator plugin to be configured.

from ovos_workshop.skills.auto_translatable import UniversalSkill
from ovos_workshop.decorators import intent_handler

class MySkill(UniversalSkill):
    def __init__(self, *args, **kwargs):
        # All handlers receive utterances in English regardless of user's language.
        super().__init__(internal_language="en-US", *args, **kwargs)

    @intent_handler("ask_weather.intent")
    def handle_weather(self, message):
        # Utterance is already in en-US here.
        self.speak("The weather is sunny.")  # auto-translated back to user's lang

UniversalFallback

Module: ovos_workshop.skills.auto_translatable.UniversalFallback Source: ovos_workshop/skills/auto_translatable.py

Combines UniversalSkill and FallbackSkill. Fallback handlers receive utterances in self.internal_language. self.speak() translates output back to the user's language.

from ovos_workshop.skills.auto_translatable import UniversalFallback
from ovos_workshop.decorators import fallback_handler

class MyUniversalFallback(UniversalFallback):
    def __init__(self, *args, **kwargs):
        super().__init__(internal_language="en-US", *args, **kwargs)

    def can_answer(self, message):
        return True

    @fallback_handler(priority=75)
    def handle_unknown(self, message) -> bool:
        utterance = message.data["utterances"][0]
        self.speak(f"I heard: {utterance}")
        return True

OVOSAbstractApplication

Module: ovos_workshop.app.OVOSAbstractApplication Source: ovos_workshop/app.py

Like OVOSSkill but designed to run without an intent service. Suitable for standalone GUI apps, HiveMind-attached services, or any program that needs TTS/messagebus/settings but does not register intents with ovos-core. Creates its own bus connection if none is provided. Settings stored under apps/<id>/ instead of skills/<id>/.

from ovos_workshop.app import OVOSAbstractApplication

class MyApp(OVOSAbstractApplication):
    def __init__(self, **kwargs):
        super().__init__(skill_id="my-app.author", **kwargs)

    def initialize(self):
        self.speak("App is ready.")

app = MyApp()  # Creates its own bus connection automatically.

Skill Launcher

Module: ovos_workshop.skill_launcher.PluginSkillLoader

PluginSkillLoader is used by SkillManager to load plugin-based skills:

from ovos_workshop.skill_launcher import PluginSkillLoader

loader = PluginSkillLoader(bus, skill_id)
loader.load(MySkillClass)   # instantiates and calls _startup

Skills can also be run as standalone processes:

ovos-skill-launcher my_skill_package_name

This is the recommended approach for running skills in Docker containers.


Decorators Quick Reference

All decorators are importable from ovos_workshop.decorators:

Decorator Description
@intent_handler("file.intent") Register Padatious or Adapt intent handler
@conversational_intent("file.intent") Register converse-only Padatious handler
@fallback_handler(priority=50) Register fallback handler with priority
@common_query() Register CommonQuery handler (return answer, confidence)
@converse_handler Alias method as the skill's converse handler
@adds_context("Context") Add context entity after method runs
@removes_context("Context") Remove context entity after method runs
@skill_api_method Expose method over the bus for inter-skill calls
@killable_intent() Intent that can be interrupted mid-execution
@homescreen_app(icon, name) Register as homescreen app launcher
@ocp_search() Search for playable content
@ocp_featured_media() Provide featured media for OCP GUI
@layer_intent(intent, layer_name) Intent belonging to a named layer
@enables_layer("layer") Activate a named intent layer after method
@disables_layer("layer") Deactivate a named intent layer after method

Source code: OpenVoiceOS/ovos-workshop.


Read next: Skill Classes · Decorators Related: OVOSSkill · Fallback Skill · Common Query Framework · OCP Skills