#Phrases & Matching
Phrases are how the user's typed text finds your action. Getting a feel for the matcher will save you a lot of "why didn't that trigger?" moments.
#Step 1: tokenizing
Before anything is compared, both the user's input and your phrases are tokenized. Tokenizing:
- lowercases the text,
- strips the punctuation
. , ! ? ; :, - and splits on whitespace into a list of words.
So Set Volume to 40! and set volume to 40 both become the same tokens:
["set", "volume", "to", "40"]. You don't need to worry about capitalization or
trailing punctuation in your phrases — but curly braces are meaningful and are
not stripped.
#Step 2: matching
A phrase is a sequence of literal words and {placeholders}. Matching
walks the phrase and the input together:
- A literal word must appear in the input, in order. If it's missing, the phrase doesn't match at all.
- A placeholder captures words from the input into a parameter.
How much a placeholder captures depends on where it sits:
- A placeholder in the middle captures everything up to the next literal
word in the phrase.
open {app} nowmatched againstopen google chrome nowcapturesapp = "google chrome". If that next literal (now) never appears, the phrase doesn't match. - A placeholder at the end is greedy — it captures all remaining words.
open {app}againstopen google chromecapturesapp = "google chrome".
#Examples
| Phrase | Input | Captured params |
|---|---|---|
hello |
hello |
(none) |
set volume to {target} |
set volume to 40 |
target = "40" |
open {app} |
open google chrome |
app = "google chrome" |
email {who} about {what} |
email sam about lunch |
who = "sam", what = "lunch" |
close {app} now |
close spotify |
(no match — now is missing) |
#Step 3: picking a winner
Several phrases across several packs can match the same input. When that happens, Personal Goober prefers the most specific match — the one with the fewest placeholders. A phrase made entirely of literal words beats one with a placeholder.
That means you can safely register both a general phrase and specific shortcuts:
{
"playMusic": ["play {query}"],
"playFavorites": ["play my favorites"]
}Typing play my favorites matches both play {query} (with
query = "my favorites") and the literal play my favorites — and the literal
one wins because it has zero placeholders.
#Tips & gotchas
- Put a literal after a mid-phrase placeholder. A placeholder needs a following literal word to know where to stop. If you want to capture "the rest of the sentence," make the placeholder the last token.
- Avoid two placeholders in a row.
{a} {b}has no literal between them to split on. Separate them with a word:from {a} to {b}. - List natural variations. Give each action several phrasings
(
set volume to {x},change volume to {x},turn the volume to {x}) so real users actually hit them. - Case and punctuation don't matter — they're normalized away — so don't rely on them to disambiguate.
Next: Packaging & Distributing to get your pack onto other people's machines.