World
The world block defines the simulation environment - the spatial structure, the entities that populate it, how those entities interact with agents, and the autonomous systems that run independently of any brain. The world is a fully declarative construct: all world mechanics are expressed in .quale.
A route-topology world with waypoints, warning markers, and speed zones.
world OperatorRoute { topology: route length: 10.0 km max_speed: 60.0 km/h tick: 0.5 s
-- Waypoints the operator must stop at entity waypoint { properties { position: km, scheduled_time: float } spawn: 5 on_enter(threshold: 0.16 km, max_speed: 1.5 m/s) { agent.stopped_at_waypoint = true agent.waypoints_served += 1 record waypoint_visit { stopped: 1.0, arrival_time: agent.elapsed } } on_pass { record waypoint_visit { stopped: 0.0, arrival_time: agent.elapsed } } }
-- Warning markers along the route entity warning_marker { properties { position: km, severity: 0..1 } on_cross { when severity > 0.5 { agent.warning_active = true agent.warning_acknowledged = false agent.cognitive_load += 0.05 } } }
-- Speed restriction zones entity speed_zone { properties { start: km, end: km, limit: km/h } }
query nearest_ahead(entity_type, position) -> distance, index, properties query speed_zone_at(position) -> limit
import entities from "route-data.csv"}A route-topology world where the “route” represents a traffic stream over time.
world TrafficStream { topology: route length: 1000.0 km max_speed: 1.0 km/h tick: 0.1 s
-- Network connections appear along the "route" (time axis) entity packet_flow { properties { position: km, packet_rate: 0..1, entropy: 0..1, syn_ratio: 0..1, age: 0..1, malicious: bool } spawn: 100
on_cross { -- Load connection properties into agent state agent.packet_rate = packet_rate agent.payload_entropy = entropy agent.syn_ratio = syn_ratio agent.connection_age = age agent.is_threat = malicious agent.connections_seen += 1
-- Record the decision for fitness scoring when actuator.block > 0.5 { when malicious { agent.true_positives += 1 agent.threats_blocked += 1 } when not malicious { agent.false_positives += 1 } record classification { blocked: 1.0, was_threat: malicious ? 1.0 : 0.0, correct: malicious ? 1.0 : 0.0 } } when actuator.block <= 0.5 { when malicious { agent.threats_missed += 1 } record classification { blocked: 0.0, was_threat: malicious ? 1.0 : 0.0, correct: malicious ? 0.0 : 1.0 } } } }
query nearest_ahead(entity_type, position) -> distance, index, properties
import entities from "traffic-data.csv"}A grid-topology world with consumable food, poison, and water entities.
world ForestFloor { topology: grid(15, 15) walls: border tick: 1.0 s
-- Safe food: restores hunger and energy entity food { properties { color: 0..1, smell: 0..1, texture: 0..1 } spawn: 8 respawn: 20 ticks
on_cross { when actuator.eat > 0.5 { agent.hunger -= 0.3 agent.energy += 0.2 agent.health += 0.05 agent.food_eaten += 1 consume() } } }
-- Poisonous food: causes nausea and health loss entity poison { properties { color: 0..1, smell: 0..1, texture: 0..1 } spawn: 3 respawn: 30 ticks
on_cross { when actuator.eat > 0.5 { agent.nausea += 0.4 agent.health -= 0.3 agent.energy -= 0.1 consume() } } }
-- Water sources entity water { properties { color: 0..1 } spawn: 5 respawn: 15 ticks
on_cross { when actuator.drink > 0.5 { agent.thirst -= 0.5 agent.energy += 0.1 agent.water_drunk += 1 consume() } } }}Topology
Section titled “Topology”The topology defines how space works in the world. The engine provides three spatial primitives.
| Topology | Syntax | Description |
|---|---|---|
| Route | topology: route | 1D scalar dimension (distance along a path). Position is a single float |
| Grid | topology: grid(W, H) | 2D integer grid with optional walls. Position is two integers (x, y) |
| Graph | topology: graph | Node-edge network. Position is a node index |
Route Properties
Section titled “Route Properties”Route topology is used when the agent traverses a linear path. Both Human Factors and Network Security use route topology.
-- Human Factorsworld OperatorRoute { topology: route length: 10.0 km max_speed: 60.0 km/h tick: 0.5 s}-- Network Securityworld TrafficStream { topology: route length: 1000.0 km max_speed: 1.0 km/h tick: 0.1 s}| Property | Description |
|---|---|
length | Total length of the 1D route |
max_speed | Maximum speed in the world (used by perception for normalization) |
tick | Real-time seconds per simulation tick |
Grid Properties
Section titled “Grid Properties”Grid topology is used for 2D spatial environments. The Survival demo uses a grid.
world ForestFloor { topology: grid(15, 15) walls: border tick: 1.0 s}| Property | Description |
|---|---|
walls | Wall configuration. Currently only border is supported |
tick | Real-time seconds per simulation tick |
Entities
Section titled “Entities”Entities are the objects that populate the world. Each entity type declares its properties and interaction handlers.
Properties
Section titled “Properties”Properties are named, typed values that each instance of the entity carries. All properties are accessible to interaction handlers and spatial query results.
-- Human Factors: waypoints with position and scheduleentity waypoint { properties { position: km, scheduled_time: float }}
-- Network Security: packet flows with multiple metric propertiesentity packet_flow { properties { position: km, packet_rate: 0..1, entropy: 0..1, syn_ratio: 0..1, age: 0..1, malicious: bool }}
-- Survival: food with observable propertiesentity food { properties { color: 0..1, smell: 0..1, texture: 0..1 }}For route topology, every entity must have a position property. For grid topology, entities have a grid cell position managed by the engine.
Interaction Handlers
Section titled “Interaction Handlers”When an agent’s position update sweeps past an entity, the engine fires the appropriate handler.
| Handler | Fires when | Parameters | Use case |
|---|---|---|---|
on_cross | Agent’s position sweep crosses the entity position | none | Point-of-passage events |
on_enter(threshold, max_speed) | Agent is within threshold distance AND below max_speed | threshold, max_speed | Controlled stops |
on_pass | Agent crosses entity without meeting on_enter conditions | none | Missed stops |
Inside handlers, entity properties are accessible by name (e.g., severity, malicious, color). Agent state is accessible via agent.*.
on_cross - Crossing Handler
Section titled “on_cross - Crossing Handler”Fires whenever the agent crosses the entity. Used for point-of-passage events in route worlds and cell-overlap events in grid worlds.
Route example (Network Security): Entity properties are loaded into agent state and a record is emitted for fitness scoring.
entity packet_flow { properties { position: km, packet_rate: 0..1, entropy: 0..1, syn_ratio: 0..1, age: 0..1, malicious: bool } spawn: 100
on_cross { -- Load connection properties into agent state agent.packet_rate = packet_rate agent.payload_entropy = entropy agent.syn_ratio = syn_ratio agent.connection_age = age agent.is_threat = malicious agent.connections_seen += 1
-- Record the decision for fitness scoring when actuator.block > 0.5 { when malicious { agent.true_positives += 1 agent.threats_blocked += 1 } when not malicious { agent.false_positives += 1 } record classification { blocked: 1.0, was_threat: malicious ? 1.0 : 0.0, correct: malicious ? 1.0 : 0.0 } } when actuator.block <= 0.5 { when malicious { agent.threats_missed += 1 } record classification { blocked: 0.0, was_threat: malicious ? 1.0 : 0.0, correct: malicious ? 0.0 : 1.0 } } }}Route example (Human Factors): A conditional handler that fires only for high-severity markers.
entity warning_marker { properties { position: km, severity: 0..1 } on_cross { when severity > 0.5 { agent.warning_active = true agent.warning_acknowledged = false agent.cognitive_load += 0.05 } }}on_enter - Conditional Entry Handler
Section titled “on_enter - Conditional Entry Handler”Fires when the agent is within a distance threshold AND below a maximum speed. Requires both parameters. If the agent crosses the entity without meeting these conditions, on_pass fires instead.
-- Human Factors: operator must slow down to stop at waypointsentity waypoint { properties { position: km, scheduled_time: float } spawn: 5 on_enter(threshold: 0.16 km, max_speed: 1.5 m/s) { agent.stopped_at_waypoint = true agent.waypoints_served += 1 record waypoint_visit { stopped: 1.0, arrival_time: agent.elapsed } } on_pass { record waypoint_visit { stopped: 0.0, arrival_time: agent.elapsed } }}on_cross for Grid Worlds
Section titled “on_cross for Grid Worlds”In grid worlds, on_cross fires when the agent occupies the same cell as the entity. The consume() function removes the entity instance and starts a respawn timer.
-- Survival: safe food restores hunger and energyentity food { properties { color: 0..1, smell: 0..1, texture: 0..1 } spawn: 8 respawn: 20 ticks
on_cross { when actuator.eat > 0.5 { agent.hunger -= 0.3 agent.energy += 0.2 agent.health += 0.05 agent.food_eaten += 1 consume() } }}-- Survival: poisonous food causes nausea and health lossentity poison { properties { color: 0..1, smell: 0..1, texture: 0..1 } spawn: 3 respawn: 30 ticks
on_cross { when actuator.eat > 0.5 { agent.nausea += 0.4 agent.health -= 0.3 agent.energy -= 0.1 consume() } }}Event Records
Section titled “Event Records”Interaction handlers can emit typed event records using the record keyword. These records are appended to the scenario event log and used by the fitness block for per-record metric aggregation.
-- Human Factors: track waypoint stops with timing datarecord waypoint_visit { stopped: 1.0, arrival_time: agent.elapsed}
-- Network Security: track classification decisionsrecord classification { blocked: 1.0, was_threat: malicious ? 1.0 : 0.0, correct: malicious ? 1.0 : 0.0}Record fields can be bare names (resolved from handler scope) or name: expression pairs. Record types are defined implicitly by their first emission - all subsequent record statements of the same type must have the same fields.
Spawn and Respawn
Section titled “Spawn and Respawn”Grid-world entities can declare spawn counts and respawn timers. Route-world entities can declare spawn counts for procedural placement.
-- Survival: grid entities with spawn and respawnentity food { properties { color: 0..1, smell: 0..1, texture: 0..1 } spawn: 8 -- place 8 instances at random positions respawn: 20 ticks -- consumed entities reappear after 20 ticks}
-- Network Security: route entities with spawn countentity packet_flow { properties { position: km, ... } spawn: 100 -- 100 packet flows along the traffic stream}
-- Human Factors: route entities with spawn countentity waypoint { properties { position: km, scheduled_time: float } spawn: 5}Speed Zones
Section titled “Speed Zones”Entities without interaction handlers define passive spatial data. Speed zones are a common pattern for route topology.
-- Human Factorsentity speed_zone { properties { start: km, end: km, limit: km/h }}Speed zones are accessed via the speed_zone_at spatial query rather than interaction handlers.
Spatial Queries
Section titled “Spatial Queries”Spatial queries provide efficient lookups against entity collections. They are declared in the world block and callable from perception, action, machines, and entity handlers.
-- Route topology queries (Human Factors)query nearest_ahead(entity_type, position) -> distance, index, propertiesquery speed_zone_at(position) -> limit
-- Route topology queries (Network Security)query nearest_ahead(entity_type, position) -> distance, index, propertiesQuery Results
Section titled “Query Results”Spatial queries return a result struct. Entity properties are promoted to top-level fields on the result.
-- Human Factors: query a waypointlet chk = nearest_ahead(waypoint, agent.position)-- chk.distance - distance to the entity (built-in)-- chk.index - ordinal position in the entity list (built-in)-- chk.position - promoted from waypoint.properties.position
-- Human Factors: query the current speed zonelet zone = speed_zone_at(agent.position)-- zone is the speed limit value (scalar result)No-Match Fallback
Section titled “No-Match Fallback”When a spatial query finds no matching entity (e.g., past the last waypoint on the route):
| Field | Fallback value |
|---|---|
.distance | Positive infinity (large float) |
.index | -1 |
| Any property | 0.0 |
Perception code should account for these fallback values.
Topology-Specific Queries
Section titled “Topology-Specific Queries”| Query | Signature | Description |
|---|---|---|
nearest_ahead(type, pos) | -> distance, index, properties | Next entity of type ahead of position |
speed_zone_at(pos) | -> limit | Speed limit at position. Returns world.max_speed if no zone contains the position |
Route queries use a 10m (0.01 km) deadband: entities at or behind the agent’s current position are excluded to prevent re-triggering.
| Query | Signature | Description |
|---|---|---|
nearest(type, pos, direction) | -> distance, properties | Nearest entity of type in a specific direction |
at(type, pos) | -> bool, properties | Whether an entity of type exists at the given grid cell |
| Query | Signature | Description |
|---|---|---|
neighbors(pos) | -> count, list | Adjacent nodes from current position |
connected(from, to) | -> bool | Whether an edge exists between two nodes |
shortest_path(from, to) | -> distance, next_hop | Shortest path length and next node toward target |
Machines
Section titled “Machines”World-scoped state machines are declared inside the world block. They run at step 1 of the tick loop (before perception), so they can update world state that perception reads. See also agent machines in the body block.
Machine Features
Section titled “Machine Features”| Feature | Syntax | Description |
|---|---|---|
| Scope | scope: world or scope: agent | Determines tick loop placement and visibility |
| Initial state | initial: <state> | Starting state. Defaults to first declared state |
| State block | state <name> { ... } | Per-tick logic that runs while in this state |
| Entry action | on_enter { ... } | Runs once on transition into the state |
| Exit action | on_exit { ... } | Runs once on transition out of the state |
| Transition | transition A -> B: when <cond> | State transition rule |
| Timer | timer | Per-machine local variable, initialized to 0 |
| Elapsed | elapsed_in_state | Seconds since entering current state (resets on transition) |
| Machine-level let | let x = expr at machine level | Evaluated once per tick, visible to all states |
| Entity iteration | for entity in world.<entities> { ... } | World machines only |
Transition Semantics
Section titled “Transition Semantics”- Bottom transitions (declared at machine level) are evaluated after all state logic, in declaration order
- When a transition fires:
on_exitruns for the old state, thenon_enterruns for the new state, all within the same tick - The new state’s per-tick logic does not run in the transition tick; it begins on the next tick
Scope Visibility
Section titled “Scope Visibility”| Scope | Can read | Can write |
|---|---|---|
scope: world | World state, entity properties, spatial queries | World state, entity properties |
scope: agent | Agent state, actuator outputs, world state (read-only), spatial queries | Agent state only |
Data Import
Section titled “Data Import”Entity instances can be loaded from external CSV files. The engine validates that every imported instance has the required properties declared in the entity type definition.
-- Human Factorsimport entities from "route-data.csv"
-- Network Securityimport entities from "traffic-data.csv"The CSV file path is relative to the .quale file’s directory. Each row becomes an entity instance; columns must match entity type property names. The entity type is determined by a type column in the CSV.
Inline entity instances are also supported for small datasets:
waypoint "Checkpoint Alpha" { position: 2.0, scheduled_time: 120.0 }World Block Keyword Reference
Section titled “World Block Keyword Reference”All keywords and constructs available inside a world block.
Top-Level Fields
Section titled “Top-Level Fields”| Field | Syntax | Required | Description |
|---|---|---|---|
topology | topology: route or topology: grid(W, H) | Yes | Spatial structure of the world |
length | length: N unit | Route only | Total length of the 1D route |
max_speed | max_speed: N unit | Route only | Maximum speed (used for perception normalization) |
walls | walls: border | Grid only | Wall configuration |
tick | tick: N s | Yes | Real-time seconds per simulation tick |
entity | entity <name> { ... } | No | Entity type definition |
query | query <name>(...) -> ... | No | Spatial query declaration |
import | import entities from "file.csv" | No | External data import |
state | state <name>: <type> = <value> | No | World state variable |
machine | machine <Name> { ... } | No | World-scoped state machine |
Entity Declaration Syntax
Section titled “Entity Declaration Syntax”entity <name> { properties { <name>: <type>, ... } spawn: <count> respawn: <count> ticks on_cross { <statements> } on_enter(threshold: <value> <unit>, max_speed: <value> <unit>) { <statements> } on_pass { <statements> }}| Sub-block | Required | Description |
|---|---|---|
properties | No | Named, typed values each entity instance carries |
spawn | No | Number of instances to place at scenario start |
respawn | No | Ticks until a consumed entity reappears (grid worlds) |
on_cross | No | Handler fired when agent crosses the entity |
on_enter | No | Handler fired when agent is within threshold distance AND below max_speed |
on_pass | No | Handler fired when agent crosses entity without meeting on_enter conditions |
All sub-blocks are optional and may appear in any order.
Entity Handler Statement Reference
Section titled “Entity Handler Statement Reference”Inside entity interaction handlers (on_cross, on_enter, on_pass), the full statement language is available:
| Statement | Syntax | Description |
|---|---|---|
let | let x = expr | Local variable binding |
when | when cond { stmts } | Conditional guard |
when/else when/else | when cond { } else when cond { } else { } | Exclusive chain |
when (single-line) | when cond: stmt | Single-line conditional |
| Assignment | agent.X op expr | Modify agent state (=, +=, -=, *=, /=) |
record | record type { fields } | Emit a typed event record |
consume | consume() | Remove the entity from the world |
Inside handlers, entity properties are accessible by bare name. For example, in an on_cross handler for an entity with properties { severity: 0..1 }, the name severity resolves to the current entity instance’s property value.
Query Return Value Reference
Section titled “Query Return Value Reference”Spatial queries return a result struct. Use dot access to read fields.
Struct result (e.g., nearest_ahead):
| Field | Type | Description |
|---|---|---|
.distance | float64 | Distance from the agent to the entity |
.index | float64 | Ordinal position in the domain’s entity list, or -1 if no match |
.<property> | float64 | Entity properties are promoted to top-level fields |
let chk = nearest_ahead(waypoint, agent.position)-- chk.distance - built-in: distance to entity-- chk.index - built-in: entity ordinal index-- chk.position - promoted from waypoint properties-- chk.scheduled_time - promoted from waypoint propertiesScalar result (e.g., speed_zone_at):
let zone = speed_zone_at(agent.position)-- zone is the speed limit value directly (not a struct)No-match fallback values:
| Field | Fallback |
|---|---|
.distance | Positive infinity (very large float) |
.index | -1 |
| Any property | 0.0 |