Skip to content

GUI Service (ovos-gui)

Maturity: Beta ⬤⬤⬤◯◯ — but the stack is deprecated

The ovos-gui repository is active, but the GUI stack this page documents is legacy and being superseded. There is no generally usable OVOS GUI, and a replacement is Upcoming. See Screens on OVOS Today for the full picture and what to use now. The badge rates repository health, not the stack's status.

In a nutshell

ovos-gui is the part of OpenVoiceOS that decides what shows up on a screen: text, images, a music player, or an idle home screen. Skills never draw to the display themselves. They send a request to this service, which keeps track of what each skill wants shown and passes it on to whatever screen is connected. Think of it as a stage manager that decides which scene is in front of the audience at any moment. To learn more, see the Home Screen and the Glossary.

Formal specification

The forward model for the display layer is OVOS-GUI-1: GUI Display Subsystem. It reframes the GUI as a voice-OS peripheral: an application declares what to show using a closed SYSTEM_* template vocabulary, and any number of interchangeable render backends decide how to draw it (pixels, a character grid, a synthesized face…), each routed solely by the message's session_id. The ovos-gui daemon described on this page is the current ("legacy") implementation. Read GUI-1 for the target contract this subsystem is converging on. For the full set see the spec index.

ovos-gui is the GUI orchestration daemon for OpenVoiceOS. It tracks display state and manages the namespace stack that determines what is currently visible on screen.

How a skill draws on screen (beginner view)

A skill never talks to the display directly. It calls methods on self.gui (a GUIInterface), which emit messages on the OVOS messagebus. ovos-gui receives those messages, keeps track of what each skill wants shown, and forwards the result to whatever GUI client is connected (typically ovos-shell running the Qt/Kirigami UI).

A minimal example that displays some text:

from ovos_workshop.skills import OVOSSkill
from ovos_workshop.decorators import intent_handler

class HelloSkill(OVOSSkill):
    @intent_handler("hello.intent")
    def handle_hello(self, message):
        self.speak("Here is your message")
        self.gui.show_text("Hello from OVOS", title="Greeting")

show_text() writes the text into the skill's namespace and tells the GUI client to load the built-in text page. When the skill is done, the namespace is removed and the screen returns to the previous view or the idle/homescreen.


Architecture (current)

self.gui is a SkillGUI (subclass of GUIInterface from ovos_bus_client.apis.gui). It emits these bus messages:

Bus message Emitted by Purpose
gui.value.set GUIInterface.__setitem__ / _sync_data() Write session variables into the skill's namespace
gui.page.show GUIInterface.show_page() / show_pages() Request one or more QML pages be shown
gui.page.delete / gui.page.delete.all remove_page() / remove_all_pages() Remove pages from the namespace
gui.event.send send_event() Send a custom event into the namespace
gui.clear.namespace clear() Remove the skill's namespace from the active stack

ovos-gui itself is the GUI WebSocket server. ovos_gui/bus.py runs a Tornado WebSocket endpoint (default port 18181) that Qt clients connect to. NamespaceManager (ovos_gui/namespace.py) translates the bus messages above into the Qt wire protocol (mycroft.session.*, mycroft.gui.list.*) and pushes them to every connected client. See GUI Protocol for the wire format.

┌──────────────────────────────────────────────────────────┐
│  Skill (OVOSSkill)                                        │
│  self.gui.show_text("Hello", title="Greeting")           │
└────────────────────┬─────────────────────────────────────┘
                     │  gui.value.set  +  gui.page.show
                     │  (OVOS MessageBus)
┌──────────────────────────────────────────────────────────┐
│  ovos-gui  —  NamespaceManager (namespace.py)            │
│              GUIWebsocketHandler (bus.py, Tornado)        │
│  Maintains the active namespace stack and per-namespace  │
│  session data + page list; mirrors it to every client    │
│  as mycroft.session.* / mycroft.gui.list.* messages      │
└────────────────────┬─────────────────────────────────────┘
                     │  WebSocket (port 18181)
            Qt5 / Qt6 GUI client (mycroft-gui / ovos-shell)
            resolves and renders the requested QML pages

In words: a skill calls self.gui (for example show_text()), which emits gui.value.set and gui.page.show on the OVOS messagebus. ovos-gui's NamespaceManager tracks the active namespace stack and mirrors it out to every connected client as mycroft.session.* / mycroft.gui.list.* messages over its WebSocket. The Qt client receives those messages and renders the requested QML page.

GUIInterface display methods

self.gui exposes these display methods (from ovos_bus_client.apis.gui.GUIInterface):

Method QML page shown
show_page(name, ...) / show_pages(names, ...) arbitrary page resource(s)
show_text(text, title=None, ...) SYSTEM_TextFrame
show_image(url, caption=None, title=None, fill=None, ...) SYSTEM_ImageFrame
show_animated_image(url, ...) SYSTEM_AnimatedImageFrame
show_html(html, resource_url=None, ...) SYSTEM_HtmlFrame
show_url(url, ...) SYSTEM_UrlFrame
show_input_box(title=None, ...) SYSTEM_InputBox
show_face(awake=True, ...) SYSTEM_Face
show_loading_animation(text, ...) SYSTEM_Loading
show_status_animation(text, success, ...) SYSTEM_Status
show_notification(content, ...) / show_controlled_notification(content, ...) notification overlay

Skills may also ship their own .qml pages and call show_page("my_page.qml"). Page resources are resolved by the Qt client (see GUI Protocol).


Namespaces

GUI state is organized into namespaces, each corresponding to a skill_id. Each namespace holds session data (key/value pairs) and an ordered list of displayed pages.

  • NamespaceManager maintains an ordered active stack (mirrored to clients as the reserved mycroft.system.active_skills namespace). The namespace at position 0 is the one currently displayed.

  • Skills display pages via gui.show_*(). Users interact with the rendered page.

  • When a skill clears its namespace (gui.clear()gui.clear.namespace), the namespace is removed from the active stack and the next namespace becomes visible.

  • When the stack is empty, the GUI client shows its idle/homescreen view.

Example lifecycle:

OVOS idle          → homescreen / idle view
"play music"       → music player namespace at position 0
"what time is it"  → clock skill namespace at position 0; music player at 1
clock times out    → music player namespace at position 0
music ends         → stack empty → idle view shown

Note: GUI does not yet track namespaces per Session. Today all clients share one global display stack.


Configuration

The GUI WebSocket server is configured under gui_websocket in mycroft.conf:

{
  "gui_websocket": {
    "host": "127.0.0.1", // loopback-only by default — widen to 0.0.0.0 only for a remote display
    "base_port": 18181,
    "route": "/gui"
  }
}
Key Description
host Interface the Tornado WebSocket server binds to (default: 127.0.0.1, loopback only)
base_port TCP port Qt clients connect to (default: 18181)
route WebSocket route path (default: /gui)

The GUI WebSocket is unauthenticated, unencrypted, and reaches the core bus

Anything received on the GUI socket is translated into an emit on the core messagebus. So this socket carries the same authority as the bus itself. There is no authentication and no origin check. On top of that, there is no TLS option either. Unlike ovos-messagebus (which can serve wss:// itself), ovos-gui's Tornado WebSocket server has no working gui_websocket.ssl server path. The gui_websocket.ssl key does exist in the default config (value false), but it is a no-op. create_gui_service in ovos_gui/bus.py reads only route, base_port, and host, so nothing turns this socket into wss://.

It ships bound to 127.0.0.1 (loopback only). Widen gui_websocket.host to 0.0.0.0 only if a remote display genuinely needs network access — and check configs from older installs, which may still carry 0.0.0.0. Never leave 0.0.0.0 on an untrusted network, and never expose port 18181 beyond a trusted network. If a display really must run on another machine, put it behind a VPN or a reverse proxy that authenticates and terminates TLS. Or use HiveMind for authenticated remote transport.


Upcoming: unreleased

The following describes a plugin-based rendering rework that is not yet released and not present on any published package. It is specified by the OVOS-GUI-1 spec and implemented in ovos-gui, with adapters in ovos-legacy-mycroft-gui-plugin and pyhtmx-gui-client. Do not rely on any of this on a stable install. Tracked in ovos-plugin-manager#377, ovos-gui#112, ovos-gui#117, and ovos-legacy-mycroft-gui-plugin#3.

What changes. Per OVOS-GUI-1, ovos-gui becomes a pure state-and-dispatch hub. It runs no WebSocket server and renders nothing. It loads every installed GUI adapter plugin (opm.gui_adapter entry-point group) via OVOSGUIAdapterFactory.create_all(bus, config) and fans each display event out to all of them at once. This enables multi-modal output (Qt + browser + terminal at once). A headless device with zero adapters degrades to a no-op dispatch. It never crashes. The Qt WebSocket server moves into the ovos-legacy-mycroft-gui-plugin adapter.

Templates instead of QML page names. Skills display one of a closed vocabulary of 22 SYSTEM_* templates (SYSTEM_weather, SYSTEM_text, SYSTEM_list, and more) defined by the spec. Custom QML page names are no longer accepted by the router. The template-based GUIInterface moves into the standalone ovos-gui-api-client package (separate from the current ovos_bus_client.apis.gui.GUIInterface).

Addressing is session_id-only. The spec drops any separate site/room/location dimension. A GUI message is routed solely by its session_id, and a shared/multi-room screen is expressed by clients sharing one session_id. This is the intended target design, not a regression.

See GUI Adapter Plugins for the adapter API and the full template list, and the Upcoming section of GUI Protocol for the routing messages.


See GUI Protocol for the full Qt WebSocket wire protocol. See OVOS Shell for the production Qt5/Kirigami shell application, and Home Screen for idle-screen skills.


Read next: PHAL · Concepts Overview Related: Screens on OVOS Today · GUI Adapter Plugins · GUI Protocol · Skill GUI Support