Skip to main content
A rule is when a condition holds, do an effect — and it is 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.
Start a local server first — see the Quickstart. All commands target http://localhost:3917; every POST sends Content-Type: application/json.

Add a rule

The quickest way is the string DSL on POST /rule/create:
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" }
  • whendeath, timer:N (N seconds), health-below:N, score:N, or phase:NAME.
  • filterany, team:N, or entity:N.
  • actions — space-separated verb target amount, where verbheal, damage, score, spawn, despawn, teleport, color, text, endgame and targetthis, source, entity:N.
The rule is now part of the world. Read the rule set back at any time:
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:
# (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" } ] }
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.

The fully-typed form

The DSL is shorthand. The complete data form is the rule list inside a scenario, where the condition and each action are typed values you can generate, diff, and store:
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.