- name
- file-system-object
- description
- The grammar rules that make MOOLLM's file system object-oriented. Plural directory names declare element type; UPPERCASE marker files declare interface exports (COM-style, minus the UUIDs); directories are implementation classes exporting every interface whose marker file sits at their root.
- license
- MIT
- tier
- 1
- allowed-tools
- ["read_file","write_file"]
- related
- ["skill","prototype","card","schema","self","com-xpcom","yaml-jazz","room"]
- tags
- ["moollm","meta","grammar","object-oriented","com","self","filesystem","directories","markers"]
- credits
- ["Smalltalk (Alan Kay et al., Xerox PARC, 1970s) — classes, messages, image-as-object","Self (Ungar & Smith, 1987) — prototype delegation; objects without classes","NeWS (James Gosling & David S. H. Rosenthal, Sun, 1986) — PostScript window system with prototype delegation in production","TNT: The NeWS Toolkit (Owen Densmore & David S. H. Rosenthal, Sun) — class hierarchy built on NeWS's prototype foundation; the patent and the conceptual ancestor","COM / XPCOM — multiple interfaces per class; QueryInterface","Ted Nelson — intertwingled systems; every node can link anywhere","MOOLLM — the actually-existing MOOLLM file system, already using this grammar before it was named"]
# File System as Object — Directories, Interfaces, and the UPPERCASE Marker Grammar
> **"A directory named `<things>/` is saying: the things in here are of the type `<thing>`. A file named `FOO.md` at a directory's root is saying: this directory exports the FOO interface. The directory IS an implementation class; the UPPERCASE marker files ARE its interface declarations; no UUIDs needed because the filename IS the class name."**
This skill formalizes a grammar that **already exists throughout MOOLLM**. Every skill you've read — `skill`, `prototype`, `card`, `schema`, `adventure`, `room`, `character`, `incarnation` — uses these rules implicitly. The other meta-skills USE the grammar; this skill NAMES it so newcomers (human or LLM) can read MOOLLM directory trees fluently without pattern-matching each one from scratch.
---
## The Three Rules
### Rule 1: Plural-named directories declare element type
A directory named `<things>/` declares "the things in here are of type `<thing>`."
```
skills/ → each child is (presumably) a skill
biomes/ → each child is a biome
mechanisms/ → each child is a schema mechanism
recipes/ → each file is a recipe
gotchas/ → each file is a gotcha
runbooks/ → each file is a runbook
instances/ → each child is an instance
stacks/ → each child is a stack
protocols/ → each file is a protocol
rooms/ → each child is a room
characters/ → each child is a character
```
"Presumably" is doing real work here: the plural name is a **declaration of intent**. To confirm a specific child actually IS of that type, look for its **interface marker file** (see Rule 3). Auxiliary content (templates, indexes, READMEs) can also live in a plural container without being instances — their absence of a marker file is the tell.
### Rule 2: Singular-named directories are instances
A directory named `<thing>/` (singular, kebab-case or single word) is an **instance**. The directory name is the instance's identifier.
```
skills/skill/ → instance named "skill" (a specific skill, happens to BE the meta-skill about skills)
skills/biome/ → instance named "biome"
skills/gcs/ → instance named "gcs"
mechanisms/json-schema/ → instance named "json-schema"
instances/leela-zion2-dev-0/ → instance named "leela-zion2-dev-0"
```
This reads as: `<plural-container>/<instance-id>/`.
### Rule 3: UPPERCASE marker files declare interface exports
A file named `FOO.md` or `FOO.yml` (UPPERCASE filename) at a directory's root declares that the directory **EXPORTS the FOO interface**.
```
skills/gcs/
├── SKILL.md ← "I export the SKILL interface"
├── CARD.yml ← "I export the CARD interface"
├── GLANCE.yml ← "I export the GLANCE interface"
├── README.md ← "I export the README interface (human landing)"
├── recipes/ ← plural: "I contain recipes"
├── gotchas/ ← plural: "I contain gotchas"
└── ...
```
The UPPERCASE convention visually distinguishes **interface declarations** from ordinary content. The presence of the file IS the declaration — no separate registry required.
**One directory exports many interfaces.** Just like a COM class implements many interfaces, a MOOLLM skill directory typically exports SKILL + CARD + GLANCE + README + sometimes CHARACTER + EXPORTS + PROTOTYPES — all simultaneously, via multiple marker files.
---
## The COM Analogy
This is Henry's framing, which anchors the whole grammar:
| COM concept | File-system-object equivalent |
|---|---|
| Implementation class (C++ / IDL class) | Directory — the `<thing>/` singular name |
| Interface declaration (IDL `interface IFoo`) | UPPERCASE marker file — `FOO.md` or `FOO.yml` |
| Interface UUID (`IID_IFoo = {01234567-89ab-...}`) | **Not needed** — the filename IS the identifier |
| Multiple interfaces per class | Multiple UPPERCASE marker files per directory |
| `QueryInterface(IID_IFoo, &ptr)` | `cat <dir>/FOO.md` (or "does this dir export FOO?" = `test -e <dir>/FOO.md`) |
| Class factory (`CoCreateInstance`) | Prototype instantiation (see `skill-instantiation-protocol.md`, `delegation-object-protocol.md`) |
| Aggregation (one class delegating to another) | DOP prototype chain via `inherits:` or `PROTOTYPES.yml` |
| TypeLib registry | `schemapedia/registry.yml` (for schema mechanisms); `skills/biome/biomes/registry.yml` (for biomes) |
COM's big wins were: (a) multiple interfaces per implementation, (b) language-neutral contracts, (c) strong versioning via UUIDs. MOOLLM keeps (a) and (b), swaps (c) for **readable UPPERCASE names** because we want humans and LLMs to read the tree, not a binary-stamped registry.
COM's big losses were: opaque UUIDs, fiddly registration, reliance on a global registry, Windows-centric tooling. MOOLLM avoids all four by putting the declarations in the filesystem itself.
---
## Why UPPERCASE
The UPPERCASE-filename convention (`SKILL.md`, `CARD.yml`, `MECHANISM.yml`, `ALERT.yml`, `PROTOTYPES.yml`) does several things at once:
1. **Visual grep.** In any `ls` output, UPPERCASE files leap out. Structural signposts pop; ordinary content recedes.
2. **Class-vs-content distinction.** Lowercase filenames (`camera-configs.json`, `my-recipe.md`) are content; UPPERCASE is meta — "I am telling you what this directory IS."
3. **Namespace cleanliness.** `foo.md` (lowercase) is a note about foo; `FOO.md` (uppercase) is a declaration that this directory implements FOO. They don't collide, and their roles are clear at a glance.
4. **Future-proof tooling.** A validator script can simply glob for `[A-Z]*.{md,yml}` at a directory root to find all exported interfaces. No manifest file, no parsing.
5. **Big-endian naming.** The UPPERCASE prefix groups structural files together alphabetically at the top of `ls` output.
**When NOT to use uppercase.** Normal content, per-instance data (`state.yml`, `history.md`), templates (`RUN.yml.tmpl` — the `.tmpl` is the tell that it's a template, not a declaration), ordinary documentation (`troubleshooting.md`).
---
## Serialization — YAML Preferred, JSON Welcome, Comments Encouraged
Interface marker files come in three flavors, each picked on purpose:
| Extension | Use when | Why |
|---|---|---|
| `.yml` | The interface is **data-shaped** (fields, structure, lists). Default choice. | Comments are first-class and **encouraged** (see [`yaml-jazz`](../yaml-jazz/)). The same file can carry structure, semantic hints, lineage notes, and authorial voice simultaneously. |
| `.md` | The interface is **narrative** (explains, teaches, guides). | Markdown supports prose + structure + code blocks. `SKILL.md`, `README.md` are the canonical narrative interfaces. |
| `.json` | **A downstream tool needs it** (jq pipelines, ajv validators, frontend code reading an API) and no human is expected to author it by hand. | Universal tool support. Smaller parser footprint. But: no comments → strips human intent. |
**The rule: YAML is preferred, JSON is welcome, comments are encouraged.**
### When to prefer which
- **Authoring by hand?** → YAML. Every time.
- **Tool reads it, humans rarely?** → JSON is fine.
- **Both?** → YAML is canonical; emit JSON on a hook if needed.
- **Narrative / teaching / guiding?** → Markdown.
### Why YAML over JSON for MOOLLM interface declarations
YAML gives us three-audiences support (humans, LLMs, machines — see the `yaml-jazz` skill):
```yaml
# CARD.yml — this is a comment — it carries semantic information for
# humans AND LLMs, even though machines technically ignore it.
card:
id: example
tagline: "The tagline is the elevator pitch."
# ↑ Next audience note: rule-of-thumb is one sentence, present tense.
```
Strip the comments and you have the same data. Keep them and you have **intent** alongside the data — why the fields are there, what alternatives we considered, which examples are load-bearing. That's the yaml-jazz difference, and it's why every UPPERCASE marker file in MOOLLM defaults to YAML.
### Canonical patterns observed in MOOLLM
| Pattern | Example | Notes |
|---|---|---|
| Data-shaped interface | `CARD.yml`, `GLANCE.yml`, `MECHANISM.yml`, `ALERT.yml`, `CHARACTER.yml`, `PROTOTYPES.yml`, `EXPORTS.yml` | YAML. Comments throughout. |
| Narrative interface | `SKILL.md`, `README.md`, `CHANGELOG.md` | Markdown with YAML frontmatter. |
| Generated-for-tool interface | rare in MOOLLM proper; common in build outputs | `.json` next to `.yml` canonical, regenerated on change. |
| Template interfaces | `CARD.yml.tmpl`, `SKILL.md.tmpl` | `.tmpl` suffix signals placeholder content; not a real declaration. |
If you're introducing a new UPPERCASE interface type and you have to choose: `FOO.yml` is the default. Reach for `.md` if the content is prose-heavy; reach for `.json` only when a tool demands it.
### The yaml-jazz skill is a hard dependency
This skill inherits conceptually from [`yaml-jazz`](../yaml-jazz/): "Semantic YAML — comments as data; three audiences." The two skills together give MOOLLM its **authoring grammar**:
- `file-system-object` says: directories are classes, UPPERCASE files are interfaces.
- `yaml-jazz` says: inside those interface files, comments are first-class semantic carriers.
Together they turn an `ls` + `cat` session into a legitimate class browsing experience.
---
## Nesting — Sub-skills and Categorization
Following the grammar, a directory can nest further plurals inside itself:
```
skills/biome/ ← singular (instance of skill type)
├── SKILL.md ← exports SKILL interface
├── CARD.yml ← exports CARD interface
├── biomes/ ← plural: "this skill contains biomes"
│ ├── registry.yml ← (not UPPERCASE — data, not interface)
│ ├── gateways.yml ← (not UPPERCASE — data, not interface)
│ ├── convention.yml ← (not UPPERCASE — data, not interface)
│ └── families.yml ← (not UPPERCASE — data, not interface)
└── templates/
└── BIOME/ ← the template IS named UPPERCASE because it's a TYPE template
├── SKILL.md.tmpl
├── CARD.yml.tmpl
└── ...
```
A skill can also contain sub-skills:
```
skills/parent-skill/
├── SKILL.md
├── CARD.yml
└── skills/ ← plural: sub-skills live here
└── child-skill/
├── SKILL.md
└── CARD.yml
```
And so on recursively. The grammar holds at any depth.
### Skills as categories
When a skill contains a `skills/` subdirectory, the parent skill plays two roles at once:
1. **It's still a skill itself** (via its own `SKILL.md` / `CARD.yml`).
2. **It's also a CATEGORY** for the sub-skills — the parent directory name is the category name; its child skills belong to that category by virtue of their path.
```
skills/gardening/ ← the gardening skill AND the gardening category
├── SKILL.md ← the parent skill's full protocol
├── CARD.yml
└── skills/ ← sub-skills (i.e., members of the gardening category)
├── composting/
│ ├── SKILL.md
│ └── CARD.yml
├── pruning/
│ ├── SKILL.md
│ └── CARD.yml
└── seed-starting/
└── SKILL.md
```
No separate "category" concept is needed — **the parent skill IS the category**. A sub-skill participates in the category simply by living under `skills/<parent>/skills/<child>/`. Cross-category sub-skills (a skill that belongs to two categories) are handled by DOP inheritance, not by duplicating directories: `child-skill` lives in one canonical path, and other categories reference it via `inherits:` chains.
**When to nest vs flatten.** Put a skill under a parent when:
- It's only meaningful inside the parent's context (e.g., `biome`'s `biomes/` stubs — each stub is only a reference biome for this mother skill).
- It's a sub-concern of the parent that isn't reused elsewhere yet.
Pull it up to a top-level skill (lift it) when:
- It becomes reusable across unrelated contexts.
- Other skills start wanting to inherit from it.
- Its audience broadens beyond users of the parent skill.
This is the same PLAY-LEARN-LIFT arc applied to skill hierarchy: sub-skills start nested (low-cost), get promoted when they earn independence.
---
## Skill Lookup and Inheritance Through Tree Containment
When one skill references another — via `inherits:`, `related:`, or a prose mention — the reference can take two forms:
| Form | Example | When to use |
|---|---|---|
| **Bare name** | `inherits: [biome]` | Most authoring. Short, Postel-friendly, resolver-driven. |
| **Unambiguous path fragment** | `see: moollm/skills/biome/SKILL.md` | When you need to disambiguate, cross-repo-reference, or help a reader find the exact file. |
Both are valid. MOOLLM's resolver is expected to accept either and find the right skill, following Postel's robustness principle: **be liberal in what you accept, conservative in what you emit**. When authoring by hand, reach for the unambiguous form when you easily can; reach for the bare name when the context makes it obvious.
### What counts as a skill — duck typing on marker files
A directory participates in the MOOLLM object system to the extent its UPPERCASE marker files say it does. There are **three distinct levels of participation**, and a directory can sit at any of them:
| Level | Minimum markers | What works | What doesn't |
|---|---|---|---|
| 📜 **Full skill** | `SKILL.md` + `CARD.yml` (+ usually `GLANCE.yml`, `README.md`) | Everything: dispatch, narrative, semantic-image-pyramid reading, ambient inheritance when contained | — |
| 📇 **Dispatchable object** | **`CARD.yml` alone** | Dispatch: **methods, advertisements, k-lines, state, navigation all work**. `queryInterface(dir, 'card')` returns the sniffable interface. Inheritance declared in CARD.yml's `inherits:` chain resolves normally. | No narrative/protocol doc; no `SKILL.md`-level reading-order entry point (GLANCE → CARD → SKILL → README collapses to GLANCE → CARD) |
| 🦆 **Scope-declared** | `skills/<name>/` container (or `biomes/<name>/`, `characters/<name>/`, etc.) declares the TYPE of the directory | Type-level discovery works (enumeration recognizes it as of the plural's type); becomes dispatchable the moment a CARD.yml appears | Without CARD or SKILL, there's nothing to dispatch yet — it's a stub, not an error |
**A CARD-only directory is a first-class object.** It isn't a "degraded skill" — it's a **lightweight form** for when narrative isn't warranted. A directory with just `CARD.yml` can still:
- Be invoked via its `methods:` block
- Advertise capabilities via `advertisements:`
- Activate k-lines via `k_lines:`
- Declare inheritance via `inherits:` (resolver walks the chain the same way)
- Participate in DOP delegation
- Be the target of `related:` from other skills
```
skills/my-thing/ ← dispatches just fine
└── CARD.yml ← this alone carries methods, ads, k-lines, navigation
← queryInterface(., 'card') → CARD.yml
← queryInterface(., 'skill') → null (no SKILL.md — that's OK)
```
This matters because it removes a friction: you don't need to write a 300-line SKILL.md just to make something dispatchable. Write the CARD when you have methods to declare; write the SKILL when you have a protocol to teach. The two files answer different questions (*"what can this DO?"* vs *"how does this WORK?"*), and not every object needs a teaching narrative.
> 🦆 **Quack-quack duck typing** — a directory is an object to the degree its marker files quack. `SKILL.md` is the full orchestra; `CARD.yml` is a solid string quartet; `skills/<dir>/` with no markers is a stage with a name on it. All three are legitimate; each does a different amount of work.
Any additional UPPERCASE marker file adds another interface: `CHARACTER.yml` makes it incarnation-ready; `MECHANISM.yml` registers it with schemapedia; `ALERT.yml` makes it a branch-as-object alert. The directory exports all of them simultaneously, in classic COM-style multiple-interface fashion.
> 🎴 **The CARD is a rich pun.** `CARD.yml` names a surface that is — *simultaneously* — an interface definition (IDL / OLE Control / ActiveX TypeLib), a **HyperCard** (Atkinson-style navigable unit with fields/buttons/scripts), an **actor** (Hewitt-style message-receiver with local state), a **thread** (a dispatchable unit of control), a **message dispatching surface** (Smalltalk/Self-style), and a **portable token** (trading card + business card). The richness is load-bearing; see [`skills/card/SKILL.md` § "The Card Pun Stack"](../card/SKILL.md#the-card-pun-stack--what-a-card-is) for the full lineage.
### The lookup scope — two searches, one upward walk
A bare reference like `inherits: [biome]` is resolved by walking **outward** from the referring skill's location. The walk performs **two independent searches** at every level. Both use the same parent-walking loop; they return different things.
```
referring_skill_dir/
↑ up one level
referring_skill_dir's parent/
↑ up one level
...
```
At each step, check two things:
#### Search 1 — scoped `skills/` directory at this level
View on GitHub