> ## 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.

# Data-driven rules

> Add rules to a running world, list them, change them mid-run, and ship them in a scenario — game logic as inspectable data, not compiled code.

A rule is **`when` a condition holds, `do` an effect** — and it is [data](/concepts/rules-as-data),
so you can add it, read it back, and change it while the simulation runs. This guide covers
both the compact string form and the fully-typed declarative form.

<Note>
  Start a local server first — see the [Quickstart](/quickstart). All commands target
  `http://localhost:3917`; every `POST` sends `Content-Type: application/json`.
</Note>

## Add a rule

The quickest way is the string DSL on `POST /rule/create`:

```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" }
```

* **`when`** — `death`, `timer:N` (N **seconds**), `health-below:N`, `score:N`, or `phase:NAME`.
* **`filter`** — `any`, `team:N`, or `entity:N`.
* **`actions`** — space-separated `verb target amount`, where `verb` ∈ `heal`, `damage`,
  `score`, `spawn`, `despawn`, `teleport`, `color`, `text`, `endgame` and `target` ∈ `this`,
  `source`, `entity:N`.

The rule is now part of the world. Read the rule set back at any time:

```bash theme={null}
curl -s http://localhost:3917/rule/list
# { "count": 1, "rules": [ { "id": 0, "name": "agent-rule-0", "type": "health_below" } ] }
```

Each tick of `/step`, the engine evaluates every rule against the table and applies the
effects of those whose condition holds.

## Change rules mid-run

Because rules are a live part of the world, you can add one while the simulation is running —
no restart, no recompile:

```bash theme={null}
# (the world is already running and stepping, from the steps above)
curl -s -X POST http://localhost:3917/rule/create \
  -H 'Content-Type: application/json' \
  -d '{"when":"timer:1","filter":"team:1","actions":["heal this 5"]}'
# { "ok": true, "rule_id": 1, "when": "timer:1" }

curl -s http://localhost:3917/rule/list
# { "count": 2, "rules": [ { "id": 0, "name": "agent-rule-0", "type": "health_below" }, { "id": 1, "name": "agent-rule-1", "type": "timer" } ] }
```

<Warning>
  Rules are **sticky**: neither `/reset` nor applying a new scenario clears the rule set —
  `/reset` despawns entities only, and a scenario *appends* its rules. There is no rule-clear
  endpoint, so for a clean rule set, restart the server. Keep this in mind when iterating.
</Warning>

## The fully-typed form

The DSL is shorthand. The complete data form is the rule list inside a
[scenario](/guides/deterministic-replay), where the condition and each action are typed
values you can generate, diff, and store:

```bash theme={null}
curl -s -X POST http://localhost:3917/scenario \
  -H 'Content-Type: application/json' -d '{
    "version": 2,
    "entities": [ { "position": [2,1,0], "health": 80, "team": 1 } ],
    "rules": [
      {
        "when": { "kind": "health_below", "threshold": 50 },
        "filter": "any",
        "actions": [ { "action": "heal", "target": "this", "amount": 20 } ]
      }
    ]
  }'
# { "ok": true, "entities_spawned": 1, "rules": 1, "templates": 0, "assertions": 0 }
```

The typed condition is `{"kind": "<snake_case>", ...}` — `death`, `timer` (+`interval`),
`health_below` (+`threshold`), `score` (+`threshold`), `phase` (+`phase`). Each action is
`{"action": "...", "target": "this" | "source" | {"entity": N}, ...}`. Because every part is
data, a world's entire logic ships as a file you can read, diff, and re-apply.
