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

flow-basics

Skill1 starsChanged 3 months agoMITView on GitHub

Write, compile, and run an ordinary Flow program. Use for any general Flow coding task, for the syntax of variables, functions, structs, arrays, control flow, imports, and C interop, and whenever you need to check that a Flow file actually runs.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

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

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

    Do not invent syntax from another language.

    line 168

≈ “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

Writing ordinary Flow

Most Flow work is ordinary code. Reach for a declarative form when it improves the model, not to save a line.

Choose the route before writing

DecisionChoicesDefault
Compiler hostflowc, pythonpython unless the program is pure Stage-A
CPU backendC, MLIRC
Moderun, compile, gfx, audio, wasmThe one closest to the real target

Anything with println, a flow block, an effect, or generics needs FLOW_HOST=python.

The syntax

# Comments start with a hash. There are no line comments with slashes.

let x: i32 = 42                # immutable
let mut count: i32 = 0         # mutable
count = count + 1

const GRAVITY: f64 = 9.81      # file-level constant

function add(a: i32, b: i32) -> i32 {
    return a + b
}

function greet(name: string) -> void {
    println(name)
}

struct Point {
    x: f64,
    y: f64
}

function main() -> i32 {
    let p: Point = Point { x: 1.0, y: 2.0 }
    println(p.x)

    let values: array<f64, 4> = [1.0, 2.0, 3.0, 4.0]
    println(values[2])

    for i in 0 to 10 {          # 0 up to but not including 10
        if i % 2 == 0 {
            println(i)
        }
    }

    let mut n: i32 = 5
    while n > 0 {
        n = n - 1
    }

    if n > 0 {
        println("positive")
    } elif n < 0 {
        println("negative")
    } else {
        println("zero")
    }

    return 0
}

Scalars are i32, i64, f32, f64, bool, string, void. Low-level work uses ptr<T>. Casts use as, for example count as f64.

Signatures always carry explicit types. main returns i32, where zero means success and any other value is a failure code you choose.

Printing

println("text")
println(some_number)

extern {
    function printf(fmt: string, val: f64) -> i32
}
printf("%.4f m\n", height)

println takes one value. For formatted output, declare printf in an extern block, which is what the shipped examples do.

Imports

import "stdlib/text.flow"
import "stdlib/math.flow"
import "stdlib/dynamics/state_space.flow"

Library imports are quoted paths rooted at stdlib/, which resolves to lib/stdlib/ in the checkout. Look in lib/stdlib/ for what exists before writing a helper. The flow-stdlib skill covers searching.

C interop

extern {
    function sqrt(x: f64) -> f64
    function fabs(x: f64) -> f64
    function malloc(size: i64) -> ptr<void>
}

Declare only the surface you need. A parser-accepted extern is not proof that the symbol links. Compile and run before claiming it works.

Run it

FLOW_HOST=python flow run program.flow      # compile and run
FLOW_HOST=python flow compile program.flow  # compile only
flow fmt program.flow                        # format
flow explain program.flow                    # show the compilation plan

Or use the packaged wrapper, which tries the fast host, falls back to the full one, and prints the command that worked:

flow-check program.flow

Generated C lands in $FLOW_HOME/build/. Reading it is a good way to understand what a construct lowered to. Never edit it; it is regenerated on every build.

Verify before reporting

A program that compiles has not been shown to be correct. Make main check something and return a distinct code per failure:

function main() -> i32 {
    if add(2, 2) != 4 {
        return 1
    }
    if sum_to(10) != 55 {
        return 2
    }
    println("OK")
    return 0
}

Then report the exact command, the real output, and the exit code.

Pitfalls

  • Comments use #. Slashes are not comments.
  • Ranges are 0 to n, exclusive of n. There is no .. form.
  • let without mut cannot be reassigned.
  • The default host silently lacks println; the error names the Stage-A subset.
  • Do not invent syntax from another language. Grep examples/ for a construct before using it.

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.