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.
| Glyph | Node | Palette tab | Reads |
|---|---|---|---|
| ✦ | Skill | skills | <name>/SKILL.md |
| § | Rules | rules | CLAUDE.md, AGENTS.md, .cursorrules, .cursor/rules/*, .github/copilot-instructions.md |
What lands on the wire
Section titled “What lands on the wire”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.
How they resolve
Section titled “How they resolve”Each node stores a name plus an optional absolute path.
- Path first. If the node has a path and the scanner still knows that file, it is used verbatim.
- Then by name. Candidates are filtered by kind and name, narrowed by
originand then bysourcewhen those are set, and the lowest precedence layer wins. - 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.
Origins & shadowing
Section titled “Origins & shadowing”Skills carry an origin bucket and a precedence layer. Lower layer wins a name collision.
| Layer | Origin | Where |
|---|---|---|
| 10 | project | .claude/skills, .agents/skills, .cursor/skills, .opencode/skills in the repo |
| 20 | custom | .threadle/skills/custom in the repo |
| 30 | imported | .threadle/skills/imported in the repo |
| 40 | custom | ~/.config/threadle/skills/custom |
| 50 | imported | ~/.config/threadle/skills/imported |
| 60 | global | ~/.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.
Auto-invoke
Section titled “Auto-invoke”autoInvoke mirrors the skill’s disable-model-invocation frontmatter field.
| Value | Meaning |
|---|---|
true | the model may pick the skill up on its own |
false | explicit /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.
Wiring example
Section titled “Wiring example”✦ 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.
Related
Section titled “Related”- Nodes overview
- Context nodes — the other injection lane
- Agents & sessions
- Loose ends
- Trust — what threadle reads from disk