Tutorial: Typed chain
Wires are not only “text.” A node can declare input / output as text, int, float, bool, or json. threadle checks that the payload parses before the next node runs, so a bad number fails loudly instead of poisoning the rest of the graph.
This tutorial builds two small demos from the repo examples.
Demo A. Text → json → float
Section titled “Demo A. Text → json → float”Text stats emits a JSON object. Sum numbers walks that JSON and returns a float total.
char-stats
Section titled “char-stats”{ "id": "char-stats", "label": "Text stats", "glyph": "∑", "description": "chars, words and lines of the input, as JSON", "entry": "node.ts", "input": "text", "output": "json"}export default class TextStats { async run(input: string): Promise<string> { return JSON.stringify( { chars: input.length, words: (input.trim().match(/\S+/g) ?? []).length, lines: input === "" ? 0 : input.split("\n").length, }, null, 2, ); }}sum-numbers
Section titled “sum-numbers”{ "id": "sum-numbers", "label": "Sum numbers", "glyph": "+", "description": "sums every number found in a JSON value", "entry": "node.ts", "input": "json", "output": "float"}export default class SumNumbers { async run(input: string): Promise<string> { let total = 0; const walk = (v: unknown): void => { if (typeof v === "number") total += v; else if (Array.isArray(v)) v.forEach(walk); else if (v && typeof v === "object") Object.values(v).forEach(walk); }; walk(JSON.parse(input)); return String(total); }}Wire and run
Section titled “Wire and run”prompt → Text stats → ◇ Data(json) → Sum numbers → output(You can omit ◇ Data when Text stats already declares output: "json". The type gate accepts a direct wire. Data is useful when an upstream agent emits prose JSON you still want to coerce.)
Prompt:
one twothreeExpected JSON from Text stats (shape):
{ "chars": 14, "words": 3, "lines": 2 }Sum numbers walks every number → output roughly 19 (exact chars depend on newlines).
If you wire a plain text prompt directly into Sum numbers, the run fails at the type gate. json expected. Instead of throwing inside JSON.parse mid-pipeline.
Demo B. Int prompt → Fibonacci
Section titled “Demo B. Int prompt → Fibonacci”{ "id": "fibonacci", "label": "Fibonacci", "glyph": "φ", "description": "first N Fibonacci numbers", "entry": "node.ts", "input": "int", "output": "text"}export default class Fibonacci { async run(input: string): Promise<string> { const n = Math.min(Number.parseInt(input.trim(), 10), 90); const seq: bigint[] = []; let [a, b] = [0n, 1n]; for (let i = 0; i < n; i++) { seq.push(a); [a, b] = [b, a + b]; } return seq.join(", "); }}Wire an int-typed prompt (inspector → value type int). Or ◇ Data(int). Into Fibonacci:
prompt(int: 8) → Fibonacci → output◇ Data(int: 8) → Fibonacci → output→ 0, 1, 1, 2, 3, 5, 8, 13
A text prompt containing eight will not satisfy int and the edge or run will refuse.
Compatibility cheat sheet
Section titled “Compatibility cheat sheet”| From → To | Allowed? |
|---|---|
| same type | yes |
anything → text | yes |
int → float | yes |
float → int | no |
text → json | only if the string parses as JSON |
Named ports use the same types per port. See Params & named ports.
Install from the repo
Section titled “Install from the repo”If you have the threadle source tree:
Settings → custom nodes → ⇣ Import → pick
examples/nodes/char-stats (and siblings), or copy the folders into ~/.config/threadle/nodes/.
Related
Section titled “Related”- Custom nodes
- Stdlib pack.
jq/extract-jsonafter typed Data nodes - Params & named ports. Widgets + multi-lane I/O
- Tutorial: Extract URLs
- Tutorial: Command node
- Lanes & value types