OptionalcardinalityCardinality constraint for objects fields. Ignored on other
field types. Defaults to { min: 0, max: Infinity }.
OptionaldefaultValue the matcher fills when the player provides no input for
this field. The default runs through shell-side variable
interpolation just like player-typed text — default: "$focus"
resolves to the giver's current focus at bind time.
required: true + default: is allowed: the default replaces
the missing input, no shape error. The "missing required arg"
message only fires when the field is required AND has no
default AND the player supplied nothing.
OptionalgreedyGreedy positional: consumes the remainder of the original input verbatim (whitespace preserved, escapes processed, quotes literal). Must be the last positional in its block.
OptionalmultipleOptionalonPolicy when MQL resolves too many results.
'object' field default: 'top' (preserves pre-cardinality
behavior; pick the highest-scored match).'objects' field default: 'prompt' if cardinality.max is
set, 'take-all' otherwise.'top' and 'take-all' are mutually exclusive between field
types (schema validation rejects 'top' on objects,
'take-all' on object, etc.).
OptionalonPolicy when MQL resolves fewer results than cardinality.min.
v1 only value: 'error'. Future values land additively.
OptionalprepositionsOptional list of prepositions the matcher will consume as a
leading boundary marker for this positional field. Lowercased.
Typing look at flower against prepositions: [at] consumes
the at and binds target = "flower"; typing look flower
binds target = "flower" directly. The consumed preposition
lands on ctx.prep[fieldName].
For multi-field commands, later fields' declared prepositions
also serve as termination boundaries for an earlier greedy
field — give the red flower to bob splits correctly because
recipient: prepositions: [to] tells the matcher to stop the
greedy gift at to.
Prepositions are always optional: declaring prepositions: [to]
means "consume to if it appears here," not "require to."
OptionalrequiredOptionalschemaOptional JSON Schema fragment for type: 'struct' fields. Run
by ajv during the structured-input coercion step; failure yields
a friendly error pointing at the offending property.
OptionalscopeMQL scope fragment(s) the dispatcher tries when resolving this
field. Each fragment runs through ShellApi.expandVariables
(so $focus / stored vars expand at resolve time) and is tried
in order; first non-empty result wins.
The YAML/spec record accepts string | string[]. After
CommandDefinition construction, the runtime value is always
string[] | undefined — normaliseShape coerces a bare string
into a singleton array, so consumers don't have to branch.
The array form is the explicit fallback chain — a verb that
wants drill-first-then-broad declares
scope: ['$focus', 'reachable'] so a drilled player searches
the focus first with the room as fallback. Verbs that should
ignore drill declare a non-$focus fragment (e.g.
scope: 'inventory' for drop, scope: 'peers' for get).
Default when omitted: ['$focus'] — the drill chain IS the
scope. The resolver's empty-scope fallback to reachable
stays as the safety net for when the focus chain stops resolving
(typically after movement into a different room). Only
meaningful for type: object / type: objects fields.
Optionaltypestring / number / boolean — primitive coerce-on-bind.object — singular MQL field; the dispatcher resolves the
bound text via MqlApi.resolveOne (when onExcess: 'top') or
MqlApi.resolveMany (otherwise — full list needed for
counting / prompting). Implicit cardinality { exactly: 1 }.objects — plural MQL field; the dispatcher resolves via
MqlApi.resolveMany. multiple: true is NOT used for MQL
fields — the cardinality is the type plus the optional
cardinality knob.struct — structured-input-only blob (Record<string, unknown>).
Cannot be bound from text — msh returns a clear error if a
verb's positional or option of this type appears in tokenised
input. Used by widget/editor clients via
assembleFromStructured. Validated against the optional
schema (JSON Schema) before user-defined validators fire.Optionalupdates_Focus management policy for this field. Three modes:
extend — append the post-desugar input fragment to the
giver's current focus with : as the separator. With
same-anchor + via.detailPath compaction (re-resolving the
same target doesn't double-add). The drill-additive default
for inspection-shaped verbs (look, examine, read,
open, close).
replace — set focus to the post-desugar input fragment
wholesale. For navigation/anchoring verbs that should reset
the trail rather than extend it.
none (default) — focus unchanged. Most commands (get,
drop, say) don't manage focus.
Pronoun substitution applies in all extending paths: when raw
is itself a pronoun (it/him/her/them/$$), the stored
fragment from pronoun memory replaces the literal pronoun string
before the focus is updated, so the trail tracks the actual
referent rather than the unstable pronoun.
Empty resolutions never touch focus regardless of mode — the resolveAndValidate gate is "if resolved.stuff is non-null".
Renamed from the v1 updates_scope?: boolean field — the field
manages focus, not scope. The boolean's true setting is
equivalent to 'extend' under the new drill-additive default.
Optionalvalidators
Positional argument definition — appears in YAML's
args:array for syntax variants and subcommands. The array's index IS the positional slot number;namebecomes the model field key the bound value lands on.