agentleFS
flooooooooooowflooooooooooow/flow-skills/skills/flow-dynamics/SKILL.md

flow-dynamics

Skill1 starsChanged 3 months agoMITView on GitHub

Model a system that changes over time using Flow's `flow` blocks, `evolves as` equations, and `when ... reaches` events. Use for simulations, physics, ODEs, population models, circuits, control systems, epidemics, chemical kinetics, or any request phrased as "simulate", "model over time", or "how does X change".

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read state off the instance by field name: ball.height, ball.velocity.

    line 58
  2. Very specific:

    Check docs/vision/north-star.md before assuming more.

    line 74
  3. Distinctive:

    Write the loop yourself only when the point is to teach the lowering or to use a specialised numerical method the DSL does not cover.

    line 84
  4. Distinctive:

    Put the check in main and return a distinct non-zero code per failure.

    line 137

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Evolution as syntax

This is what Flow exists for. When a system changes over time, write the rule it follows and let the compiler build the simulation.

Requires FLOW_HOST=python.

The form

flow Ball {
    state height      : f64 = 2.0     # m
    state velocity    : f64 = 0.0     # m/s
    param gravity     : f64 = 9.81    # m/s^2
    param restitution : f64 = 0.8

    height evolves as velocity
    velocity evolves as -gravity

    when height reaches 0.0 {
        velocity becomes -restitution * velocity
        height becomes 0.0
    }
}
  • state is a value that changes and carries an initial condition.
  • param is a constant of the model, held on the instance.
  • x evolves as expr is the derivative of x.
  • when guard reaches value { ... } is a discrete event.
  • becomes assigns inside an event body.

Driving it

The compiler generates a constructor and a step function. The caller owns the instance and supplies dt.

function main() -> i32 {
    let dt: f64 = 0.001
    let mut ball: Ball = Ball_new()

    for k in 0 to 6000 {
        Ball_step(&ball, dt)
        if k % 500 == 0 {
            println(ball.height)
        }
    }
    return 0
}

Read state off the instance by field name: ball.height, ball.velocity.

FLOW_HOST=python flow run ball.flow

Semantics to state plainly

  • Derivatives read the pre-step state. Continuous states advance together, so ordering inside the block does not create a dependency.
  • Event assignments are staged and applied together. Both becomes lines above see the same pre-reset velocity.
  • Zero crossing is detected at step granularity. The event fires at the end of the step in which the guard crossed. Event times carry O(dt) error. Say this whenever the timing matters, and shrink dt to show the error shrinking.
  • The generated names X_new and X_step are part of the current lowering. Check docs/vision/north-star.md before assuming more.

Choosing a step size

Halve dt and rerun. If the answer moves, the step is too large. Report both runs. For a stiff system, say so and reach for a solver from lib/stdlib/dynamics/ rather than shrinking dt indefinitely.

When to hand-integrate instead

Write the loop yourself only when the point is to teach the lowering or to use a specialised numerical method the DSL does not cover. Compare the two:

  • examples/evolution/bouncing_ball_evolves.flow is the declarative form.
  • examples/evolution/bouncing_ball.flow solves the exact impact instant by hand and documents the difference.

Related library code

ls lib/stdlib/dynamics/
grep -rn --include='*.flow' "function dsys_" lib/stdlib/

lib/stdlib/dynamics/state_space.flow carries Matrix, DynamicalSystem, discretisation, controllability, Gramians, and similarity transforms. Use them for linear analysis and control design rather than writing matrix code inline.

import "stdlib/dynamics/state_space.flow"

let A: array<f64, 4> = [0.0, 1.0, -1.0, -0.3]
let B: array<f64, 2> = [0.0, 1.0]
let C: array<f64, 2> = [1.0, 0.0]
let sys: DynamicalSystem = dsys_continuous(2, 1, 1, 0.05,
    Matrix { data: A, rows: 2, cols: 2 },
    Matrix { data: B, rows: 2, cols: 1 },
    Matrix { data: C, rows: 1, cols: 2 })

Matrices are row-major fixed arrays with explicit rows and cols. Several routines take scratch arrays as arguments so they allocate nothing.

Worked examples to read first

ls examples/evolution/     # ball, pendulum, van der Pol, SIR, heat, traffic
ls examples/dynamics/      # controllability, Gramians, GA control, Lorenz
ls examples/circuits/      # RC, RLC, PLL, Chua, op-amp, transmission line
ls examples/morphogenesis/ # reaction diffusion, growth, pattern formation
ls examples/neuro/         # spiking neurons, networks

Verify the model, not the syntax

A simulation that runs is not a simulation that is right. Check at least one:

  • a closed-form answer for a simplified case;
  • a conserved quantity that should stay flat;
  • a known qualitative behaviour, such as decaying bounce apexes or a limit cycle;
  • agreement between two step sizes.

Put the check in main and return a distinct non-zero code per failure. That is how the shipped examples do it, and it makes the example a test.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.