Fast, local speech-to-text engines are cheap to run, but they come with a familiar annoyance: the transcribed text is often mangled. HomeAssistant's own intent parser, Hassil, demands exact matches against configured patterns. Say something slightly wrong and you get a dead end. hass-closest-intent sits between your STT output and Hassil, fuzzily correcting garbled phrases before they ever reach the intent engine. It's a thin wrapper that does one job well: turning "Vacuum Believing Room" into "Cleaning the living room."
The project has 35 GitHub stars and is written in Python. It doesn't call any LLMs under the hood — just fuzzy string matching against your intent patterns, with a few clever heuristics layered on top.
Architecture
closest-intent registers as a conversation agent inside HomeAssistant. On startup it parses every user-defined intent (or optionally the builtins too) and expands all pattern rules — <expansion_rule>, (alternatives|to), [optional|alternatives] — into concrete surface forms. During this pass it also records where {slots} appear and whether each slot is a wildcard or belongs to a fixed list such as areas, entities, or numbers.
When a request arrives — whether from voice or the chat box — the integration fuzzy-matches the raw input against those expanded rules. If a rule contains no slot, it's selected immediately. If it does contain a slot, the code searches across the top-scoring matched sentences to extract the best-fitting slot value. The README describes this as "smallest slot-value on a word-boundary," though the extraction isn't strictly limited to that.
Once the best match is found, a canonical sentence is reconstructed and forwarded to Hassil. Hassil then handles the intent exactly as if the user had spoken perfectly. If nothing matches, the raw input is passed to a configurable fallback agent — by default Hassil itself, though an LLM can be wired in if you want.
The README frames this as a pipeline: STT → closest-intent → Hassil → HomeAssistant. There's no action execution or script logic inside closest-intent; it stays out of that business entirely.
What you can do with it
The feature list centers on three capabilities. Pattern expansion handles all of Hassil's alternation and optional syntax, applied even to HASS-defined lists like your areas and entities. Slot extraction works for both wildcards (e.g., {item} in a shopping-list command) and constrained slots like {timer_hours:hours}. Fuzzy slot resolution lets the integration correct misspelled or misheard values against available options — "livikroom" becomes "living room."
The README includes a table of real examples. The author recorded themselves speaking in German with wyoming-faster-whisper-base as the STT engine, then compared outcomes. "Star cleaning." was corrected to trigger the cleaning intent. "Stop clenching!" mapped to "stop cleaning." "Vacuum Believing Room" resolved to "Cleaning the living room." Bare Hassil, without the wrapper, rejected all of these.
Configuration options are straightforward. The threshold setting (default 70) controls the minimum fuzzy-match score; raising it makes matching stricter. expansion_cap (default 16) limits how many surface forms each pattern generates — builtin intents are separately capped at 32 to avoid combinatorial blowup. A denylist lets you exclude specific intent names from matching.
threshold: 70
expansion_cap: 16
denylist: []
Constraints and gotchas
Two limitations deserve attention. False positives become more likely as your intent list grows and patterns start looking similar. The README recommends raising the threshold if this happens. Builtin intents are off by default. HomeAssistant ships with many intents and heavy expansion rules; expanding all of them would explode the search space. Even when enabled, builtin expansion is capped at 32 depth, and the README notes these expansions often cover things like (How is|How's) that don't help much with fuzzy matching.
The project is language-agnostic — the author runs it in German. It works with any STT provider that feeds text into Hassil. There's no stated dependency on specific HomeAssistant versions, but it clearly targets the Hassil conversation agent integration.
Getting started
Setup is through HACS (custom repo) or direct install, then configuration via the UI or configuration.yaml. The README covers both paths; the actual steps are short and worth reading if you already have Hassil running.
Who should reach for this
If your local STT is the bottleneck and you don't want to swap in a cloud service or add an LLM, hass-closest-intent gives you a practical middle ground. It's lighter than anything LLM-based and focused entirely on intent correction rather than generation. The trade-off is the false-positive risk and the need to keep your intent patterns clean. For users with a few dozen custom intents and a noisy STT pipeline, it's worth a try. The source is on GitHub.
Comments