Files & config
threadle writes to exactly one directory. Everything else on your disk it treats as read-only.
~/.config/threadle/├── settings.json├── graphs/│ ├── starter.json│ └── <id>.json├── payloads/│ ├── <aa>/<sha256>.json│ ├── <aa>/<sha256>.md│ └── tags.json├── nodes/│ └── <name>/node.json · node.ts├── skills/│ ├── custom/│ └── imported/├── runs/│ ├── jobs.jsonl│ ├── injects.jsonl│ └── logs/<jobId>.jsonl├── search.db├── models-pricing.json├── cursor-usage.json└── tmp/What each item holds
Section titled “What each item holds”| Path | Contents | Clearable in UI |
|---|---|---|
settings.json | Editor, pricing source, billing mode, examples toggle — see Settings | no |
graphs/ | One JSON per workflow or sub-workflow, named by graph id. The seeded starter graph is always starter.json | no |
payloads/ | Content-addressed context payloads, sharded by the first two hex characters of their SHA-256 | yes (destructive) |
payloads/tags.json | Sidecar map of hash → tags, so stored payloads stay immutable | — |
nodes/ | Custom nodes — a node.json manifest or a TypeScript class entry, plus whatever the node ships | no |
skills/custom | Skillsets you authored inside threadle | no |
skills/imported | Skillsets imported into threadle. Project-repo skills override these on a name clash | yes |
runs/jobs.jsonl | Append-only record of every run shown in the Runs view | yes |
runs/logs/<jobId>.jsonl | Per-run log, one JSON line per emitted line ({ts, lane, line}) | yes |
runs/injects.jsonl | Which payload was injected into which session — powers Lineage | yes (destructive) |
search.db | SQLite full-text index over transcripts and payloads. Deleting it just makes the next search slower | yes |
models-pricing.json | Cached model price table | yes |
cursor-usage.json | Token counts captured from the Cursor CLI’s own usage object after a run | — |
tmp/ | Scratch files written while injecting context into sessions; files older than 72 h are garbage-collected | yes |
Settings → threadle internals lists these live, with sizes and file counts, and clears the safe ones.
Content-addressed payloads
Section titled “Content-addressed payloads”A payload’s identity is sha256(kind \0 provider \0 sessionId \0 content). Distill the same session twice with the same result and you get one file, not two.
Each payload is stored twice in the same shard directory:
<hash>.json— the payload object (kind, source, content, metadata)<hash>.md— a plain-text sidecar so the directory is readable by a human or bygrep. Written for every kind exceptfiles.
Writes are atomic: content goes to <hash>.json.tmp and is renamed into place. Graph writes use the same trick with a random suffix.
Because the hash is the identity, a portable graph strips payloadHash on export — the blob is local to the machine that made it.
Overriding the location
Section titled “Overriding the location”| Variable | Effect |
|---|---|
THREADLE_CONFIG_DIR | Replaces ~/.config/threadle entirely. Every path above is relative to it |
Set it to keep separate profiles, or to point threadle at a scratch directory during experiments:
THREADLE_CONFIG_DIR=/tmp/threadle-scratch threadle --no-openWhat threadle reads but never writes
Section titled “What threadle reads but never writes”Provider storage is parsed in place. Nothing under these paths is ever created, modified, or deleted by threadle.
| Provider | Path | Env override |
|---|---|---|
| Claude Code | ~/.claude/projects/<slug>/<uuid>.jsonl, ~/.claude/history.jsonl, ~/.claude/sessions/*.json, ~/.claude/agents/*.md | CLAUDE_CONFIG_DIR |
| opencode | ~/.local/share/opencode/opencode.db — opened readOnly: true | OPENCODE_DATA_DIR |
| Cursor | ~/.cursor/projects/<slug>/agent-transcripts/…, ~/.cursor/chats/<md5>/…/meta.json | CURSOR_CONFIG_DIR |
Two more files are read but not written: ~/.claude.json (for the detected plan shown in Settings) and ~/.cache/opencode/models.json (preferred source for model prices).
Project directories are read for skills and rules files, and for agent definitions in <projectDir>/.claude/agents/. When you run an agent, the agent’s own CLI writes its own session storage exactly as it would from a terminal — that writing belongs to the tool, not to threadle.
Related
Section titled “Related”- Settings — the keys inside
settings.json - Trust model — the read-only guarantee in full
- Providers — how each storage format is parsed
- CLI — where a headless run persists its results