Guide
Three things you author, in one file per level, lw.manifest.json. Everything else is computed. The file is checked when it loads, never at runtime.
One sentence in plain English becomes temperament and an archetype: guard, owner, elder, child, drifter. The archetype sets defaults for what they reach for; the sentence is written once and never re-read by a model.
"characters": { "Hulda": { "persona": "Innkeeper of the Bannered Mare. Proud of her prices, quick to bar a thief." } }
canA narrowing of the level's verbs. Anything not listed is impossible for that character, permanently: not under fear, not under an order, not inside a plan, not from a scene.
"verbs": [ { "name": "greet" }, { "name": "serve" }, { "name": "report" }, { "name": "refuse_service" }, { "name": "confront" }, { "name": "watch" }, { "name": "say" } ],
"characters": { "Hulda": { "can": ["greet", "serve", "report", "refuse_service", "watch", "say"] } }
Hulda cannot confront, ever, because it is not in her list. A can that names a verb the level does not have is a load error, not a silent grant. No can at all means the archetype's default, and the load report says what was assumed.
neverRules over four namespaces: self., target., place., slice.. Grammar: and, or, not, parentheses, comparisons. A field your feed does not supply makes the rule false; a rule can never fire on a guess.
"never": [
{ "verb": "confront", "when": "target.isChild", "name": "no-confronting-children" },
{ "verb": "draw", "when": "place.temple", "name": "no-steel-in-the-temple" },
{ "verb": "leave_post", "when": "slice.morning or slice.noon", "name": "shop-hours" }
]
"places": { "temple": { "loctypes": ["temple"] }, "street": { "default": true } }
loctypes matches every temple in the game in one line. interior and exterior are built in. The full field list is in Manifest.
lw dev --mock loads the manifest and prints the load report. python -m pipeline.verb_manifest --check lw.manifest.json does the same without starting anything.