> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eucaengine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Bring up a local server and run the full agent loop — build a world, play it, and experiment on it — in a few minutes.

This is the agent loop end to end: **build** a tiny world, **play** it forward, and
**experiment** on a fork. Every command below is real and runnable against a local server.

## Prerequisites

* macOS or Linux
* A Rust toolchain ([rustup](https://rustup.rs))
* A clone of the engine repository

## 1. Start the server

The agent API is served by the **headless host** — `euca-studio` with no window. From the
repo root:

```bash theme={null}
cargo run -q -p euca-studio -- --headless
```

It binds `localhost:3917`. Leave it running and open a second terminal for the commands
below.

<Warning>
  The local server is **unauthenticated by default** — run it on a machine you control, driven by
  an agent on the same host. Optional Ed25519 auth is available; see
  [Hosting & deployment](/systems/hosting-deployment).
</Warning>

<Tip>
  Every `POST` must send `-H 'Content-Type: application/json'`. Without it the JSON body is
  rejected and the request looks like it was ignored.
</Tip>

Check it is up:

```bash theme={null}
curl -s http://localhost:3917/
# { "engine": "Euca Engine", "version": "1.1.0", "entity_count": 107, "archetype_count": 18, "tick": 100 }
```

<Note>
  The headless host boots the **loaded project** (a full world), so your real `entity_count`, `tick`, and
  the entity ids your spawns return will be higher than the small illustrative numbers shown below — the flow
  is identical, only the ids differ. (For an empty world, build your own host that loads no level.)
</Note>

## 2. Build a world

Spawn two entities and add a rule. Entity A gets a velocity **and** a `Kinematic`
`physics_body` so a system actually moves it; entity B is a stationary target on the other
team.

<CodeGroup>
  ```bash cURL theme={null}
  # Entity A — team 1, moving along +x.
  curl -s -X POST http://localhost:3917/spawn \
    -H 'Content-Type: application/json' \
    -d '{"position":[0,1,0],"velocity":{"linear":[1,0,0]},"physics_body":"Kinematic","health":100,"team":1}'
  # { "entity_id": 1, "entity_generation": 0 }

  # Entity B — team 2, stationary at x = 5.
  curl -s -X POST http://localhost:3917/spawn \
    -H 'Content-Type: application/json' \
    -d '{"position":[5,1,0],"health":60,"team":2}'
  # { "entity_id": 2, "entity_generation": 0 }
  ```

  ```python Python theme={null}
  import requests
  BASE = "http://localhost:3917"

  a = requests.post(f"{BASE}/spawn", json={
      "position": [0, 1, 0], "velocity": {"linear": [1, 0, 0]},
      "physics_body": "Kinematic", "health": 100, "team": 1,
  }).json()
  b = requests.post(f"{BASE}/spawn", json={
      "position": [5, 1, 0], "health": 60, "team": 2,
  }).json()
  print(a, b)  # {'entity_id': 1, 'entity_generation': 0} {'entity_id': 2, 'entity_generation': 0}
  ```

  ```rust Rust theme={null}
  use serde_json::json;

  fn main() -> Result<(), Box<dyn std::error::Error>> {
      let base = "http://localhost:3917";
      let http = reqwest::blocking::Client::new();

      let a: serde_json::Value = http
          .post(format!("{base}/spawn"))
          .json(&json!({"position":[0,1,0],"velocity":{"linear":[1,0,0]},
                        "physics_body":"Kinematic","health":100,"team":1}))
          .send()?
          .json()?;
      let b: serde_json::Value = http
          .post(format!("{base}/spawn"))
          .json(&json!({"position":[5,1,0],"health":60,"team":2}))
          .send()?
          .json()?;
      println!("{a} {b}");
      Ok(())
  }
  ```
</CodeGroup>

Add a rule — logic is [data](/concepts/rules-as-data), not code. This one heals any entity
that drops below 50 health:

```bash theme={null}
curl -s -X POST http://localhost:3917/rule/create \
  -H 'Content-Type: application/json' \
  -d '{"when":"health-below:50","filter":"any","actions":["heal this 20"]}'
# { "ok": true, "rule_id": 0, "when": "health-below:50" }
```

## 3. Play it

Step the simulation forward, then read the world back:

<CodeGroup>
  ```bash cURL theme={null}
  curl -s -X POST http://localhost:3917/step \
    -H 'Content-Type: application/json' -d '{"ticks":30}'
  # { "ticks_advanced": 30, "new_tick": <boot_tick + 30>, "entity_count": <project + your spawns> }

  curl -s -X POST http://localhost:3917/observe
  ```

  ```python Python theme={null}
  requests.post(f"{BASE}/step", json={"ticks": 30})
  world = requests.post(f"{BASE}/observe").json()
  print(world["tick"], len(world["entities"]))
  ```

  ```rust Rust theme={null}
  http.post(format!("{base}/step")).json(&json!({"ticks": 30})).send()?;
  let world: serde_json::Value =
      http.post(format!("{base}/observe")).send()?.json()?;
  println!("{world:#}");
  ```
</CodeGroup>

`observe` returns the **whole world** — the loaded project's entities plus the two you spawned. Picking
your two rows out of it, entity A has advanced along +x (30 ticks at 1 unit/s, with `dt = 1/60`) while B
has not moved (ids shown illustratively as `1`/`2` — yours will be the higher ids your spawns returned):

```json theme={null}
{
  "entities": [
    { "id": 1, "generation": 0,
      "transform": { "position": [0.5000002, 1.0, 0.0], "rotation": [0.0,0.0,0.0,1.0], "scale": [1.0,1.0,1.0] },
      "velocity": { "linear": [1.0,0.0,0.0], "angular": [0.0,0.0,0.0] },
      "physics_body": "Kinematic", "health": [100.0,100.0], "team": 1 },
    { "id": 2, "generation": 0,
      "transform": { "position": [5.0,1.0,0.0], "rotation": [0.0,0.0,0.0,1.0], "scale": [1.0,1.0,1.0] },
      "health": [60.0,60.0], "team": 2 }
  ]
}
```

The full `observe` dump is the whole world as a flat table — see
[The world as a table](/concepts/world-as-table). (Below, `T` is whatever tick the world is at when you
fork; the numbers diverge **relative** to it.)

## 4. Experiment on a fork

Fork the world, run a what-if **only on the copy**, and confirm the main run never moved.

```bash theme={null}
# Fork at the current tick T.
curl -s -X POST http://localhost:3917/fork \
  -H 'Content-Type: application/json' -d '{"fork_id":"what-if"}'
# { "ok": true, "fork_id": "what-if", "parent_tick": T }

# Run the counterfactual 100 ticks forward — on the fork only.
curl -s -X POST http://localhost:3917/fork/what-if/step \
  -H 'Content-Type: application/json' -d '{"ticks":100}'
# { "ok": true, "fork_id": "what-if", "start_tick": T, "new_tick": T+100, "ticks_advanced": 100, ... }

# The fork advanced to tick T+100:
curl -s http://localhost:3917/fork/what-if/observe        # → "tick": T+100

# The main world is untouched at tick T:
curl -s -X POST http://localhost:3917/observe             # → "tick": T

# Drop the fork. The main run never changed.
curl -s -X DELETE http://localhost:3917/fork/what-if
# { "ok": true, "deleted": "what-if" }
```

<Check>
  The fork advanced 100 ticks while the main world stayed exactly where it was. That clean
  divergence — the same systems running on an isolated copy — is what makes a fork a true
  [counterfactual](/concepts/forks).
</Check>

## Going further

* **Diff two moments** — snapshot the world with `POST /snapshot`, change it, snapshot again,
  and compare with `GET /snapshot/diff` (it compares game-state summaries: counts, phase,
  roles).
* **Save and replay** — export the whole world as a scenario with `GET /scenario` and rebuild
  it with `POST /scenario`. See [Determinism & replay](/concepts/determinism).
* **Full API** — every endpoint, request, and response is in the [API reference](/api-reference/introduction).
* **Grade a world model** — the same engine doubles as an exact answer key; see
  [World-model evaluation](/evaluation/overview).
