Skip to content

Skill Installer (SkillsStore)

Maturity — Mature ⬤⬤⬤⬤⬤

Long-lived and actively maintained. Depend on it freely. Rated by repository health, not version.

In a nutshell

This is the built-in part of OVOS that can add or remove skills (and other software packages) while the assistant is running. No terminal or restart is needed. Something asks "install this skill," and OVOS downloads and wires it in on the fly. It is switched off unless explicitly enabled, for safety. See Skill Manager for how skills then get loaded, or the Glossary for terms.

Module: ovos_core.skill_installer.SkillsStore: ovos_core/skill_installer.py

The SkillsStore is a built-in subsystem of ovos-core that provides runtime skill and package management via the messagebus.

In plain terms: other parts of the system (or you, over the bus) can ask OVOS to pip install a skill or library while it is running. No shell access or restart is needed. It is opt-in and guarded behind the allow_pip config flag.


Technical Reference
  • SkillsStore.pip_install(): ovos_core/skill_installer.py. Core logic for calling pip or uv.

  • SkillsStore.handle_install_skill(): ovos_core/skill_installer.py. Bus event handler for ovos.skills.install.

  • After a successful install, ovos_core/skill_installer.py re-imports ovos_plugin_manager (Python's importlib.reload) so the new entry points are picked up.


Overview

The skill installer allows for dynamic installation and uninstallation of skills and other Python packages. It uses uv pip if uv is available on the system's $PATH; otherwise, it falls back to standard pip.

To prevent issues with concurrent package management, a named lock (ovos_pip.lock) is used during all install and uninstall operations.

Configuration

The installer can be configured in mycroft.conf. It is disabled unless allow_pip is true — every install/uninstall handler bails out with a DISABLED error otherwise:

{
  "skills": {
    "installer": {
      "allow_pip": true,
      "constraints": "https://raw.githubusercontent.com/OpenVoiceOS/ovos-releases/refs/heads/main/constraints-stable.txt",
      "sounds": {
        "pip_error": "snd/error.mp3",
        "pip_success": "snd/acknowledge.mp3"
      }
    }
  }
}

Three more booleans in the same skills.installer section shape the pip call itself, all default false: upgrade passes --upgrade so re-installing an already-installed package actually updates it (without it, a repeat install is a silent no-op, since ovos-core 2.6.1a1); allow_alphas permits pre-release versions; break_system_packages passes the matching pip flag for externally-managed environments.

The constraints file bounds allowed versions — its entries are compatible ranges (>=x,<y), not exact pins, so it constrains what may be installed rather than fixing it. The packages it lists are also treated as protected: ovos.pip.uninstall refuses to remove a package named there.

Uninstall protection is an accident guard, not a security control

The protected list stops a request from removing OVOS's own components by name. It is not a privilege boundary. Anything that can reach the messagebus already has full control of the device, and allow_pip: true gives it package-management rights. Security comes from keeping the bus local and allow_pip off, not from this list.

Skills are not sandboxed — this installs and runs arbitrary code

There is no sandbox or permission model. Installing a skill through SkillsStore means pip/uv installing a Python package and loading it. It runs with the same access as the rest of OVOS on the OVOS user account. The messagebus has no authentication. Combined with that fact, turning allow_pip on while the bus is reachable by anyone untrusted is effectively a remote-code-execution switch: anyone who can reach the bus can request an install of code they control. See Privacy & Security for the full picture before enabling this in production.

Install/Uninstall Events

You can trigger installation and uninstallation by emitting messages on the messagebus. The skill events and the pip events take different payloads. Skills are installed from a single GitHub URL, while the generic pip events take a list of package specifiers.

Skill installation

A skill is installed from a GitHub repo URL (it is validated and then installed as git+<url>):

ovos.skills.install        data: {"url": "https://github.com/OpenVoiceOS/skill-foo"}
  → ovos.skills.install.complete  (success)
  → ovos.skills.install.failed    (error)

Skill uninstallation

Uninstall by skill_id (or package name). A skill_id like skill-foo.author is mapped to the package name skill-foo-author:

ovos.skills.uninstall      data: {"skill": "skill-foo.author"}
  → ovos.skills.uninstall.complete
  → ovos.skills.uninstall.failed

General pip management

ovos.pip.install           data: {"packages": ["some-lib>=1.0"]}
ovos.pip.uninstall         data: {"packages": ["some-lib"]}

Services other than core can run their own ServiceInstaller (from ovos-utils), which listens on the broadcast topics above. To install into one service rather than all of them, name it in the payload: a request carrying data.service_name is acted on only by the service of that name, and a request without it reaches every installer (OVOS-INSTALL-1 §2). That is how a package installs into the process that actually loads it.

The suffixed ovos.pip.install.<service_name> / ovos.pip.uninstall.<service_name> pair addresses the same thing and predates the specification. Those topics still work and log a deprecation, for one stable cycle. Write data.service_name instead: a topic carries no target, which is what the payload is for.

Four services run their own installer: ovos-audio (service name ovos_audio, since 2.2.0a1), ovos-dinkum-listener (ovos_dinkum_listener, since 0.9.0a1), ovos-gui (ovos_gui, since 1.5.0a1), and ovos-PHAL (since 0.3.0a1, service name ovos_PHAL, or ovos_PHAL_admin when running as AdminPHAL). This matters when services run in separate venvs or containers, where a broadcast install into core's environment would not reach the target process.

Post-Install Discovery

After a successful skill installation, ovos-plugin-manager's entry point cache is reloaded. This ensures the new skill is discovered on the next SkillManager scan cycle (which occurs every 30 seconds by default).

InstallError Types

If an installation fails, an error message is emitted. Possible errors include:

Error Code Meaning
DISABLED The installer is disabled in the configuration.
PIP_ERROR The underlying pip/uv process returned a non-zero exit code.
BAD_URL A provided URL failed validation.
NO_PKGS The package list was empty.

Read next: Speech Service · Concepts Overview Related: Skill Manager · Security & Trust Model · Skills Overview