The Problem: JavaScript and the UI Bottleneck
Initially, I tried doing the text extraction in vanilla JavaScript. The logic was simple: read the DOM, extract the text, find the keywords, and relate them.
The reality was a nightmare.
When you try to process a 10,000-word chat history, tokenize it, and run ranking algorithms on it, JavaScript’s single-threaded nature rears its ugly head. The browser extension would hang. The UI would freeze. On top of that, pulling in a heavy machine-learning model to summarize the text goes against the core philosophy of this tool: It needs to be instant, lightweight, and 100% local. No external APIs.
The Solution: C++ and WebAssembly (WASM)
I needed system-level performance inside the browser. So, I pivoted the core engine to C++ compiled to WebAssembly (WASM).
By offloading the heavy lifting to a C++ WASM module, the extension can chew through massive conversation logs in milliseconds without blocking the main browser thread. It’s deterministic, memory-efficient, and feels incredibly snappy.
But C++ alone doesn't solve the logic problem. To build the actual graph, I needed a way to figure out what words actually mattered without asking an LLM to do it for me.
Enter TextRank & the Porter Stemmer Algorithm
Instead of using modern AI to parse the AI chat, I went back to battle-tested Natural Language Processing (NLP) algorithms.
- The Porter Stemmer Algorithm: Before we can rank anything, we need to clean the data. The Stemmer algorithm normalizes words down to their root. It turns "coding," "coder," and "codes" into simply "code." This is crucial for building our JSON graph because it prevents duplicate nodes and keeps the payload highly compressed.
- TextRank: This is the secret sauce. TextRank is essentially Google’s PageRank algorithm, but applied to graphs of text rather than web pages. By running TextRank in C++, the engine builds a matrix of how words co-occur in the chat. The words that have the highest "votes" (connections) become the core nodes in our JSON Graph.
The Bridge: The "Inject" Feature
Once the WASM engine spits out this beautiful, compressed JSON state graph, how does it get to the new LLM?
To make the UX seamless, I built an Inject feature. When you are ready to migrate, the extension directly opens the target LLM in a new tab (e.g., a fresh Claude window) and utilizes a fallback mechanism to automatically copy-paste the structured JSON dump directly into the chat box.
You click one button, the new tab opens, the JSON graph is pasted, and the new model instantly understands your exact working state.
Try It Out / Contribute
Thread is currently in the testing phase, and the core C++ WASM pipeline is operational. If you are interested in local-first browser tools, C++ WASM integration, or just want a better way to manage your AI contexts, I’d love your feedback!
🔗 https://www.github.com/Arham-Qureshi/Thread
Drop a star, break the code, or open an issue.
Top comments (0)