Skip to content

Dynamics

Defines per-tick state cascade rules - how internal states change over time independent of agent actions. Dynamics is optional; omitting it means no per-tick state changes.

Dynamics are the physics of your simulation - the rules that govern what happens every tick regardless of what the agent does. This is where you model things like fatigue slowly increasing, stress accumulating, or physiological decay over time. Without dynamics, state only changes when agent actions or entity interactions modify it. With dynamics, the world exerts constant pressure that the agent must respond to.

Dynamics runs at step 6 of the tick loop, after all other blocks have finished. This means all state mutations from the action block, entity interactions, and agent machines are visible to the dynamics cascade.

The Network Security demo does not use a dynamics block - the IDS agent has no physiological state that changes over time independent of actions. Not every domain requires dynamics.

dynamics OperatorPhysiology {
hidden dt: 0..1 = 0.05
per_tick {
fatigue += 0.001 * dt
stress -= 0.005 * dt
boredom += 0.003 * dt
cognitive_load -= 0.01 * dt
}
rules {
if cognitive_load > 0.2: fatigue += 0.002 * dt
if fatigue > 0.8: stress += 0.001 * dt
}
clamp 0..1
}

Hidden states are invisible to the brain - the agent cannot sense them. They participate in rules but never appear as sensor inputs.

hidden name: min..max = initial

Both demo dynamics blocks use a hidden dt variable to scale state changes:

-- Human Factors
hidden dt: 0..1 = 0.05
-- Survival
hidden dt: 0..1 = 0.05

The per_tick block contains rules that run unconditionally every tick.

Models fatigue growth, stress recovery, boredom growth, and cognitive load decay:

per_tick {
fatigue += 0.001 * dt
stress -= 0.005 * dt
boredom += 0.003 * dt
cognitive_load -= 0.01 * dt
}

The rules block contains conditional rules evaluated in order. Earlier rules’ effects are visible to later rules within the same tick.

Cascading effects: high cognitive load accelerates fatigue, and high fatigue increases stress.

rules {
if cognitive_load > 0.2: fatigue += 0.002 * dt
if fatigue > 0.8: stress += 0.001 * dt
}

The death block defines conditions that kill the agent. Death conditions are checked after all rules apply.

-- Survival: agent dies when health or energy reaches zero
death {
if health <= 0
if energy <= 0
}

The Human Factors demo does not have a death block in dynamics - the agent dies when it reaches the end of the route (agent.alive = false in the action block).

Setting agent.alive = false in any block also kills the agent, independent of the dynamics death block.


The clamp directive constrains all dynamics-managed states to a range after each tick.

-- Both demos use the same clamp range
clamp 0..1

This ensures no state drifts below 0 or above 1 due to accumulated rule effects.


OperatorMeaningExample
+=Add to current valuehunger += 0.005 * dt
-=Subtract from current valueenergy -= 0.003 * dt
*=Multiply current valuenausea *= 0.95
=Set to valuehealth = 0.0
OperatorMeaning
>Greater than
<Less than
>=Greater than or equal
<=Less than or equal

Right-hand side of an assignment can be:

FormExample
Literal valuehunger += 0.003
Unary minusenergy += -0.1
State referenceenergy = health
number * state_reffatigue += 0.002 * dt
number * (expr)stress += 0.001 * (1.0 + fatigue * 2.0)
state * valuenausea *= 0.95
state + valuerecovery = health + 0.1
state - valuepenalty = energy - 0.2
Parenthesized sub-expressionenergy -= (hunger + thirst)

Operator precedence: * binds tighter than + and -. Use parentheses to override precedence when needed.

  • Rule ordering matters - earlier rules’ effects are visible to later rules within the same tick
  • per_tick rules run unconditionally every tick
  • rules block contains conditional rules evaluated in order
  • death conditions are checked after all rules apply; if any is true the agent dies
  • clamp applies to all states after each tick

The dynamics block uses a simpler syntax than perception/action blocks. The let, when, match, and ternary features are NOT available in dynamics. Dynamics uses if for conditionals, not when.

dynamics <Name> {
hidden <name>: <range> = <initial>
per_tick { <rules> }
rules { <conditional_rules> }
death { <death_conditions> }
clamp <range>
}
Sub-blockRequiredDescription
hiddenNoHidden state variables (invisible to the brain)
per_tickNoUnconditional per-tick rules
rulesNoConditional rules (if guards)
deathNoDeath conditions checked after all rules
clampNoRange constraint applied to all dynamics-managed states
hidden dt: 0..1 = 0.05

Hidden states are invisible to the brain and do not appear as sensor inputs. They participate in dynamics rules only.

OperatorMeaningExample
+=Add to current valuehunger += 0.005 * dt
-=Subtract from current valueenergy -= 0.003 * dt
*=Multiply current valuenausea *= 0.95
=Set to valuehealth = 0.0

Dynamics uses if, not when:

rules {
if hunger > 0.8: energy -= 0.005 * dt
if nausea > 0.3: health -= 0.01 * dt
}
OperatorMeaning
>Greater than
<Less than
>=Greater than or equal
<=Less than or equal

The dynamics expression syntax is simpler than the full expression language.

FormExample
Literal valuehunger += 0.003
Unary minusenergy += -0.1
State referenceenergy = health
number * state_reffatigue += 0.002 * dt
state * valuenausea *= 0.95
state + valuerecovery = health + 0.1
state - valuepenalty = energy - 0.2
Parenthesized sub-expressionenergy -= (hunger + thirst)
death {
if health <= 0
if energy <= 0
}

Each condition is checked independently. If any condition is true, agent.alive is set to false.

clamp 0..1

Applied after all rules and death checks. Constrains every dynamics-managed state to the specified range.