InitfinityTM
Initfinity / Docs / Flow Definition Language (FDL)

Flow Definition Language (FDL)

FDL (Flow Definition Language) is Initfinity's text format for defining flows. It's concise, human-readable, and can be generated by AI or written by hand. Every FDL file can be converted to/from the native FlowDefinition JSON format without loss, apart from three things FDL does not carry: the editor viewport, the node catalog id and the hosted flow link. Those stay in .flow and .flob files.

Basic Structure

#fdl 1
flow "My Flow"

node1(type) field1=value1 field2="string value" @x,y
node2(type) field3=42 @x,y

node1.port -> node2.port

A flow file has three parts:

  1. Header: flow "Name" declares the flow name
  2. Nodes: each line declares one node with its type, fields, and optional position
  3. Edges: connections between node ports using source.port -> target.port

Version Header

The first line of an FDL file is #fdl 1, the format version. Tools always write it. Readers accept files without it and read them as version 1, so hand-written files and older files keep working. A future incompatible format would start with #fdl 2; a reader that does not know that version stops with a clear error instead of guessing. To older readers the line is just a comment.

Node Syntax

id(typeKey) field=value field2="string" @x,y
PartRequiredDescription
idYesUnique identifier (alphanumeric, hyphens, underscores)
typeKeyYesNode type (e.g. trigger, number, http-fetch)
field=valueNoField configuration (space-separated key=value pairs)
@x,yNoPosition hint (decimals allowed, e.g. @10.5,3); omit to use auto-layout

Value Quoting Rules

Value TypeWhen to UseExample
BareAlphanumeric + -_./GET, upper, true, 42
Double-quotedContains spaces or special chars"https://api.example.com", "a + b"
Backtick-fencedJSON objects, arrays, or multi-line code`{"key": "val"}`

Operators containing >, <, = must be quoted: operator=">=".

A bare 42 is a number and a bare true or false is a boolean. To keep a string that looks like one of those, quote it: text="42", flag="true". Tools do this automatically when they write a file.

Escape sequences in double-quoted strings: \", \\, \n, \r, \t and \uXXXX. Any other backslash is kept as written, so "C:\dir" is fine.

Inside a backtick-fenced JSON value, write a literal backtick as \u0060. A value that is valid JSON is stored as that JSON value (`null` is an explicit null); any other backtick text, such as multi-line code, is kept as a string.

Display metadata

Names starting with $ are reserved for node metadata and never clash with a node's own fields:

KeyMeaning
$title="Name"The title shown on the node
$description="Text"The node's description
$style= followed by a JSON object in backticksNode size, for example `{"width":800,"height":400}`

A plain title= is also stored as the node title, so nodes such as code or note that have a field called title keep it.

Edge Syntax

#fdl 1
source-node.output-port -> target-node.input-port

Ports are always explicit; there are no defaults. Use the exact port IDs from the node definition.

Edges get a derived id (source-port-target-port). When a file needs a different id or extra edge data such as a label, the writer adds a line after the edges that older readers skip:

#fdl 1
flow "Custom edge"

a(trigger) @0,0
b(logger) @280,0

a.out -> b.in

edgeid a.out -> b.in e-custom
edgeextra a.out -> b.in label="go"

Background

An optional line sets a per-flow canvas background as JSON in backticks:

#fdl 1
background `{"variant":"lines","gap":24,"color":"#101820","image":"/backgrounds/space.jpg"}`

All keys are optional. image is a virtual filesystem path.

Flow id and decorators

The writer adds id= to the header only when the flow's id differs from the one derived from its name: flow "My Flow" id=my-custom-id. Canvas decorators (emoji, text, pins and so on) are written as one JSON array line:

#fdl 1
decorators `[{"id":"d1","type":"decorator","position":{"x":0,"y":0},"data":{"decoratorKind":"text","text":"Note"}}]`

Comments

#fdl 1
# This is a comment (ignored by the parser)

Auto-Layout

If all nodes have position @0,0 (or no positions are specified), the parser automatically applies a left-to-right topological layout with 280px column spacing and 160px row spacing.

Markdown List Markers

Node and edge lines may be prefixed with -, *, or + to allow embedding FDL inside markdown lists:

#fdl 1
- start(trigger) label="Run"
- fetch(http-fetch) url="https://api.example.com" method=GET
- start.out -> fetch.in

Common Node Types

NodeTypeKeyKey FieldsPorts
Manual triggertriggerlabelout (trigger)
Numbernumbervaluein, out
Texttexttext, modein, out
Mathmathformula (e.g. "a + b")a, b → result
Comparisoncomparisonoperator (==,!=,>,<,>=,<=)a, b → result
Condition / branchconditiondefault, invertin → true, false (triggers)
HTTP fetchhttp-fetchurl, methodin (body), out, status, error
JSON pathjson-pathpath (dot-notation, e.g. user.name)in, out
Loggerloggerlevel, prefixin, out
Codecodesource, languagein, out
CSV parsercsv-parserdelimiter, headerin → out, headers, count, error
String transformstring-transformop (upper,lower,trim,len)in, out
Array filterarray-filterproperty, valuein, out
Countercountername, stepreset → count
Sleepsleepduration (ms)in, out
IntervalintervalscheduleMode (interval, preset or cron), interval (ms), count, preset, cronExpressionout (trigger), ticks, index
JSON datajsondatain, out

Example: HTTP API with Error Handling

#fdl 1
flow "Fetch Todo"

fetch(http-fetch) url="https://jsonplaceholder.typicode.com/todos/1" method=GET
extract(json-path) path=title
display(text)
log(logger)
err-log(logger) prefix="ERROR:"

fetch.out -> extract.in
extract.out -> display.in
display.out -> log.in
fetch.error -> err-log.in

Example: Conditional Branching

#fdl 1
flow "Score Classifier"

score(number) value=75
threshold(number) value=60
check(comparison) operator=">="
branch(condition)
pass-msg(text) text="Pass"
fail-msg(text) text="Fail"

score.out -> check.a
threshold.out -> check.b
check.result -> branch.in
branch.true -> pass-msg.in
branch.false -> fail-msg.in

Example: Filter CSV Rows

#fdl 1
flow "Filter Active Users"

csv-input(text) text="name,active\nAlice,true\nBob,false"
parser(csv-parser)
filter(array-filter) property=active value=true
log(logger)

csv-input.out -> parser.in
parser.out -> filter.in
filter.out -> log.in