Skip to content

Tutorial: Command node

Custom nodes do not require TypeScript. If a program already reads stdin and writes stdout, point command at its argv and you are done. This tutorial wraps sort -u. The sort-unique example in the repo.


Terminal window
mkdir -p ~/.config/threadle/nodes/sort-unique

No node.ts. The descriptor is enough.


~/.config/threadle/nodes/sort-unique/node.json
{
"id": "sort-unique",
"label": "Sort · unique",
"glyph": "⇅",
"description": "sorts input lines and drops duplicates (plain sort -u)",
"command": ["sort", "-u"]
}

Rules that matter:

RuleWhy
command is an argv arrayNo shell, no interpolation, no globbing
Relative argv[0] (e.g. ./tool)Resolves inside the node directory
Absolute / PATH binariessort, jq, python3 work as usual
Exactly one of entry or commandClass flavor vs command flavor

  1. Reload threadle.
  2. Drag Sort · unique from the custom section.
  3. Wire prompt → Sort · unique → output.
  4. Prompt text:
banana
apple
banana
cherry
apple
  1. ▶ Run → output:
apple
banana
cherry

Uppercase with tr:

{
"id": "upper",
"label": "Uppercase",
"glyph": "⇧",
"command": ["tr", "a-z", "A-Z"]
}

jq filter (JSON in, JSON out. Set "input": "json" / "output": "json" when chaining typed nodes):

{
"id": "jq-keys",
"label": "jq keys",
"glyph": "{}",
"input": "json",
"output": "json",
"command": ["jq", "keys"]
}

Local script:

{
"id": "my-py",
"label": "My script",
"glyph": "π",
"command": ["python3", "./run.py"]
}

Put run.py next to node.json. Working directory is the node folder.


SymptomCause
Node fails with stderr excerptNon-zero exit. Fix the tool or the input
timed out after …msRaise timeoutMs (max 300000)
Command not foundBinary not on PATH for the server process (GUI launches often miss ~/.local/bin)

stderr appears in the run log even on success. Useful for jq warnings.


Use entry + node.ts when you need params, named ports, or logic that is awkward as a one-liner. Use command when the Unix toolbox already does the job.

Ready-made wrappers for jq, rg, git, and test runners ship in the stdlib pack. Import those before reinventing them.