# intents: the training data behind Home Assistant's local voice control

> The OHF-Voice/intents repository is not an application but a corpus of YAML sentence templates, responses and tests, one directory per language, and it is where every new voice command for Home Assistant Assist is written before it works offline on a Raspberry Pi.

**OHF-Voice/intents** — Intents to be used with Home Assistant

- Repository: https://github.com/OHF-Voice/intents
- Website: https://developers.home-assistant.io/docs/voice/overview/
- Stars: 632 · Forks: 642
- Language: Python
- License: CC-BY-4.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/ohf-voice-intents

## A corpus of YAML, not a codebase with an API

The repository description is one line: intents to be used with Home Assistant. The README says it contains training data for Home Assistant's local voice control, and that framing sets expectations correctly. There is no server, no client library and no runtime to install. What there is, is a directory of YAML files describing, for each language, which sentences should be understood and what the assistant should say back. The audience splits in two. The first is a speaker of a language Home Assistant does not yet understand, who wants to add support. The second is a user of a supported language who finds that a command Home Assistant is supposed to recognise does not match the way they would phrase it. The licence is CC-BY-4.0, which is unusual for code and normal for language data, and the last push to the repository was on 2026-10-20, with releases published under date style version numbers such as 2026.10.6.

## Four directories per language, and two top level manifests

The repository layout is the specification. At the top there are two manifests. languages.yaml lists the supported languages and their language leader, which is the person who coordinates the work for that language, and intents.yaml lists the supported intents, which is the shared vocabulary every language has to cover. Below that, each language gets a set of directories. The sentences/ directory holds intent matching sentences in files named domain_intent.yaml, following a template sentence syntax. The responses/ directory holds what the assistant replies, using a separate test syntax. The tests/ directory holds test sentences and the intents they are expected to match. There are also shared/ for content shared across languages, lists/ and rules/ for reusable value lists and matching rules, a script/ directory holding the tooling, a website/ directory that produces the progress page, and a docs/ directory with more detail. The consequence of that design is that adding a language or an intent is a matter of adding directories and YAML, not writing code.

## The intentfest tool validates, tests, parses and samples

The tool that makes the corpus maintainable is the intentfest module, invoked as a Python module. The first job is validation, checking that the data is correctly formatted for a given language.

```bash
python3 -m script.intentfest validate --language nl
```

The second job is running the tests, which parse the sentences and verify them against the test sentences. The test selection is by intent name, so you can work on one intent at a time.

```bash
pytest tests --language nl -k fan_HassTurnOn
```

Leaving off the language flag tests all languages, leaving off the -k flag tests all files, and adding -n auto enables parallelisation, which is what you want when the corpus is large. The toolchain around that is Python and modest: hassil 3.12.1 does the sentence matching, with PyYAML, voluptuous for schema validation, regex and jinja2, and the developer side adds pytest with xdist for parallel runs, mypy, pylint, flake8, black, isort and pre-commit. The repository is configured for devcontainers, which the README names as the easiest way to start contributing.

## Parsing and sampling let you see what the matcher does

Two subcommands make the matching logic visible, which is the practical way to debug a sentence that does not fire. The parse command takes a sentence and prints a line of JSON per sentence you pass, with the text, whether it matched, the intent it matched and the slots it extracted.

```bash
python3 -m script.intentfest parse --language en --sentence 'turn on the lights in the kitchen'
```

```json
{
  "text": "turn on the lights in the kitchen",
  "match": true,
  "intent": "HassTurnOn",
  "slots": {
    "area": "kitchen",
    "domain": "light"
  }
}
```

The sample command goes the other way and prints sentences the matcher could produce, which is how you check that a template generates the phrasings you intended. You can limit the output to particular intents with the --intents flag, and leave off -n to generate all possible sentences rather than a sample. A third subcommand, sample_template, renders one template directly, and it accepts lists, ranges and expansion rules, so you can see what an optional segment such as [the] expands to.

## Counting permutations, because optional segments multiply

There is a performance trap in the design that the tooling explicitly addresses. Using optional segments in a sentence definition can produce a very large number of variations, sometimes growing unexpectedly large, and that can affect performance, particularly on lower-powered devices such as the small computers Home Assistant often runs on. The count_sentences command exists for this, with a summary mode that gives a per intent, per language total, and a detailed mode that shows the permutations for each intent in a language.

```bash
python3 -m script.intentfest count_sentences --language nl --summary
```

```bash
python3 -m script.intentfest count_sentences --language nl
```

The stated purpose is to identify overly broad definitions, refine the sentence structures, and keep interactions natural and efficient without unnecessary complexity that slows processing. This is a good example of a corpus project that takes performance seriously: the sentences are not just translated, they are budgeted.

## Adding a language, and asking an LLM for a first draft

Two commands support the growth of the corpus. The first adds a language, taking a language code and the name of the language in its own language, with the code expected to follow ISO 639 conventions such as en or pl.

```bash
python3 -m script.intentfest add_language <language code> <language name>
```

The second is a translation aid. The llm_template command generates a prompt you can paste into ChatGPT or another LLM to help translate a given intent, and the README shows it used for the HassListAddItem intent translated into Italian.

```bash
python3 -m script.intentfest llm_template it HassListAddItem
```

That is a pragmatic choice rather than a translation pipeline. The generated output still has to be checked by a speaker of the language, and the language leader named in languages.yaml is the person who does that. The repository also links the Home Assistant developer documentation on intent recognition, the list of supported built-in intents, the list of supported languages, the contributing guide, the language leaders page and a progress page per language and intent, so a contributor can see how much of a language is done before starting.

## Where the intents corpus is the wrong place to work

The limits follow from the design. First, this repository is not a voice assistant and cannot be evaluated by running it. You can parse a sentence and see whether it matches, but whether the reply is natural, and whether the assistant handles the follow up, is decided elsewhere in Home Assistant. Second, coverage is uneven across languages by construction, since each language is maintained by volunteers and the progress page exists precisely because that varies, so a feature you assume is voice controlled may not be. Third, the whole model assumes the intent set in intents.yaml, so a command Home Assistant has no intent for cannot be added here, only phrasings of existing intents can. The alternative worth naming is a general speech to intent stack where you train your own model from your own corpus, which gives full control over the phrase set and the response wording at the cost of building the matching and the model yourself, and of losing the shared cross language effort that is the reason this repository exists. For a Home Assistant user who wants a sentence understood, this is the only place to say so.

## Conclusion

Contribute to the intents repository if you speak a language Home Assistant does not cover yet, or if you want to make an existing voice command understand more phrasings, because sentences are matched by template rather than by keyword. Do not expect to install anything from it, since it is training data consumed by Home Assistant rather than a service. Verify first whether your language already has a leader listed in languages.yaml, and measure the sentence count for your intents before adding optional segments, since template permutations can grow large enough to slow down a low powered device.

## FAQ

### How do I validate sentence data in the Home Assistant intents repository?

Run python3 -m script.intentfest validate --language nl to check that the data is correctly formatted for a language, then run the tests with pytest, for example pytest tests --language nl -k fan_HassTurnOn, which parse the sentences and verify them against the test sentences.

### How do I check whether a sentence matches an intent?

Use the parse subcommand with a language and a sentence, for example python3 -m script.intentfest parse --language en --sentence 'turn on the lights in the kitchen'. It prints JSON with the text, the match flag, the intent and the extracted slots.

### How do I add a new language to the Home Assistant intents repository?

Run python3 -m script.intentfest add_language with a language code and the name of the language in its own language. The code should follow ISO 639, such as en or pl, and languages.yaml records the supported languages and their language leader.

### Why should I count sentence variations before adding optional segments?

Optional segments in a sentence definition can produce a very large number of variations, sometimes growing unexpectedly large, which can impact performance on lower-powered devices. The count_sentences command gives a per intent and per language summary and detailed permutation counts so overly broad definitions can be refined.

## Sources

- [License: CC-BY-4.0](https://github.com/OHF-Voice/intents/blob/main/LICENSE)
- [OHF-Voice/intents on GitHub](https://github.com/OHF-Voice/intents)
- [Project website](https://developers.home-assistant.io/docs/voice/overview/)
- [README](https://github.com/OHF-Voice/intents/blob/main/README.md)
- [Releases](https://github.com/OHF-Voice/intents/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ohf-voice-intents
