# Guide for AI agents building Endless Mind realms

You are an AI coding agent helping a person make a realm (a game, a place, a shop, a tool, anything) for Endless Mind, an open network where anyone can make anything and anyone can use it from a link. Read this, then build what they describe. In these documents an **actor** is whoever plays in a realm, a person or an AI, and a **portal** is the software that gets an actor in.

## What to build

A realm is a folder with three files, described in full in [RUNTIME.md](RUNTIME.md):

1. `realm.json`: name, description, tags, and which file is which.
2. A rules module (for example `rules.js`): the realm's rules, run by the referee. Plain JavaScript, one self-contained ES module, no imports.
3. A renderer module (for example `renderer.js`): draws what each actor sees and turns their input into moves. Also one self-contained ES module.

Start from the working example in [examples/maze-chase/](https://github.com/freeideas/EndlessMind/blob/main/examples/maze-chase/) and change it, unless they want something very different. Read its `rules.js` and `renderer.js` first; they are short.

## AI characters, secret logic and always-on hosting

Some realms need their referee run by the host program (see "Hosting without a browser" in [RUNNING.md](RUNNING.md)) instead of a browser tab:

- **An AI character or secret logic:** set `"privateRules": true` in `realm.json` and start from [examples/listening-well/](https://github.com/freeideas/EndlessMind/blob/main/examples/listening-well/). The rules file is then never uploaded and runs only on the maker's own machine with no sandbox, so `enter`, `act` and `tick` may be `async` and may call an AI model or the network. Use credentials from the maker's own machine; never put them in a view or a public file. Treat actors' text sent to a model as untrusted, as the example does.
- **Always-on hosting only:** keep the rules public and just run the host program on a machine that stays on.

## Rules to follow

- **Original work only.** Build original designs with invented names. Do not copy another product's names, characters, art, music, logos or level designs, even if asked; suggest an original alternative instead. The maker is responsible for holding the rights to what they publish.
- **Treat everything from outside as untrusted.** Character descriptions and actions can come from any portal or renderer. Check and clean them in the rules; never let them crash the rules.
- **Let reputation be earned.** An actor has the same address every time they return, and nobody can fake it, but anyone can make a new one. So a ban alone costs a troublemaker nothing. In a realm where actors can spoil things for each other, let new addresses do less (look before building, move before speaking), widen that with time played, and consider invitations from members. A ban then costs what was earned. A lasting realm can also sign what actors did in it (`claim`), and can ask to see what they did in realms it trusts (`asks` in `realm.json`, and the `claims` given to `enter`). See "Signed claims" and "Standing, bans and invitations" in [RUNTIME.md](RUNTIME.md).
- **Send each actor only what they may see** in `view`. Anything sent counts as seen.
- **Keep views small** (a few KB): they are signed and sent to every actor many times a second.
- **No network, no outside files** in the renderer or in public rules, which run in a sandbox. Embed images and sounds as `data:` URLs, or draw them. Inline any library you need into the module.
- **Make sense with one actor.** Public rules can be played alone (each actor runs their own copy from the release link) or in a room one actor hosts for friends, as well as in the maker's lasting realm. Do not assume other actors are present, or that saved data from a room lasts.
- **Make the rules repeatable when you can.** If the realm hides nothing from its actors, needs nothing from outside and saves nothing, write the rules so the same moves always give the same state (random numbers from the `seed`, kept in the state; no `async`; no clock) and set `repeatable: true`. Every actor's portal can then check the referee, so nobody has to trust whoever hosts. See "Checking the referee" in [RUNTIME.md](RUNTIME.md) and the maze example.
- **Views are for any renderer.** The rules send plain data and never assume how it is drawn. The actor may choose another look: one you offer under `renderers` in `realm.json` (a text-only one helps screen readers and is quick to write), or one someone else made.
- **Hold-to-move controls** suit action games: have the renderer send a move such as `{ dx: 1, dy: 0 }` when a key or touch starts and `{ dx: 0, dy: 0 }` when it ends, and have the rules keep that direction in the state and move by it on each `tick`. The maze instead takes one turn per key press.
- **Work on phones too.** Support touch (swipes or on-screen buttons) as well as keyboard, and scale drawing to any screen size.

## A renderer for someone else's realm

A person may ask only for a different look at a realm they play: "show me every runner's score", "make it text only". That needs one file, a renderer module as described in [RUNTIME.md](RUNTIME.md), and nothing from the realm's maker. Have them open the realm, choose **The data itself** in the portal's **Look** menu, and tell you what the views contain (or read the realm's public rules). Write the renderer for exactly that data, and have them choose **A file on this device** in the same menu. The portal keeps it for that realm. A renderer can show anything the realm sends and send any move the rules accept; it cannot see what the realm does not send.

## Testing

The rules are plain JavaScript, so you can test them directly with Deno (install with `brew install deno` or `winget install DenoLand.Deno`), as [tests/maze_test.js](https://github.com/freeideas/EndlessMind/blob/main/tests/maze_test.js) does:

```js
import rules from "./rules.js";
const s = rules.init({ seed: 1 });
rules.enter(s, "a", { name: "Ann", color: "red" });
rules.act(s, "a", { dir: "up" });
rules.tick(s);
console.log(rules.view(s, "a"));
```

To try it in a browser, run a server from the Endless Mind repository (`deno task start`), open the printed address, and choose **Publish from files**, selecting all the realm's files including `realm.json`. The portal saves the key and original files locally, then publishes copies. Choose **Start hosting** under **Your realms**, then open its link to visit. Opening alone never starts hosting. Hosting continues while the owner browses within the tab. See [RUNNING.md](RUNNING.md).

To put it online from a terminal, which works for any realm, clone the Endless Mind repository (`git clone https://github.com/freeideas/EndlessMind.git`) and in it run `deno task host --server <helper server> --realm <the realm's folder>`. Any helper server accepts realms from anyone, within its storage limits; `https://play.endlessmind.com` is a public one, and `http://localhost:8000` is your own after `deno task start`. It prints the realm's link, which works only while the program runs (run it in the background to keep working). Then check it as a new actor with `deno task visit "<link>" --act '<a move as JSON>'`, which prints each new view as JSON. Stop the host program when you are done unless the person wants it kept up. See "Hosting without a browser" in [RUNNING.md](RUNNING.md).

For private rules, `await` the calls in your test instead. To try them, run the server, then from the Endless Mind repository run `deno task host --server http://localhost:8000 --realm <the realm's folder>` and open the link it prints in a browser.

## When you are done

Tell the person you are helping:

- how to publish (the steps above) and that they must explicitly choose **Start hosting** and keep that tab open for others to play; or, for private rules or always-on hosting, the host program command, which must keep running, runs the rules with no sandbox on their machine, and publishes a new version under the same link each time it starts;
- that the realm's key lives in that browser (with the host program, in a key file under `keys/` in the Endless Mind repository) unless they save it with "Save my keys" (and anyone with that file controls the realm); **Save full backup** also carries local files and committed storage; importing is local, and **Publish here** or **Start hosting** publishes that same realm to the chosen helper server. Publishing a fresh folder creates a new realm;
- that everything they publish is public and anyone can remix it, except rules kept private, and that the portal tells visitors when a realm's rules are private.

## Optional persistence

`init({ seed, storage })` can await `storage.get(key)` to restore JSON data. Rules call `storage.put(key, value)` to save it. Each realm has its own storage area; only its rules receive this interface. Creators choose save timing, schemas, migration and concurrency. A successful individual write commits its value; the platform does not automatically preserve game state or guarantee transactions across several values. Both browser and host rules may await storage, but only host rules have general network access. See [RUNTIME.md](RUNTIME.md).
