Selected work / Code explorer

Threadmark

A map is useful when you can check where each edge came from.

Threadmark helps me follow dependencies through unfamiliar JavaScript, TypeScript and Python repositories. The Windows app and CLI share a Rust engine; source code stays on the machine.

Project
Personal software project
Stack
Rust, Tauri, React, SQLite, Tree-sitter
Stage
Early release candidate · v0.1.1
Release

Windows builds are unsigned. Read installation notes and limits ↗

The question behind the interface

Searching a name gives me occurrences. It does not tell me whether one function calls another, which relationship was resolved, or what an edit might reach. Threadmark brings those questions into one view, then lets me open the source behind an answer.

The project includes the analysis engine, local persistence, CLI and desktop interface. The useful boundary is between understanding code and presenting it: the interface should ask for a neighbourhood, not become a second analysis engine.

Watch the desktop app · 45 seconds

Threadmark 0.1.1, recorded in the native Windows app on 10 October 2026 using a forecast-service sample repository. Silent, real-time capture; no cursor overlay. Download MP4 · Read transcript
Video transcript and setup

Start with forecast.ts in the relationship map. Select the import from forecast.test.ts to inspect its exact source evidence. Switch to Impact to see reverse static reachability, then expand the controller.ts evidence path. Static reachability does not guarantee runtime impact.

The code is a small TypeScript and Python fixture, not a production application.

Interface walkthrough

Open a step to inspect the capture. Each image can be opened at full size.

01 Follow a relationship

The repository tree, directed relationship map and inspector share the selected symbol.

The repository tree, directed relationship map and inspector share the selected symbol.
Threadmark · Follow a relationship. Open full image ↗
02 Inspect the evidence

The source inspector places relationship evidence beside the code it came from.

The source inspector places relationship evidence beside the code it came from.
Threadmark · Inspect the evidence. Open full image ↗
03 Compare a change

The Changes view separates added, removed and modified symbols in a local Git comparison.

The Changes view separates added, removed and modified symbols in a local Git comparison.
Threadmark · Compare a change. Open full image ↗

These Threadmark captures render the frontend with responses recorded from its Rust engine against local example repositories. They show the interface, not a native session recording. Capture details ↗

Try a small example

Which code depends on this?

This hand-written sample explains directed relationships. It does not run Threadmark or analyse your files.

function readConfig() { return { limit: 10 }; }
function loadItems() { return readConfig().limit; }
function renderList() { return loadItems(); }
function exportItems() { return loadItems(); }

readConfig

Direct dependencies: none in this sample.

Reverse reachability: loadItems, renderList, exportItems.

A path through a static graph is a reason to investigate. It does not prove that every caller will run.

Two boundaries worth keeping

One engine for two clients

Rust owns discovery, Tree-sitter adapters, resolution, graph queries and Git comparison. React owns interaction and layout. Both the desktop app and CLI call the same engine. This keeps a relationship's meaning consistent whichever way I inspect it.

The desktop requests up to 24 nodes in a neighbourhood. The engine marks limits explicitly, so a bounded view cannot silently imply that no other dependencies exist.

Identity is separate from location

Symbol IDs use repository, path, language, qualified name and kind. Line numbers are excluded. Adding blank lines should move the source span without making every symbol look newly added. Renaming a file still changes identity and currently appears as additions and removals.

Architecture and decisions ↗ · Why evidence belongs beside an edge →

A cache hit does not make the work free

Version 0.1.1, measured on 7 October 2026. Generated TypeScript fixtures, ten functions per file, single run.

Documented engine measurements, not desktop latency promises
Files / functions New index Unchanged refresh One-file update Peak working set
100 / 1,000 102 ms 48 ms 60 ms 21 MiB
1,000 / 10,000 673 ms 307 ms 383 ms 86 MiB
10,000 / 100,000 7.40 s 3.52 s 4.60 s 731 MiB

Conditions matter

Windows 11 x64 · Intel Core i7-1365U · 16 GB RAM · Rust 1.98.1 release build. No concurrent build. OS filesystem caches were not flushed: “new index” means a new database and parse cache, not a physically cold disk.

Whole-graph resolution and snapshot persistence still run during a refresh. Reusing parses helps, but does not remove those costs. The first adjacency load and broad real-world graphs add work not captured by a small warm query.

Method, reproduction command and raw results ↗ · Read the performance note →

Where the answers stop

Static evidence cannot resolve arbitrary runtime dispatch, reflection or computed imports. Reverse impact is graph reachability, not a prediction of execution or test coverage. Git renames are not yet tracked as continuous identities.

The next useful improvements are affected-subgraph resolution and more efficient persistence, followed by broader desktop and long-session measurements. Linux and macOS have not been validated.

Next: Benchlight →