| name | container |
| description | Intermediate scope for inheritance — like OpenLaszlo's <node> |
| license | MIT |
| tier | 1 |
| allowed-tools | ["read_file","write_file"] |
| related | ["room","object","adventure","prototype","logistic-container"] |
| tags | ["moollm","scope","inheritance","hierarchy","composition"] |
Container
Intermediate scopes that provide inheritance without being navigable rooms.
Containers are directories that define shared properties for their children,
without themselves being places you can "go to."
The OpenLaszlo Inspiration
In OpenLaszlo (Don Hopkins' earlier work!), <node> was a fundamental building block:
<node name="mazeDefaults">
<attribute name="isDark" value="true"/>
<attribute name="hasDanger" value="true"/>
</node>
<view extends="mazeDefaults">
</view>
MOOLLM's CONTAINER.yml does the same for adventure directories:
container:
name: "The Twisty Maze"
inherits:
is_dark: true
is_dangerous: true
grue_rules:
can_appear: true
All rooms inside maze/ automatically inherit these properties!
Container vs Room vs Meta
| Type | File | Navigable? | Inherits to children? |
|---|
| Room | ROOM.yml | ✅ Yes | ❌ No |
| Container | CONTAINER.yml | ❌ No | ✅ Yes |
| Meta | .meta.yml | ❌ No | ❌ No (just metadata) |
Use Container when:
- You want to define shared properties
- Children should inherit automatically
- The directory itself is not a place
Use Room when:
- The directory is a navigable location
- It has exits and can be entered
Use .meta.yml when:
- Just declaring "this is a system directory"
- No inheritance needed
Inheritance Rules
Cascade Down
Properties in inherits: flow to ALL descendants:
maze/
├── CONTAINER.yml # inherits: { is_dark: true }
├── room-a/
│ └── ROOM.yml # Inherits is_dark: true
├── room-b/
│ └── ROOM.yml # Inherits is_dark: true
└── deep/
└── CONTAINER.yml # Can add MORE inherits
└── room-c/
└── ROOM.yml # Inherits from BOTH containers!
Override by Redefining
Children can override inherited values:
room:
name: "The Treasure Chamber"
is_dark: false
Merge, Don't Replace
For objects and arrays, inheritance MERGES:
container:
inherits:
rules:
- "Grues patrol in darkness"
room:
rules:
- "This room has a pit trap"
Result: room-g has BOTH rules.
Defaults vs Inherits
| Field | Purpose |
|---|
inherits | Properties that children GET automatically |
defaults | Values to use IF a child doesn't define them |
container:
inherits:
is_dark: true
defaults:
room:
atmosphere: "damp and musty"
Use Cases
Maze with Grue Rules
container:
name: "The Twisty Maze"
description: "Passages all alike... or are they?"
inherits:
is_dark: true
is_dangerous: true
grue_rules:
can_appear: true
safe_with_light: true
rules:
- "No teleportation"
- "Breadcrumbs disappear after 3 turns"
- "Echoes alert nearby rooms"
ambient:
sound: "dripping water"
smell: "wet stone"
temperature: cold
Animal Character Category
container:
name: "Animal Characters"
description: "Non-human beings with souls"
inherits:
type: animal
has_instincts: true
defaults:
character:
can_speak_human: false
pet_able: true
diet: omnivore
Kitchen Appliances
container:
name: "Kitchen Appliances"
inherits:
type: appliance
requires_power: true
defaults:
object:
breakable: true
fixable_with: "wrench"
Resolution Order
When looking up a property:
- Self — Check the object/room itself
- Parent Container — Check
CONTAINER.yml in parent dir
- Grandparent Container — Keep going up
- Adventure Defaults —
ADVENTURE.yml defaults
- Prototype — The skill template
maze/deep/room-c/ROOM.yml
↓ inherits from
maze/deep/CONTAINER.yml
↓ inherits from
maze/CONTAINER.yml
↓ inherits from
ADVENTURE.yml (if it has defaults)
↓ inherits from
skills/room/ROOM.yml.tmpl
Linter Behavior
The linter recognizes CONTAINER.yml:
📂 Phase 1: Discovery
Found: 36 rooms, 54 objects, 6 characters
Found: 2 containers
Containers suppress the "missing type declaration" warning:
⚠️ Directory has room children but no ROOM.yml
✅ maze/ is a container (not a room)
Related Patterns
- Prototype Inheritance (Self/JavaScript) — Objects inherit from prototypes
- Lexical Scope (Lisp/JavaScript) — Inner scopes access outer variables
- Cascading (CSS) — Styles flow from parent to child
- XML Namespaces — Context flows through the tree
Credits
- OpenLaszlo — The
<node> element as non-visual scope
- Self — Prototype inheritance without classes
- CSS — The cascade as inheritance mechanism
- Don Hopkins — For remembering OpenLaszlo! 🎉