Skip to main content
In most engines, game logic is code: a callback compiled into the binary that you cannot read back at runtime. In Euca, a rule is data. A rule is a plain value — a condition plus an effect — that lives in the world alongside entities and components. You can list the rules currently in force, add new ones while the simulation is running, and serialize the whole rule set into a scenario document.
Every byte of a rule is data. A rule is when a condition holds, do an effect — no closures, nothing hidden in the binary. That is what makes the world’s logic as legible to an agent as its state.

The shape of a rule

A rule carries a condition, an effect bundle, a firing policy, and — for stochastic rules — a named random variable and an explicit outcome distribution. A deterministic rule simply omits the variable. Because all of that is data, an agent can read a rule as easily as it reads an entity.

Adding a rule

The compact way is POST /rule/create, which takes a small string DSL:
# When any entity drops below 50 health, heal it back up by 20.
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"]}'
  • whendeath, timer:N, health-below:N, score:N, or phase:NAME.
  • filter — which entities it applies to: any, entity:N, or team:N.
  • actions — space-separated, each with a target prefix: damage entity:1 10, heal this 30, score source 1. The target is this, source, or entity:N.
Read the rules currently in force at any time:
curl -s http://localhost:3917/rule/list

Rules as a scenario document

The DSL is a shorthand. The full data form is the rule list inside a scenario — a declarative document you export, edit, and re-apply. Here the condition and each action are fully typed values:
{
  "rules": [
    {
      "when": { "kind": "health_below", "threshold": 50 },
      "filter": "any",
      "actions": [
        { "action": "heal", "target": "this", "amount": 20 }
      ]
    }
  ]
}
Because rules are values, you can do things that compiled callbacks make impossible: list them, diff two rule sets, generate them programmatically, change them mid-run, and ship a world’s entire logic as a file.

Two kinds of rule: deterministic vs. the stochastic answer key

The rules above — created over HTTP via /rule/create’s string DSL or the typed form in a scenario — are deterministic: a condition fires a fixed effect. They drive gameplay, and they’re what an agent authors at runtime. The world-engine layer adds a second, richer rule type: a stochastic rule that names a random variable and attaches an explicit probability distribution over outcomes. Because that distribution is data — not a hidden rand() call — the engine reads the exact probability of every next outcome analytically. That declared distribution is the true next-step distribution, which is what makes Euca an exact answer key for grading world models.
Stochastic, distribution-bearing rules are authored in Rust (euca_rule::Rule carrying a variable + an outcome distribution, via the online world) and hosted as pre-built evaluation sub-worlds. An agent cannot create a distribution-bearing rule over the HTTP or CLI surface — the agent-facing rules (/rule/create, scenarios) are the deterministic kind.