Build with your AI agent

What pitch init leaves in a repository for the agent building the demo.

On this page

Demos are often built by an AI coding agent: Claude Code, Cursor, Codex, Copilot, or another agent working in your repository. What pitch init leaves behind is written for that agent as much as for you. This page covers the files it writes, the guide it leaves for the agent, how an agent can run pitch with nobody at the terminal, and how it checks its own work against the contract before anything is deployed.

What pitch init leaves

pitch init writes three files at the root of the demo: pitch.json, pitch.README.md and PITCH.md. It adds one line to AGENTS.md and CLAUDE.md pointing at PITCH.md, and changes nothing else. It never edits your code, and never replaces any of the three files unless you pass --force; with one already there it stops and says so.

  Wrote pitch.json (1 app, static) and pitch.README.md, which explains it and shows a story's shape.
  Wrote PITCH.md, the guide for a coding agent: the rules, the build contract and the loop.
  Added one line to the end of CLAUDE.md, pointing at PITCH.md. Nothing else in it changed.

pitch.json

The manifest: what the build is, the apps in it and the device each is for, its health route and demo controls, and the pages beside it. Its first line names the schema it follows:

{
  "$schema": "https://getroomi.com/schema/pitch.json",
  "name": "Columbus",
  "kind": "static",
  "output": ".next-build",
  "apps": [{ "id": "app", "name": "Columbus", "path": "/", "device": "laptop" }]
}

The schema is generated from the same definition the CLI and the platform check the file with, and every field in it carries a description of what it is for. An agent, or an editor, that reads $schema can complete and check the file without running anything. pitch.json has every field.

pitch.README.md

The notes JSON cannot carry, in three sections:

  • What it found: the kind of build, a table of the apps with their paths and the device each is framed as, one line for each thing it read and where, and a Not written: line for anything it saw and chose not to guess, such as a demo route that reads a body.
  • Add a story: the shape of a guided tour on the build's own apps, as a story block that validates as it stands, with every word a placeholder to replace. On a container build where it found a scenario route, the example's second step runs it.
  • Then: pitch validate, pitch deploy and pitch deploy --commit, and what each does.

Nothing reads pitch.README.md. It is there to be read, by you or by the agent that writes the tour, and deleted whenever you like.

PITCH.md

The guide for the coding agent working in the repository, and for the person it works with. It is the same whatever the demo, and it is drawn from these docs when pitch init runs, so it says what they say:

  • What Roomi is, in three sentences.
  • Rules that do not bend: mock data only, no secrets, no real client names needed, nothing published without your yes, and change only what it was asked to (anything beyond pitch.json and the story is shown to you as a diff first).
  • The loop: edit, pitch validate, pitch deploy to rehearse, show you the rehearsal's own output, and pitch deploy --commit only on your yes.
  • Static or container, and the container build contract, copied from the Container demos page.
  • pitch.json: a static and a container example, and every field as the schema describes it.
  • The story: its shape and how to write one, copied from Writing the tour.
  • Pages, after publishing (pitch link, and pitch link copy when one is lost), and where each rule is written down on this site.

It tells the agent never to sign in for you and never to print a token: if pitch says nobody is signed in, you run pitch login yourself.

AGENTS.md and CLAUDE.md

Coding agents read AGENTS.md (most of them) or CLAUDE.md (Claude Code) when they start work in a repository. pitch init adds this line to the end of each one there, so the agent finds the guide:

Deploying this demo to Roomi? Read [PITCH.md](PITCH.md) first: the rules, the build contract and the loop.

A file that already mentions PITCH.md is left exactly as it was. With neither file in the repository, pitch init makes an AGENTS.md holding that one line. Nothing else in either file is touched, and pitch init --print shows the line it would add, and where, without writing anything.

Keeping PITCH.md current

PITCH.md is a copy of the docs as they were when pitch init ran. To bring it up to date, without touching pitch.json, pitch.README.md or anything else:

pitch init --update
  Rewrote PITCH.md from the docs as they are now. Nothing else was touched.

If it is already current, it says so and writes nothing. With --print it shows the guide instead of writing it.

Running pitch with nobody at the terminal

Every question pitch init could ask has a flag that answers it. With nobody at the terminal and no flag, it does not guess: it stops, writes nothing, and names the flag.

  Could not tell, and there is nobody to ask:
    Which device is "Columbus" (/) for?  --device app=<phone|tablet|laptop|screen|none>
  Nothing was written.

So an agent can run it, relay the question to you, and run it again with your answer. For Columbus the answer takes two flags, because its build writes to a folder pitch init cannot see (Static demos):

pitch init --device app=laptop --output .next-build

The flags are --kind container|static, --output <dir>, --health <path> and --device <app>=<device>, once per app. --yes takes the suggested default wherever there is one. pitch init --print shows what would be written, and writes nothing.

A repository whose apps each run on their own dev port is not deployable as it stands, because a room loads one origin. pitch init says so, describes the change to one server, and writes nothing; it is for you, or your agent with your agreement, to make. Container demos describes it.

Checking its own work

pitch validate checks pitch.json and the story against the contract without building or sending anything. Every problem names the field, says what is wrong, and gives the address of the docs entry that explains it:

  pitch.json does not validate: 1 problem
    story[1].app: step "rush" happens in app "kitchn", which apps does not declare
      https://getroomi.com/docs/pitch-json#field-story-app

A field it does not know is a problem too, with the nearest one it does know, because the platform would ignore it and a misspelt field would be a setting that silently does nothing:

  pitch.json does not validate: 1 problem
    stroy: pitch does not know this field (did you mean "story"?); the platform would ignore it
      https://getroomi.com/docs/pitch-json
  note story: there is none, so the room offers no guided tour. A viewer meets the demo without a word from you
         https://getroomi.com/docs/story

pitch deploy without --commit is the next check, and it is safe for an agent to run: nothing leaves the machine. It builds the demo and scans it for secrets. A container build it also runs on the platform's own runner, and runs each step of the tour on that copy; a step that fails there fails the rehearsal, so an agent that writes a tour can prove it works before you see it. Then it shows what would go live.

pitch deploy --commit is the step that publishes. An agent should run it only when you have seen the rehearsal and said yes; the Claude Code skill holds to that as a rule.

What keeps a demo deployable

Whatever builds the demo, these are what pitch validate and the rehearsal hold it to:

  • Mock data only. Every rehearsal scans the project and the build for secrets, and a finding stops the deploy.
  • One origin. Every app is served by one server, each under its own path.
  • A container build keeps the build contract: a Dockerfile whose last stage builds in /app on Node 24, a CMD that starts it, a server on PORT, and a health route. Container demos has the whole contract.
  • Demo routes answer JSON with a message, which the room shows the viewer in your words.
  • A tour step sets up what it needs itself, so a viewer can start at any step. Writing the tour says how.

With Claude Code

Claude Code reads CLAUDE.md, so after pitch init it finds PITCH.md on its own. The Claude Code plugin's skill goes further and drives all of this for you: it runs pitch init, relays its questions, drafts the tour, validates, rehearses and asks before publishing. Deploying from Claude describes it.

With Claude in chat

Claude in claude.ai or the Claude app works through the connector, with no terminal and no repository, so it never reads a PITCH.md. The connector gives it the same guide instead: a short version in the instructions it reads when it connects, and the whole of it from the deploy_guide tool, drawn from the same sources as PITCH.md with the connector's tools in place of pitch commands. check_bundle then checks its demo as pitch validate checks yours, and names every problem with its fix. Deploying from Claude describes it.