Skip to content

Settings

⚙ Settings holds four persisted preferences, plus management panels for custom nodes and on-disk state. Everything persisted lives in ~/.config/threadle/settings.json.

SettingKeyValuesDefault
Default file openereditor.modevscode · vscode-insiders · cursor · zed · commandvscode
Custom opener commandeditor.commandargv string, e.g. emacsclient -nunset
Model prices sourcepricingUrlany http(s) URLunset → https://models.dev/api.json
Claude Code billingclaudeBillingsubscription · apisubscription
Show workflow examplesshowExamplestrue · falsetrue

All four save together — the three Save buttons write the whole object, so editing the pricing URL and pressing Save in the billing card persists both.


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>:

ModeURL built
vscodevscode://file/Users/you/project
vscode-insidersvscode-insiders://file/…
cursorcursor://file/…
zedzed://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:

Terminal window
emacsclient -n
gvim
nvim-qt
subl

The 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.


A models.dev-compatible JSON endpoint. The stored value is empty by default and the field’s placeholder shows the fallback, https://models.dev/api.json. Any value that is not http:// or https:// is rejected with pricing url must be http(s).

threadle is local-first about prices: it prefers whatever is already on disk — opencode’s ~/.cache/opencode/models.json, then its own ~/.config/threadle/models-pricing.json, freshest copy wins — regardless of age. The network is contacted automatically only when no local copy exists anywhere.

The manual fetch lives in Statistics, not here: the ⟳ fetch prices button under model pricing · list prices per 1M tokens. It re-fetches the configured URL, replaces the cache, and reports updated · N providers.


Splits tracked cost (list price of the tokens — what an API would have billed) from actual spend (what you really paid).

OptionMeaning
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.

Full accounting model: Costs & billing.


A two-button segmented control (off / on) with no Save button — toggling writes immediately. When on, the recipes and examples tables appear under your workflows list. See Recipes and Examples.


Manages ~/.config/threadle/nodes/. Three ways in:

ActionWhat it does
+ Create nodeScaffolds a new node folder from a name, then opens the new file in your configured editor
⇣ ImportClones a git URL or copies a local path
⌸ Browse…Uploads a folder from disk — skips .git and node_modules, and aborts if any file exceeds 2 MB

The table lists each node’s glyph, label, description, and command — ⌁ class · <file> for a TypeScript class node, or the argv array for a manifest node. Nodes that failed to parse are listed separately with a and the parse error.

There is no delete and no in-place editor. The single per-row action opens the node’s folder in your editor; delete by removing the folder.

Nothing executes on import — metadata is read in a sandboxed child process, and node code runs only when you wire the node and press Run. See Custom nodes.


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.


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 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.


{
"editor": {
"mode": "command",
"command": "emacsclient -n"
},
"pricingUrl": "https://models.dev/api.json",
"claudeBilling": "subscription",
"showExamples": true
}

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, and showExamples is true unless explicitly false.