Resource Files

September 6, 2026 · View on GitHub

Skills load localized resources from a structured directory layout. Resources are loaded automatically at startup for every language in native_langs (core_lang + secondary_langs).

Directory Layout

The recommended layout uses a single locale/ directory:

my-skill/
├── locale/
│   ├── en-US/
│   │   ├── my.dialog        # spoken responses
│   │   ├── my.intent        # padatious intent examples
│   │   ├── my.voc           # adapt vocabulary keywords
│   │   ├── my.entity        # adapt entity examples
│   │   ├── my.rx            # regex patterns for adapt
│   │   └── skill.json       # skill metadata (examples for homescreen)
│   └── es-ES/
│       ├── my.dialog
│       └── my.intent
└── gui/
    └── my_page.qml

Legacy skills may use separate dialog/, vocab/, regex/ subdirectories: these are still supported.

Resource Types

ExtensionTypeDescription
.dialogDialogMustache-templated spoken responses (one per line, random selection)
.intentIntentPadatious training examples
.vocVocabularyAdapt keyword definitions (one keyword per line, first is canonical)
.entityEntityAdapt entity examples
.rxRegexAdapt regex patterns
.listListA flat list resource
.wordWordA single word
skill.jsonMetadata{"examples": ["...", "..."]} for homescreen example utterances

Dialog Files

Each line in a .dialog file is a possible response. One line is chosen randomly when speak_dialog is called:

# my.dialog
Hello there!
Hi! How are you?
Greetings, {name}!

Mustache template variables are filled from the data dict:

self.speak_dialog("my", data={"name": "Alice"})

Vocab Files (Adapt)

Each line is a keyword variation. The first word on each line is the canonical form:

# hello.voc
hello
hi
hey there
good morning

Loaded automatically as HelloKeyword (file name without extension, CamelCase from alphanumeric_skill_id).

Intent Files (Padatious)

One example utterance per line. Supports entity slots {entity} and alternation (a | b):

# my.intent
what is the weather in {location}
(show | tell me) the weather

Typed Slots

A slot may declare a type: {number:amount} names the slot amount and asks the engine for a number. The registered types are number, duration, date and color. The prefix is not part of the slot name — the samples that reach the engine carry the bare {amount}, an unregistered type degrades to an untyped slot with a warning, and the declared types travel separately in the registration's slot_types map (OVOS-INTENT-4 §6.1). An engine MAY use them to constrain where the slot matches (OVOS-INTENT-1 §5.6).

Requiring a slot and requiring its type are different things. To require the slot, list it in required_slots on the intent: the engine enforces it, and the orchestrator backstop rejects a Match whose slot map lacks it (OVOS-PIPELINE-1 §6.2). The type carries no such guarantee. Neither backstop consults data.typed_slots, and a slot value is never coerced (OVOS-INTENT-1 §5.3), so {number:amount} guarantees a value, not a number: the engine may bind text no number parser recognized.

That makes the type check the skill's own. typed_slot() returns the normalized value for a slot, and None when no typed entry covers what the engine bound — the handler re-prompts or refuses:

@intent_handler("set.timer.intent")
def handle_set_timer(self, message):
    minutes = self.typed_slot(message, "amount")
    if minutes is None:
        self.speak_dialog("how.many.minutes")
        return
    self.start_timer(minutes)

A handler that parses the whole utterance and declares no slot reads the entries directly instead: typed_slots(message, "date") returns every date the engine found, in span order. The typed_slots map carries only types with at least one entry, so an empty list means no date is available, whatever the cause.

Entity Files (Padatious)

One example value per line. An .entity file fills a {slot} named by a .intent template:

# game.entity
chess
poker
solitaire

Every .entity file shipped under a skill's locale resources is registered automatically the first time that language's resources are loaded - there is no need to call register_entity_file() explicitly, and every file is registered regardless of whether a .intent in the skill actually names a matching slot. This can be turned off in mycroft.conf:

{"skills": {"auto_register_entity_files": false}}

Padatious version hazard: on ovos-padatious >= 2.0.3a1, a registered entity is a hint - the matcher still accepts values outside the registered sample set, just with a slightly different confidence score. On older matchers (<= 2.0.2a1), registering an entity closes the vocabulary for that slot - values not in the sample set stop matching entirely. If a deployment is pinned to an older ovos-padatious, either upgrade it alongside this package or set auto_register_entity_files to false above to avoid narrowing slots that previously matched anything.

Language Fallback

When a resource is not found for the exact lang, the skill falls back to dialects of the same language. For example, if en-AU is requested but only en-US resources exist, en-US is used.

Loading Resources Manually

# Get SkillResources for current lang
resources = self.resources                         # current self.lang
resources = self.load_lang(self.res_dir, "es-ES")  # specific lang

# Find a specific file
path = self.find_resource("my.dialog", "dialog")
path = self.find_resource("hello.mp3", "snd")

SkillResources API

SkillResources is returned by self.resources and self.load_lang():

# Render a dialog (returns a string, does not speak)
text = self.resources.render_dialog("my.dialog", data={"key": "value"})

# Check if a vocab word matches
matches = self.voc_match("hello there", "hello")  # True

# Load a vocab file into a list
words = self.resources.load_vocabulary_file("my.voc")

# Load a dialog renderer
renderer = self.dialog_renderer

skill.json Metadata

Optional file for homescreen integration. Placed at locale/<lang>/skill.json:

{
  "name": "My Skill",
  "description": "Does something useful",
  "examples": [
    "what is the weather",
    "tell me the weather in Paris"
  ]
}

These examples are emitted to the homescreen as homescreen.register.examples on skill startup.


← filesystem · Home · settings →