Skip to content

Skills & rules

Two artifact nodes put a file’s contents on a wire. Both are pure sources — no input handle, text out — and both read the file fresh on every run rather than snapshotting it into the graph.

GlyphNodePalette tabReads
Skillskills<name>/SKILL.md
§RulesrulesCLAUDE.md, AGENTS.md, .cursorrules, .cursor/rules/*, .github/copilot-instructions.md

The file content is wrapped with a provenance header so a merged text lane stays attributable:

# Skill: pdf-fill (.claude/skills)
<contents of SKILL.md>

Rules files get # Rules: <name> (<source>). Content is capped at 512,000 characters. The run log records ✦ skill <name>: 4213 chars.

From there it is ordinary text: wire it into an agent alongside a prompt (the agent joins its inbound texts with \n\n---\n\n), or through a ⋈ Knot if you want explicit control over the order.

Skill and rules nodes cannot wire straight into an ⇤ Output — they are inputs to a run, not results.


Each node stores a name plus an optional absolute path.

  1. Path first. If the node has a path and the scanner still knows that file, it is used verbatim.
  2. Then by name. Candidates are filtered by kind and name, narrowed by origin and then by source when those are set, and the lowest precedence layer wins.
  3. No match fails the node: no skill named "x" found on this machine.

Exporting a portable graph clears the path, so a shared workflow re-resolves by name on the importing machine. A run that resolves by name writes the resolved path back onto the node.

Only paths the scanner itself discovered are readable — arbitrary file paths are refused.


Skills carry an origin bucket and a precedence layer. Lower layer wins a name collision.

LayerOriginWhere
10project.claude/skills, .agents/skills, .cursor/skills, .opencode/skills in the repo
20custom.threadle/skills/custom in the repo
30imported.threadle/skills/imported in the repo
40custom~/.config/threadle/skills/custom
50imported~/.config/threadle/skills/imported
60global~/.claude/skills, ~/.config/opencode/skills, ~/.cursor/skills, ~/.agents/skills

Project skills always beat threadle libraries and global agent homes.

When two skills share a name, the loser records shadowedBy — the path of the winner. Shadowed skills are hidden from the palette, and a node that was placed before the clash appeared shows shadowed in its subtitle. That is a warning only: the node still injects the file its own path points at.

Rules files are not deduplicated this way — they are listed per scope as found.


autoInvoke mirrors the skill’s disable-model-invocation frontmatter field.

ValueMeaning
truethe model may pick the skill up on its own
falseexplicit /skill-name only

It is a snapshot of the file’s state at pick time and is also toggleable through the rules API. It does not change what the ✦ node injects — a skill node always pushes the full file onto the wire.


✦ Skill ─┐
├──▶ ⟨/⟩ Agent ──▶ ⇤ Output
✎ Prompt ─┘

The starter example plan → implement → review wires a skill into its implement step.

A node with neither a path nor a name is a loose end: pick a skill/rules file.