---
name: gm-spaces
description: Write a room or a drop for GM Spaces in gm-code. Fetches the live vocabulary instead of trusting this file, and has the platform check the document before anybody saves it.
---

# Building in GM Spaces

GM Spaces rooms and drop cards are written in **gm-code**: a small flat
language of `<gm-*>` blocks. This file teaches you how to work in it. It
deliberately does not teach you the words.

## When to load

Load this when the job is to write or edit a **room** (somebody's page in
GM Spaces) or a **drop spine** (the card a drop wears on the map), in gm-code.

Do not load it to operate the app. There is no public write API. You produce a
document; a person pastes or saves it.

## Inputs

- **Whose room or what drop.** A name, and what they do or what the thing is.
- **The one job the page has.** What should a stranger do after reading it.
- **Anything real to put in it.** A line they already say, an address, a link.
  Invented facts are the failure mode here, not bad markup.

If the second one is missing, ask for it before writing. A room with no job is
where generated pages go to look generic.

## Steps

1. **Fetch the language. Every time.**

   ```
   GET https://app.gmcarl.xyz/api/gmcode?as=text
   ```

   That returns the law, the block words, what each door actually does, the
   verbs that are **deliberately not built**, and the tones, boxes and motion
   values. It is generated from the tables the renderer dispatches on, so it is
   the language as it is today, not as it was when this file was written.

   Do not skip this because you remember the words. This file has no word list
   on purpose, and the reason is in step 5.

2. **Write the document.** Flat: no block contains another. Placement and
   layout are attributes, not nesting. Open with what the page is, put the one
   job in a door, and stop.

3. **Have the platform check it.**

   ```
   POST https://app.gmcarl.xyz/api/gmcode
   {"code": "<gm-room>…</gm-room>"}
   ```

   It answers `{clean: true}` or a list of problems in the platform's own
   words. This is the same refusal the app gives at save, so a clean answer
   here means it will save.

4. **Fix and re-check until clean.** Do not hand over a document that has not
   come back clean. "It looks right" is not a check.

5. **Never copy the vocabulary into your output, your notes, or this file.**
   Point at the endpoint instead. This is not style. The app carries the scar:
   a hand-written list of blocks in its own docs went stale and was missing
   four real block types, so a model reading it refused to build rooms the app
   could already draw. A list you copy is a list that will be wrong, and it
   will be wrong silently.

## Checks

- The document came back `clean: true` from the check endpoint. Quote the
  response rather than asserting it passed.
- **Every `does=` is a real verb.** The catalogue names the ones that are not
  built and why. `rsvp`, `buy`, `join` and `tally` are the ones a writer
  reaches for first, and they are refused by name.
- **Nothing is nested.** One block never contains another.
- **Every fact in the document came from the person.** No invented hours, no
  invented address, no invented quote. If you needed a line and were not given
  one, leave the block out and say which one you left out.
- **The page has one job**, and a reader can find it without scrolling past
  three cards of atmosphere.

## Done when

The check endpoint returns clean, every door is a verb the platform performs,
and you can name in one sentence what the page asks a stranger to do. Hand
over the gm-code and the check response together.

## Install

Save as `SKILL.md` in your harness's skills directory, one folder per skill:

```
.agents/skills/gm-spaces/SKILL.md      # or .claude/skills/, per your harness
```

No key, no account. Both endpoints are public and take no auth.

---

*A prompt is a request. A file is a standard. This one is from GM! Carl Studio.
The whole shelf is at gmcarl.xyz/skills.*
