Settings
⚙ Settings holds persisted preferences, plus management panels for custom nodes and on-disk state. Everything persisted lives in ~/.config/threadle/settings.json.
| Setting | Key | Values | Default |
|---|---|---|---|
| Appearance | appearance | system · light · dark | system |
| Default file opener | editor.mode | vscode · vscode-insiders · cursor · zed · command | vscode |
| Custom opener command | editor.command | argv string, e.g. emacsclient -n | unset |
| Claude Code billing | claudeBilling | subscription · api | subscription |
| Show Workflows addon examples | showExamples | true · false | true |
| MCP client enabled | mcpClientEnabled | true · false | true |
| MCP servers disabled for client | mcpDisabledServers | string[] of server ids | [] |
| MCP publish allowlist | mcpPublishAllowlist | string[] of graph ids, or null | [] (none). null = all |
Editor / billing save together via Save. Appearance, examples, and MCP toggles write immediately.
Appearance
Section titled “Appearance”Three chips: system · light · dark.
| Value | Effect |
|---|---|
system | Follows the OS color scheme (prefers-color-scheme) |
light | Cool zinc surfaces, dark text |
dark | Lifted near-black surfaces (default technical theme) |
Applied immediately (and mirrored in localStorage so the next paint does not flash). The docs site header theme control defaults to System (auto) and offers System · Light · Dark. Tokens match the app.
Default file opener
Section titled “Default file opener”Every “open in editor” button in threadle. File lists, custom-node folders, internals paths. Routes through this setting.
URL-scheme editors are opened client-side by navigating to <scheme>://file<path>:
| Mode | URL built |
|---|---|
vscode | vscode://file/Users/you/project |
vscode-insiders | vscode-insiders://file/… |
cursor | cursor://file/… |
zed | zed://file/… |
Choosing custom command… reveals a command field and switches to a different path entirely: the browser POSTs the absolute path to /api/open, and the server spawns command <path> detached, with no shell. Because there is no terminal attached, plain vim or nano will not work. Use a GUI or client flavor:
emacsclient -ngvimnvim-qtsublThe command is split on whitespace. argv[0] becomes the binary and the path is appended as the final argument. Buttons elsewhere in the UI label themselves with the binary’s basename (emacsclient), falling back to open.
Claude Code billing
Section titled “Claude Code billing”Splits tracked cost (list price of the tokens. What an API would have billed) from actual spend (what you really paid).
| Option | Meaning |
|---|---|
subscription (Pro / Max) | Claude Code sessions report $0 actual spend. The tracked figure is hypothetical |
API key (pay per token) | An API key pays list price, so actual spend equals tracked cost |
opencode always reports what its own keys were billed, independent of this setting. Cursor token counts come from CLI usage or a chars÷4 estimate, with no list price available in public storage.
When threadle can read a plan from ~/.claude.json, the card adds a detection line. Detected from ~/.claude.json: Max · subscription.
List prices themselves are not configured here. They ship bundled (see Costs & billing). Full accounting model: Costs & billing.
Addons
Section titled “Addons”Viewer Settings → Addons lists optional packages. Workflows shows whether the addon API is mounted, opens threadle-workflows (/addon/workflows), and hosts the examples toggle below.
Show Workflows addon examples
Section titled “Show Workflows addon examples”A two-button segmented control (off / on) with no Save button. Toggling writes immediately. When on, the recipes and examples tables appear in the Workflows addon list. See Recipes and Examples.
Custom nodes
Section titled “Custom nodes”Manages ~/.config/threadle/nodes/. Three ways in:
| Action | What it does |
|---|---|
+ Create node | Scaffolds a new node folder from a name, then opens the new file in your configured editor |
⇣ Import | Clones a git URL or copies a local path. Then validates the descriptor |
⌸ Browse… | Uploads a folder from disk. Skips .git and node_modules, and aborts if any file exceeds 2 MB. Then validates |
The install table shows every package on disk with a status column:
| Status | Meaning |
|---|---|
| enabled | Valid. In the palette and runnable |
| disabled | Valid. Hidden from the palette / runner. Folder kept. Toggle with enable |
| error | Failed validation. Error text under the name. Fix node.json or remove the folder |
A summary line counts installed · enabled · disabled · errors. Per-row actions: enable / disable (valid nodes) and open folder in your editor. Disable state lives in nodes/.disabled.json and does not rewrite the author’s node.json. There is no in-app delete. Remove the folder on disk.
Nothing executes on import. Metadata is validated (sandboxed for bare class files), and node code runs only when you wire the node and press Run. See Custom nodes. For curated utilities from the threadle repo (jq, diff, …), see the stdlib pack.
Preferences plus a live discovery table for Model Context Protocol. Keys live in settings.json. The server list is scanned on demand.
| Piece | Meaning |
|---|---|
| MCP client off/on | When off, canvas ◈ MCP tool discovery and calls refuse |
| publish allowlist | Graph ids exposed by threadle mcp as wf_*. One per line or comma-separated. Empty / unset = none. null = all |
host .mcp.json snippet | Copy into Claude Code / Cursor so the host runs threadle mcp |
| ⟳ Refresh servers | Re-scans project configs (walk-up), ~/.config/threadle/mcp/servers.json, and host configs (Cursor / Claude / opencode / Antigravity / Codex where present) |
| ⌘ registry | Opens ~/.config/threadle/mcp/ |
| server table | Id, transport (stdio · streamable-http · sse), endpoint, source. threadle badge. disable / enable for the canvas client |
Spawned stdio servers get the custom-node env allowlist plus each server’s env from disk. Not a full copy of the threadle process. HTTP/SSE remotes use optional headers. Nested recursion into threadle mcp is refused. Full how-to: MCP.
Application status
Section titled “Application status”Live view of the threadle server process, refreshed every 5 s while the view is open. Agent-less workflows. Custom nodes. Run here as child processes, so this is the hardware bill.
pid · node version · uptime · cpu (server) · rss · heap used · worker threads (libuv pool) · custom-node children running · agent jobs running · cores · load 1/5/15m · system memory.
threadle internals
Section titled “threadle internals”Every file and directory threadle writes, with size and file count, and an open in editor button per row. The list is a server-side whitelist. Workflows, favorites, and settings are shown for transparency but can never be bulk-cleared through the API. They render kept instead of a clear button.
Clearing is two-click: the first click arms the button (confirm, or really delete? for destructive items) and it disarms itself after 4 seconds. Already-empty items are disabled.
Full layout: Files & config.
settings.json
Section titled “settings.json”{ "appearance": "system", "editor": { "mode": "command", "command": "emacsclient -n" }, "claudeBilling": "subscription", "showExamples": true, "mcpClientEnabled": true, "mcpDisabledServers": [], "mcpPublishAllowlist": []}Unknown keys are dropped on save. A missing or unreadable file falls back to the defaults in the table above. A claudeBilling value other than "api" reads as subscription, showExamples / mcpClientEnabled are true unless explicitly false, mcpPublishAllowlist of [] publishes nothing and null means publish all workflows, and an unknown appearance reads as system.
Related
Section titled “Related”- Files & config. The rest of
~/.config/threadle - MCP.
threadle mcpand the canvas tool node - Costs & billing. Tracked cost vs actual spend
- Trust model. What the server will and won’t touch