Blank shapes are the trigger grammar underneath every keyword blank: anchored patterns matched against the sentence your _ ends, deciding deterministically which blank claims it and with what action. They're why volume _ fires and prose that merely mentions volume never does.
The shape of a shape
A shape is a small object: a pattern (a regex matched case-insensitively against the sentence containing the _), an action (get, set, or step), and optionally a valueGroup naming the capture group that extracts a value. So {"pattern": "^volume\s+(\d+)\s*_$", "action": "set", "valueGroup": 1} makes volume 40 _ a set-to-40 command. The "sentence" is the segment after the last sentence terminator or newline before the _, so let me check. volume _ routes the same as volume _ on its own line.
You usually never write one
Most blanks declare blankKeywords instead, and keywords desugar into shapes automatically: a keyword claims a _ when it leads the sentence, capturing any words between the keyword and the _ as the argument, and a declared blankStep adds set and step shapes for free. Explicit blankShapes are the escape hatch when the synthesized grammar isn't precise enough. A blank with explicit shapes is routed solely by them.
Why anchored grammar matters
- Deterministic routing: the first matching shape claims the
_; no LLM in the routing decision. - No accidental fires: the command must lead its sentence with the
_at the trailing edge, so mid-sentence mentions of a keyword are inert. - Shape-derived clearing: a shape with a captured argument or a set action consumes its whole command span on fill, which is why
weather oslo _leaves justOslo: 13°C Overcastbehind.
The full grammar is part of the blank spec in the open standard.
Related: What is a blank? · Why is my blank not firing? · The open standard · GitHub repo