<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mayne</title>
    <description>The latest articles on DEV Community by Mayne (@mayne-x).</description>
    <link>https://dev.to/mayne-x</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3990135%2F1f40403a-91cd-4fd8-a473-ba41cdcf323c.png</url>
      <title>DEV Community: Mayne</title>
      <link>https://dev.to/mayne-x</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mayne-x"/>
    <language>en</language>
    <item>
      <title>ThinkGraph Tutorial: How to Make Your LLM Actually Think Before Answering</title>
      <dc:creator>Mayne</dc:creator>
      <pubDate>Wed, 01 Jul 2026 18:39:51 +0000</pubDate>
      <link>https://dev.to/mayne-x/thinkgraph-tutorial-how-to-make-your-llm-actually-think-before-answering-3amj</link>
      <guid>https://dev.to/mayne-x/thinkgraph-tutorial-how-to-make-your-llm-actually-think-before-answering-3amj</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/mayne-x/thinkgraph-give-your-llm-a-50-accuracy-boost-by-building-a-fact-foundation-first-lck"&gt;previous article&lt;/a&gt;, I introduced &lt;a href="https://github.com/Mayne-X/thinkgraph" rel="noopener noreferrer"&gt;ThinkGraph&lt;/a&gt; -- an open-source pipeline that forces LLMs to decompose complex prompts into atomic fact DAGs before answering. This time, let's get hands-on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Will Learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to install ThinkGraph for Claude Code, OpenCode, Cursor, and others&lt;/li&gt;
&lt;li&gt;How to use the CLI for step-by-step prompt decomposition&lt;/li&gt;
&lt;li&gt;How self-consistency voting catches hallucinations&lt;/li&gt;
&lt;li&gt;How web grounding fills knowledge gaps without API keys&lt;/li&gt;
&lt;li&gt;How to integrate ThinkGraph as an MCP server&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Mayne-X/thinkgraph.git
&lt;span class="nb"&gt;cd &lt;/span&gt;thinkgraph

&lt;span class="c"&gt;# Auto-detect and install for all your agents&lt;/span&gt;
python install.py

&lt;span class="c"&gt;# See what it would do without touching files&lt;/span&gt;
python install.py &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer detects OpenCode, Claude Code, Cursor, Codex, Copilot, and Gemini CLI configs and injects the appropriate adapter. Idempotent -- safe to re-run.&lt;/p&gt;

&lt;h2&gt;
  
  
  CLI Tutorial: Decompose a Complex Prompt
&lt;/h2&gt;

&lt;p&gt;Let's walk through a real example. Say you ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Should we migrate our PostgreSQL database to CockroachDB for a multi-region SaaS product?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 1: Triage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py triage &lt;span class="s2"&gt;"Should we migrate our PostgreSQL database to CockroachDB for a multi-region SaaS product?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: &lt;code&gt;multi-hop&lt;/code&gt; -- not trivial, enters the pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Decompose into DAG
&lt;/h3&gt;

&lt;p&gt;The agent (not the CLI) generates a dependency graph like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What are CockroachDB's multi-region capabilities?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What are PostgreSQL's multi-region limitations?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What is the migration complexity from PG to CockroachDB?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Q1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Q2"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What is the cost comparison for our scale?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Q1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Q2"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Should we migrate given Q1-Q4?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Q3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Q4"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Validate the DAG
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py validate-dag graph.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checks for cycles, dangling deps, orphan nodes, and computes execution batches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Batch 0: Q1, Q2 (parallel)
Batch 1: Q3, Q4 (parallel)
Batch 2: Q5 (needs Q3 + Q4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Resolve with Web Grounding
&lt;/h3&gt;

&lt;p&gt;Low-confidence sub-questions (&amp;lt; 0.6) can trigger automatic web search:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py web-search &lt;span class="s2"&gt;"CockroachDB multi-region latency benchmark 2026"&lt;/span&gt; &lt;span class="nt"&gt;--num-results&lt;/span&gt; 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No API key needed -- ThinkGraph parses DuckDuckGo results directly via HTTP. This is huge for automated pipelines where you don't want to manage search API credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Cache Results
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py cache-set &lt;span class="s2"&gt;"what are cockroachdb multi-region capabilities"&lt;/span&gt; &lt;span class="s1"&gt;'{"claim": "CockroachDB offers automated partitioning, survivable across regions", "confidence": 0.92}'&lt;/span&gt;
python cli/thinkgraph.py cache-get &lt;span class="s2"&gt;"what are cockroachdb multi-region capabilities"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Facts persist globally at &lt;code&gt;~/.thinkgraph/cache.json&lt;/code&gt; -- shared across projects and sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Self-Consistency Vote
&lt;/h3&gt;

&lt;p&gt;Run synthesis 2-3 times, then vote on consistency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py vote &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"CockroachDB is better for multi-region due to automated survivability"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"CockroachDB offers better multi-region support with automated partitioning and survivability"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"For multi-region, CockroachDB has automated survivability which PostgreSQL lacks"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output picks the Jaccard centroid -- the response with highest average word overlap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"winner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CockroachDB offers better multi-region support..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"scores"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.68&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"response_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7: Prune Unnecessary Nodes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py prune-dag graph.json &lt;span class="nt"&gt;--facts&lt;/span&gt; facts.json &lt;span class="nt"&gt;--prompt&lt;/span&gt; &lt;span class="s2"&gt;"Should we migrate PostgreSQL to CockroachDB?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a parent node's answer already covers a child's question, the child is auto-removed. Saves tokens without losing information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Export as Report
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py &lt;span class="nb"&gt;export &lt;/span&gt;results.json &lt;span class="nt"&gt;--format&lt;/span&gt; markdown &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; migration-analysis.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supports JSON, YAML, and Markdown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using ThinkGraph as an MCP Server
&lt;/h2&gt;

&lt;p&gt;This is the slickest integration path. Start the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python mcp/thinkgraph_mcp.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure any MCP-compatible client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"thinkgraph"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/thinkgraph/mcp/thinkgraph_mcp.py"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seven tools are exposed: triage, validate-dag, vote, web-search, cache-get, cache-set, tokens. Your MCP client can call these directly without the CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  A/B Testing Your Prompts
&lt;/h2&gt;

&lt;p&gt;Want to prove ThinkGraph improves quality? Use the A/B scorer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py ab-score &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"CockroachDB supports multi-region deployments"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ground-truth&lt;/span&gt; &lt;span class="s2"&gt;"CockroachDB supports multi-region deployments with automated partitioning and survivability across regions"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;keyword_recall&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;66.67%&lt;/span&gt;
&lt;span class="na"&gt;precision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100.00%&lt;/span&gt;
&lt;span class="na"&gt;claim_count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;uncertainty_markers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compressing Long Contexts
&lt;/h2&gt;

&lt;p&gt;When synthesis context is too long, compress it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py compress long_spec.txt &lt;span class="nt"&gt;--ratio&lt;/span&gt; 0.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uses TF-IDF sentence extraction to keep the 30% most important content. No embeddings, no API calls -- pure term-frequency math in stdlib Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Custom Plugins
&lt;/h2&gt;

&lt;p&gt;Need a custom resolve function? Register a plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli/thinkgraph.py plugin-register my_db_lookup &lt;span class="s1"&gt;'def fn(q, ctx): return {"claim": db.query(q), "confidence": 0.95}'&lt;/span&gt;
python cli/thinkgraph.py plugin-list
&lt;span class="c"&gt;# my_db_lookup, shell, weblookup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Token Math
&lt;/h2&gt;

&lt;p&gt;ThinkGraph sets a hard ceiling of &lt;strong&gt;4x the direct answer tokens&lt;/strong&gt;. If the pipeline would exceed that, it aborts to a direct answer. Here's the budget for each stage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Max Tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Triage&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decompose&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per sub-question&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Synthesize&lt;/td&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard ceiling&lt;/td&gt;
&lt;td&gt;4x direct answer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This means simple prompts (&amp;lt; 200 tokens) bypass the pipeline entirely. You never pay more than 4x, and most of the time you pay far less.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Zero Dependencies Matters
&lt;/h2&gt;

&lt;p&gt;The entire CLI is &lt;strong&gt;Python 3.8+ stdlib only&lt;/strong&gt;. No pip install. No venv. No requirements.txt. Precompiled regex, LRU cache decorators, and sets for membership. It runs anywhere Python runs -- including CI runners, Docker scratch containers, and air-gapped environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Suite
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python tests/test_golden.py       &lt;span class="c"&gt;# 15/15 passing&lt;/span&gt;
python tests/test_new_features.py &lt;span class="c"&gt;# 14/14 passing&lt;/span&gt;
python tests/benchmark.py         &lt;span class="c"&gt;# 10-prompt quality benchmark&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benchmark scores triage accuracy at 80%, compression quality at 70%, and vote consistency at 64% -- solid baselines that improve with use.&lt;/p&gt;

&lt;h2&gt;
  
  
  When NOT to Use ThinkGraph
&lt;/h2&gt;

&lt;p&gt;Honest answer: don't use it for simple Q&amp;amp;A ("What is the capital of France?"). The triage stage catches trivial prompts and short-circuits. Also don't use it for creative writing -- decomposition kills flow. But for any prompt involving comparison, planning, analysis, or multi-step reasoning, it shines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;The entire project is MIT-licensed at &lt;a href="https://github.com/Mayne-X/thinkgraph" rel="noopener noreferrer"&gt;github.com/Mayne-X/thinkgraph&lt;/a&gt;. Star it, fork it, break it, fix it. Contributions welcome.&lt;/p&gt;

&lt;p&gt;If you want the big-picture overview first, read my &lt;a href="https://dev.to/mayne-x/thinkgraph-give-your-llm-a-50-accuracy-boost-by-building-a-fact-foundation-first-lck"&gt;introductory article&lt;/a&gt;. Or just clone the repo and run &lt;code&gt;python cli/thinkgraph.py triage&lt;/code&gt; on your hardest prompt right now.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ThinkGraph forces structured thinking before guessing. Your prompts deserve a foundation, not a hallucination.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>38+ Cryptographic Algorithms in Pure Zig - Zero Dependencies, Zero Std Imports</title>
      <dc:creator>Mayne</dc:creator>
      <pubDate>Wed, 01 Jul 2026 17:05:36 +0000</pubDate>
      <link>https://dev.to/mayne-x/38-cryptographic-algorithms-in-pure-zig-zero-dependencies-zero-std-imports-2h41</link>
      <guid>https://dev.to/mayne-x/38-cryptographic-algorithms-in-pure-zig-zero-dependencies-zero-std-imports-2h41</guid>
      <description>&lt;p&gt;I just open-sourced a collection of &lt;strong&gt;38+ cryptographic algorithms&lt;/strong&gt; written entirely in pure &lt;a href="https://ziglang.org" rel="noopener noreferrer"&gt;Zig&lt;/a&gt; -- zero external dependencies, zero &lt;code&gt;std&lt;/code&gt; library imports, zero dynamic allocation.&lt;/p&gt;

&lt;p&gt;The repo is called &lt;a href="https://github.com/Mayne-X/Cryptographic-Algorithms-for-Ziglang" rel="noopener noreferrer"&gt;Cryptographic Algorithms for Ziglang&lt;/a&gt; and the constraint was simple: every algorithm had to be self-contained with no libsodium, no OpenSSL, no nothing. Just bare Zig.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Inside
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;17 Hash Functions:&lt;/strong&gt; SHA-256/512, SHA3-256, SHAKE128/256, BLAKE2b, BLAKE3, BLAKE2s, RIPEMD-160/320, Whirlpool, Tiger, MD5, SHA-1, SHA-224/384, Skein-256/512, Grostl-256/512, JH-256/512&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6 Symmetric Ciphers:&lt;/strong&gt; AES-128/256, ChaCha20 + HChaCha20, ChaCha20-Poly1305 (AEAD), TripleDES, Blowfish, Poly1305&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 Password Hashing &amp;amp; KDFs:&lt;/strong&gt; PBKDF2, bcrypt, scrypt, Argon2id (RFC 9106), HKDF (RFC 5869)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6 Asymmetric Crypto &amp;amp; Key Exchange:&lt;/strong&gt; RSA (OAEP/PSS, up to 2048-bit), Diffie-Hellman + X25519, ECDSA (secp256k1), EdDSA (Ed25519), BLS (BLS12-381), Schnorr (secp256k1)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4 Post-Quantum Schemes:&lt;/strong&gt; ML-KEM (Kyber768), ML-DSA (Dilithium65), SLH-DSA (SPHINCS+), NTRU (HPS2048509)&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;Zig is gaining traction in systems programming, embedded, and -- critically -- blockchain development. But the Zig ecosystem lacks a comprehensive, self-contained cryptography library. Most projects either link OpenSSL (defeating Zig's cross-compilation advantage) or vendor scattered implementations.&lt;/p&gt;

&lt;p&gt;This repo fixes that. Every algorithm lives in a single &lt;code&gt;.zig&lt;/code&gt; file with embedded test vectors from RFCs and NIST standards. Run &lt;code&gt;zig test filename.zig&lt;/code&gt; and you're done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hard Parts
&lt;/h2&gt;

&lt;p&gt;The "zero std imports" constraint meant writing from scratch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;2048-bit BigInt&lt;/strong&gt; (64 u64 limbs) for RSA and DSA arithmetic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endianness conversion&lt;/strong&gt;, bitwise rotation, memory copy -- all hand-rolled&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elliptic curve math&lt;/strong&gt; for secp256k1, Curve25519, and BLS12-381&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NTT polynomial multiplication&lt;/strong&gt; for ML-KEM and ML-DSA (post-quantum)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No &lt;code&gt;std.mem&lt;/code&gt;, no &lt;code&gt;std.math&lt;/code&gt;, no &lt;code&gt;std.crypto&lt;/code&gt;. It forced a deep understanding of every algorithm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blockchain Ready
&lt;/h2&gt;

&lt;p&gt;The algorithm choices are tailored for blockchain work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;secp256k1 ECDSA&lt;/strong&gt; -- Bitcoin transaction signing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ed25519&lt;/strong&gt; -- Solana and many modern chains&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schnorr&lt;/strong&gt; -- Taproot upgrade signatures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SHA-256 + RIPEMD-160&lt;/strong&gt; -- Bitcoin address derivation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BLS12-381&lt;/strong&gt; -- aggregated signatures for consensus&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Mayne-X/Cryptographic-Algorithms-for-Ziglang.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Cryptographic-Algorithms-for-Ziglang

&lt;span class="c"&gt;# Run all tests&lt;/span&gt;
zig build &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# Or test a single file&lt;/span&gt;
zig &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"Cryptographic Hash Functions/SHA-256.zig"&lt;/span&gt;
zig &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"Symmetric Key Cryptography/AES.zig"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Requires Zig &amp;gt;= 0.13.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Principles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero std imports&lt;/strong&gt; -- every utility is handwritten&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero dependencies&lt;/strong&gt; -- pure Zig, no external crates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No dynamic allocation&lt;/strong&gt; -- all fixed-size stack arrays&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedded test vectors&lt;/strong&gt; -- every file tests against known RFC/NIST vectors&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations (Honest Ones)
&lt;/h2&gt;

&lt;p&gt;The post-quantum implementations are simplified -- self-consistent but not fully RFC-compliant. BigInt maxes at 2048 bits (enough for RSA-2048, not larger). BLS is a stub with curve constants but no pairing math yet. These are clearly documented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Involved
&lt;/h2&gt;

&lt;p&gt;The entire project is MIT-licensed and available on GitHub at &lt;a href="https://github.com/Mayne-X/Cryptographic-Algorithms-for-Ziglang" rel="noopener noreferrer"&gt;Cryptographic Algorithms for Ziglang&lt;/a&gt;. Stars, issues, and PRs welcome.&lt;/p&gt;

&lt;p&gt;If you are building a Zig-based blockchain, embedded system, or just want to learn how crypto works under the hood by reading clean Zig code, this repo is for you.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>opensource</category>
      <category>security</category>
      <category>showdev</category>
    </item>
    <item>
      <title>ThinkGraph - Give Your LLM a 50% Accuracy Boost by Building a Fact Foundation First</title>
      <dc:creator>Mayne</dc:creator>
      <pubDate>Wed, 01 Jul 2026 17:02:24 +0000</pubDate>
      <link>https://dev.to/mayne-x/thinkgraph-give-your-llm-a-50-accuracy-boost-by-building-a-fact-foundation-first-lck</link>
      <guid>https://dev.to/mayne-x/thinkgraph-give-your-llm-a-50-accuracy-boost-by-building-a-fact-foundation-first-lck</guid>
      <description>&lt;h1&gt;
  
  
  ThinkGraph: Structured Decomposition for LLM Prompts
&lt;/h1&gt;

&lt;p&gt;Every developer using LLMs has experienced this: you ask a complex question, and the model guesses the whole answer at once. It hallucinates details, misses constraints, and assumes facts it should verify first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ThinkGraph&lt;/strong&gt; is an open-source skill that intercepts prompts, forces the LLM to decompose them into a dependency graph of atomic facts, resolves those facts sequentially, and &lt;strong&gt;then&lt;/strong&gt; synthesizes a grounded answer.&lt;/p&gt;

&lt;p&gt;The result? 50%+ accuracy improvement on multi-hop prompts while actually &lt;em&gt;saving&lt;/em&gt; tokens on simple ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: LLMs Guess Whole Answers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prompt: "Compare React and Vue for a large enterprise dashboard with SSR requirements"

X LLM guesses React is better without checking:
   - SSR maturity of each framework
   - Enterprise adoption rates
   - Team size implications
   - Bundle size trade-offs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Solution: Build a Foundation First
&lt;/h2&gt;

&lt;p&gt;ThinkGraph adds a 5-stage pipeline before the final answer:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Triage
&lt;/h3&gt;

&lt;p&gt;Classify the prompt: trivial? Answer directly (save tokens). Multi-hop/planning? Enter the pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Decompose
&lt;/h3&gt;

&lt;p&gt;Break the prompt into a DAG of atomic sub-questions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What is React's SSR maturity?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What is Vue's SSR maturity?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Which has better enterprise adoption?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Given Q1-Q3, which is better for a 10-person team?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Q1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Q2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Q3"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Resolve
&lt;/h3&gt;

&lt;p&gt;Answer each node in topological order. Parallelize independent nodes. Each answer carries a confidence score:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Q1 - React 18+ supports streaming SSR (conf: 0.92)
Q2 - Vue 3 has SSR via Nuxt 3 (conf: 0.88)
Q3 - React is more widely adopted in enterprise (conf: 0.85)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Low-confidence facts (&amp;lt;0.6) can be auto-web-searched via DuckDuckGo - no API key needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Self-Consistency Vote
&lt;/h3&gt;

&lt;p&gt;Run the synthesis stage 2-3 times, then pick the Jaccard centroid - the response with highest average word overlap with all others.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Synthesize
&lt;/h3&gt;

&lt;p&gt;Feed ONLY verified sub-facts into the final prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token Efficiency
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Max Tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Triage&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decompose&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per sub-question&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Synthesize&lt;/td&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard ceiling&lt;/td&gt;
&lt;td&gt;4x direct answer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Key Design Decisions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No API keys required.&lt;/strong&gt; The helper CLI does deterministic bookkeeping only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;stdlib only (Python).&lt;/strong&gt; Zero dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Works with 6+ agents.&lt;/strong&gt; OpenCode, Claude Code, Cursor, Codex, Copilot, Gemini CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Mayne-X/thinkgraph.git
&lt;span class="nb"&gt;cd &lt;/span&gt;thinkgraph
python install.py
python thinkgraph.py triage &lt;span class="s2"&gt;"compare React and Vue for enterprise SSR"&lt;/span&gt;
python thinkgraph.py validate-dag graph.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MCP Server
&lt;/h2&gt;

&lt;p&gt;ThinkGraph also ships as an MCP server (7 tools):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"thinkgraph"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/mcp/thinkgraph_mcp.py"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CLI interactive mode&lt;/li&gt;
&lt;li&gt;Multi-model routing&lt;/li&gt;
&lt;li&gt;Streaming DAG emission&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Mayne-X/thinkgraph" rel="noopener noreferrer"&gt;github.com/Mayne-X/thinkgraph&lt;/a&gt;&lt;br&gt;
MIT License&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ThinkGraph forces structured thinking before guessing. Your prompts deserve a foundation, not a hallucination.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I reclaimed 12GB from my SSD with one terminal command (and you can too)</title>
      <dc:creator>Mayne</dc:creator>
      <pubDate>Thu, 18 Jun 2026 11:21:50 +0000</pubDate>
      <link>https://dev.to/mayne-x/i-reclaimed-12gb-from-my-ssd-with-one-terminal-command-and-you-can-too-3g9k</link>
      <guid>https://dev.to/mayne-x/i-reclaimed-12gb-from-my-ssd-with-one-terminal-command-and-you-can-too-3g9k</guid>
      <description>&lt;p&gt;I've been a developer for over a decade, and if there's one thing I've learned, it's that our hard drives are basically landfills for build artifacts.&lt;/p&gt;

&lt;p&gt;A few weeks ago, I was down to &lt;strong&gt;2GB free&lt;/strong&gt; on my main SSD. Not because I had tons of important files — but because I had years worth of &lt;code&gt;node_modules&lt;/code&gt; folders, &lt;code&gt;.next&lt;/code&gt; build caches, &lt;code&gt;dist&lt;/code&gt; directories, and other junk scattered across dozens of old projects.&lt;/p&gt;

&lt;p&gt;I tried reclaiming space manually. You know the drill — &lt;code&gt;du -sh&lt;/code&gt; to find the culprits, then &lt;code&gt;rm -rf&lt;/code&gt; them one by one. It works, but it's tedious. I tried &lt;code&gt;npkill&lt;/code&gt; — it only handles &lt;code&gt;node_modules&lt;/code&gt;. I tried &lt;code&gt;wipe-modules&lt;/code&gt; — same limitation. I wanted something that could find everything at once and let me pick what to delete in one go.&lt;/p&gt;

&lt;p&gt;So I built ZapDir.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ZapDir?
&lt;/h2&gt;

&lt;p&gt;ZapDir is a terminal cleanup tool that scans your projects for heavy build artifacts and lets you delete them through a beautiful interactive interface. It's completely free, open-source under MIT, and runs on Windows, macOS, and Linux with Node.js 18+.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; zapdir
zapdir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that, and you'll see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚡  ZapDir  —  Terminal Cleanup Tool

  🗑  Junk Found — Total recoverable:  1.47 GB

  ██████████  node_modules    /node_modules      245.23 MB
  ██████░░░░  .next           /.next               1.23 GB
  ██░░░░░░░░  dist            /dist                89.45 MB

  ✔  Delete 3 item(s) freeing 1.47 GB?  ·  Yes

  ✔  Freed 1.47 GB of disk space!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The colored size bars make it obvious what's eating the most space at a glance — red for anything over 500MB, yellow for over 100MB, and green for the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes it different from npkill or wipe-modules?
&lt;/h2&gt;

&lt;p&gt;There are other cleanup tools out there, but most of them only handle one pattern. Here's how ZapDir compares:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;ZapDir&lt;/th&gt;
&lt;th&gt;npkill&lt;/th&gt;
&lt;th&gt;wipe-modules&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Patterns detected&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;13+&lt;/td&gt;
&lt;td&gt;1 (node_modules)&lt;/td&gt;
&lt;td&gt;1 (node_modules)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Interactive TUI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Color-coded sizes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dry-run preview&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Async scanner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cross-platform&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ZapDir detects: &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;.next&lt;/code&gt;, &lt;code&gt;.nuxt&lt;/code&gt;, &lt;code&gt;.turbo&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;.cache&lt;/code&gt;, &lt;code&gt;coverage&lt;/code&gt;, &lt;code&gt;out&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt;, &lt;code&gt;.parcel-cache&lt;/code&gt;, &lt;code&gt;__pycache__&lt;/code&gt;, and &lt;code&gt;.DS_Store&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it found on my machine
&lt;/h2&gt;

&lt;p&gt;I ran ZapDir across my development machine and here's what turned up:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;What was there&lt;/th&gt;
&lt;th&gt;Space recovered&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;~/Projects/legacy-app&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;node_modules&lt;/code&gt; + &lt;code&gt;.next&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1.8 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~/Projects/side-project&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;node_modules&lt;/code&gt; + &lt;code&gt;build&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;640 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~/Projects/old-tutorial&lt;/td&gt;
&lt;td&gt;&lt;code&gt;node_modules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;420 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~/.cache&lt;/td&gt;
&lt;td&gt;Various caches&lt;/td&gt;
&lt;td&gt;340 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Various Rust projects&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;target/&lt;/code&gt; directories&lt;/td&gt;
&lt;td&gt;2.1 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Old Next.js projects&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.next&lt;/code&gt; caches&lt;/td&gt;
&lt;td&gt;3.4 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abandoned monorepos&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;node_modules&lt;/code&gt; × 5&lt;/td&gt;
&lt;td&gt;2.2 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python projects&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;__pycache__&lt;/code&gt; + &lt;code&gt;.cache&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;180 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total reclaimed: roughly 12 GB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's 12 GB I got back without touching a single file I actually needed. The biggest wins were old Next.js projects with massive &lt;code&gt;.next&lt;/code&gt; caches (some over 1 GB each) and Rust projects where &lt;code&gt;target/&lt;/code&gt; directories had accumulated to over 2 GB combined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it safe?
&lt;/h2&gt;

&lt;p&gt;Short answer: yes, if you use &lt;code&gt;--dry-run&lt;/code&gt; first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zapdir &lt;span class="nt"&gt;--dry-run&lt;/span&gt; ~/Projects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This scans and shows you exactly what would be deleted without actually removing anything. The output shows every item with its size, path, and a visual bar so you know exactly what you're getting into.&lt;/p&gt;

&lt;p&gt;When you're satisfied with the preview, run it without the flag. You'll be prompted to confirm before anything is deleted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔  Delete 3 item(s) freeing 1.47 GB?  ·  Yes / No
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scanner uses &lt;code&gt;fs.promises.readdir&lt;/code&gt; with async parallel traversal for speed, and deletion is done with &lt;code&gt;Promise.allSettled&lt;/code&gt; so a permission error on one file won't crash the entire operation — it just skips that file and continues. I've been using it for weeks and haven't lost a single file I needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the scanning works
&lt;/h2&gt;

&lt;p&gt;The core logic is surprisingly straightforward. It walks directories recursively using Node.js's built-in &lt;code&gt;fs.promises&lt;/code&gt;, matches directory names against a list of known artifact patterns, calculates sizes using a streaming iterator (to avoid memory issues on huge folders), and presents everything in an interactive selection menu powered by &lt;code&gt;@clack/prompts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hidden directories like &lt;code&gt;.git&lt;/code&gt; are skipped by default for speed. The entire scan of my home directory — thousands of folders — completes in under 10 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical tip
&lt;/h2&gt;

&lt;p&gt;Here's what I do now: once a month, I run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zapdir &lt;span class="nt"&gt;--dry-run&lt;/span&gt; ~/Projects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives me a quick health check of how much junk has accumulated. When the number crosses 1 GB, I run it for real and reclaim the space. It's become part of my regular maintenance routine, right alongside &lt;code&gt;brew update&lt;/code&gt; and &lt;code&gt;npm outdated&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give it a shot
&lt;/h2&gt;

&lt;p&gt;If you're running low on disk space and have old projects lying around, try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; zapdir
zapdir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It takes five seconds to install and could free up gigabytes. The code is open source under MIT, so you can inspect exactly what it does before running it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Mayne-X/Zapdir" rel="noopener noreferrer"&gt;⭐ Star the repo on GitHub&lt;/a&gt;&lt;/strong&gt; if you find it useful — it helps other developers discover it too.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ZapDir is MIT licensed and open source. Contributions, feature requests, and bug reports are welcome on GitHub.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>productivity</category>
      <category>node</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Blazing-fast terminal cleanup tool for heavy build artifacts</title>
      <dc:creator>Mayne</dc:creator>
      <pubDate>Thu, 18 Jun 2026 08:45:25 +0000</pubDate>
      <link>https://dev.to/mayne-x/blazing-fast-terminal-cleanup-tool-for-heavy-build-artifacts-2doo</link>
      <guid>https://dev.to/mayne-x/blazing-fast-terminal-cleanup-tool-for-heavy-build-artifacts-2doo</guid>
      <description>&lt;p&gt;I've been a developer for over a decade, and if there's one thing I've learned, it's that our hard drives are basically landfills for build artifacts.&lt;/p&gt;

&lt;p&gt;A few weeks ago, I was down to &lt;strong&gt;2GB free&lt;/strong&gt; on my main SSD. Not because I had tons of important files — but because I had years worth of &lt;code&gt;node_modules&lt;/code&gt; folders, &lt;code&gt;.next&lt;/code&gt; build caches, &lt;code&gt;dist&lt;/code&gt; directories, and other junk scattered across dozens of old projects.&lt;/p&gt;

&lt;p&gt;I tried reclaiming space manually. You know the drill — &lt;code&gt;du -sh&lt;/code&gt; to find the culprits, then &lt;code&gt;rm -rf&lt;/code&gt; them one by one. It works, but it's tedious. I tried &lt;code&gt;npkill&lt;/code&gt; — it only handles &lt;code&gt;node_modules&lt;/code&gt;. I tried &lt;code&gt;wipe-modules&lt;/code&gt; — same limitation. I wanted something that could find everything at once and let me pick what to delete in one go.&lt;/p&gt;

&lt;p&gt;So I built ZapDir.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ZapDir?
&lt;/h2&gt;

&lt;p&gt;ZapDir is a terminal cleanup tool that scans your projects for heavy build artifacts and lets you delete them through a beautiful interactive interface. It's completely free, open-source under MIT, and runs on Windows, macOS, and Linux with Node.js 18+.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; zapdir
zapdir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that, and you'll see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚡  ZapDir  —  Terminal Cleanup Tool

  🗑  Junk Found — Total recoverable:  1.47 GB

  ██████████  node_modules    /node_modules      245.23 MB
  ██████░░░░  .next           /.next               1.23 GB
  ██░░░░░░░░  dist            /dist                89.45 MB

  ✔  Delete 3 item(s) freeing 1.47 GB?  ·  Yes

  ✔  Freed 1.47 GB of disk space!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The colored size bars make it obvious what's eating the most space at a glance — red for anything over 500MB, yellow for over 100MB, and green for the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes it different from npkill or wipe-modules?
&lt;/h2&gt;

&lt;p&gt;There are other cleanup tools out there, but most of them only handle one pattern. Here's how ZapDir compares:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;ZapDir&lt;/th&gt;
&lt;th&gt;npkill&lt;/th&gt;
&lt;th&gt;wipe-modules&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Patterns detected&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;13+&lt;/td&gt;
&lt;td&gt;1 (node_modules)&lt;/td&gt;
&lt;td&gt;1 (node_modules)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Interactive TUI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Color-coded sizes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dry-run preview&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Async scanner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cross-platform&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ZapDir detects: &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;.next&lt;/code&gt;, &lt;code&gt;.nuxt&lt;/code&gt;, &lt;code&gt;.turbo&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;.cache&lt;/code&gt;, &lt;code&gt;coverage&lt;/code&gt;, &lt;code&gt;out&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt;, &lt;code&gt;.parcel-cache&lt;/code&gt;, &lt;code&gt;__pycache__&lt;/code&gt;, and &lt;code&gt;.DS_Store&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it found on my machine
&lt;/h2&gt;

&lt;p&gt;I ran ZapDir across my development machine and here's what turned up:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;What was there&lt;/th&gt;
&lt;th&gt;Space recovered&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;~/Projects/legacy-app&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;node_modules&lt;/code&gt; + &lt;code&gt;.next&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1.8 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~/Projects/side-project&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;node_modules&lt;/code&gt; + &lt;code&gt;build&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;640 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~/Projects/old-tutorial&lt;/td&gt;
&lt;td&gt;&lt;code&gt;node_modules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;420 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~/.cache&lt;/td&gt;
&lt;td&gt;Various caches&lt;/td&gt;
&lt;td&gt;340 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Various Rust projects&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;target/&lt;/code&gt; directories&lt;/td&gt;
&lt;td&gt;2.1 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Old Next.js projects&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.next&lt;/code&gt; caches&lt;/td&gt;
&lt;td&gt;3.4 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abandoned monorepos&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;node_modules&lt;/code&gt; × 5&lt;/td&gt;
&lt;td&gt;2.2 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python projects&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;__pycache__&lt;/code&gt; + &lt;code&gt;.cache&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;180 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total reclaimed: roughly 12 GB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's 12 GB I got back without touching a single file I actually needed. The biggest wins were old Next.js projects with massive &lt;code&gt;.next&lt;/code&gt; caches (some over 1 GB each) and Rust projects where &lt;code&gt;target/&lt;/code&gt; directories had accumulated to over 2 GB combined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it safe?
&lt;/h2&gt;

&lt;p&gt;Short answer: yes, if you use &lt;code&gt;--dry-run&lt;/code&gt; first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zapdir &lt;span class="nt"&gt;--dry-run&lt;/span&gt; ~/Projects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This scans and shows you exactly what would be deleted without actually removing anything. The output shows every item with its size, path, and a visual bar so you know exactly what you're getting into.&lt;/p&gt;

&lt;p&gt;When you're satisfied with the preview, run it without the flag. You'll be prompted to confirm before anything is deleted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔  Delete 3 item(s) freeing 1.47 GB?  ·  Yes / No
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scanner uses &lt;code&gt;fs.promises.readdir&lt;/code&gt; with async parallel traversal for speed, and deletion is done with &lt;code&gt;Promise.allSettled&lt;/code&gt; so a permission error on one file won't crash the entire operation — it just skips that file and continues. I've been using it for weeks and haven't lost a single file I needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the scanning works
&lt;/h2&gt;

&lt;p&gt;The core logic is surprisingly straightforward. It walks directories recursively using Node.js's built-in &lt;code&gt;fs.promises&lt;/code&gt;, matches directory names against a list of known artifact patterns, calculates sizes using a streaming iterator (to avoid memory issues on huge folders), and presents everything in an interactive selection menu powered by &lt;code&gt;@clack/prompts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hidden directories like &lt;code&gt;.git&lt;/code&gt; are skipped by default for speed. The entire scan of my home directory — thousands of folders — completes in under 10 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical tip
&lt;/h2&gt;

&lt;p&gt;Here's what I do now: once a month, I run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zapdir &lt;span class="nt"&gt;--dry-run&lt;/span&gt; ~/Projects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives me a quick health check of how much junk has accumulated. When the number crosses 1 GB, I run it for real and reclaim the space. It's become part of my regular maintenance routine, right alongside &lt;code&gt;brew update&lt;/code&gt; and &lt;code&gt;npm outdated&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give it a shot
&lt;/h2&gt;

&lt;p&gt;If you're running low on disk space and have old projects lying around, try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; zapdir
zapdir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It takes five seconds to install and could free up gigabytes. The code is open source under MIT, so you can inspect exactly what it does before running it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Mayne-X/Zapdir" rel="noopener noreferrer"&gt;⭐ Star the repo on GitHub&lt;/a&gt;&lt;/strong&gt; if you find it useful — it helps other developers discover it too.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ZapDir is MIT licensed and open source. Contributions, feature requests, and bug reports are welcome on GitHub.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>node</category>
      <category>tooling</category>
    </item>
    <item>
      <title>PyChase: AST-Powered Duplicate Code Detection for Python</title>
      <dc:creator>Mayne</dc:creator>
      <pubDate>Thu, 18 Jun 2026 04:49:03 +0000</pubDate>
      <link>https://dev.to/mayne-x/pychase-ast-powered-duplicate-code-detection-for-python-3408</link>
      <guid>https://dev.to/mayne-x/pychase-ast-powered-duplicate-code-detection-for-python-3408</guid>
      <description>&lt;h2&gt;
  
  
  The Problem: Hidden Code Duplication
&lt;/h2&gt;

&lt;p&gt;Every codebase accumulates copy-paste clones. They start innocently — "I'll just duplicate this function and tweak it" — but over months they compound into a maintenance tax. When a bug is fixed in one copy, the other 5 copies stay broken. When a feature needs to change, you hunt down every variant by hand.&lt;/p&gt;

&lt;p&gt;Traditional duplicate detectors fall into two camps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Line-based tools&lt;/strong&gt; (Duplo, Simian) — compare raw text, miss everything after variable renaming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token-based tools&lt;/strong&gt; (jscpd, PMD CPD) — slightly better, but still fail when identifiers change&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generic AST tools&lt;/strong&gt; (SonarQube) — heavy infrastructure, Python support is an afterthought&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PyChase takes a different approach: &lt;strong&gt;normalized AST fingerprints with MinHash + LSH&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What PyChase Catches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Clone Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;PyChase&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Type-1&lt;/td&gt;
&lt;td&gt;Exact copy-paste&lt;/td&gt;
&lt;td&gt;Same code, same names&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;1.000 score&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type-2&lt;/td&gt;
&lt;td&gt;Renamed identifiers&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;calculate_total&lt;/code&gt; → &lt;code&gt;compute_sum&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;0.786 score&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type-3&lt;/td&gt;
&lt;td&gt;Modified logic&lt;/td&gt;
&lt;td&gt;Added/removed statements, reordered&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;0.620 score&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Parse to AST
&lt;/h3&gt;

&lt;p&gt;Each &lt;code&gt;.py&lt;/code&gt; file is parsed into a Python Abstract Syntax Tree using the standard &lt;code&gt;ast&lt;/code&gt; module.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Normalize
&lt;/h3&gt;

&lt;p&gt;Variable names, function names, attribute names, string literals, numbers, and docstrings are replaced with generic placeholders. This strips &lt;strong&gt;everything except structure&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# These two produce the SAME normalized AST:
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_total&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;
    &lt;span class="n"&gt;tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tax&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;
    &lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fee&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Shingle
&lt;/h3&gt;

&lt;p&gt;The normalized AST node sequence is broken into overlapping &lt;strong&gt;k-shingles&lt;/strong&gt; (default k=3):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(FunctionDef, arguments, arg) → (arguments, arg, Add) → ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Fingerprint + Match
&lt;/h3&gt;

&lt;p&gt;Each shingle set becomes a &lt;strong&gt;structural fingerprint&lt;/strong&gt;. &lt;strong&gt;MinHash signatures&lt;/strong&gt; compress these into compact 256-bit signatures. &lt;strong&gt;Locality Sensitive Hashing (LSH)&lt;/strong&gt; indexes them — only units sharing a bucket are compared.&lt;/p&gt;

&lt;p&gt;This reduces candidate pairs from &lt;strong&gt;O(n²) to nearly O(n)&lt;/strong&gt;. For 10,000 functions, that's 50 million comparisons avoided.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Cluster + Report
&lt;/h3&gt;

&lt;p&gt;Connected-component clustering groups related matches. Results render as text, JSON, CSV, or an &lt;strong&gt;interactive HTML report&lt;/strong&gt; with collapsible groups and syntax-highlighted code previews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pychase

&lt;span class="c"&gt;# Scan your project&lt;/span&gt;
pychase &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Generate HTML report&lt;/span&gt;
pychase &lt;span class="nt"&gt;--format&lt;/span&gt; html &lt;span class="nt"&gt;--output&lt;/span&gt; duplicates.html &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# JSON output for CI&lt;/span&gt;
pychase &lt;span class="nt"&gt;--json&lt;/span&gt; &lt;span class="nt"&gt;--threshold&lt;/span&gt; 0.85 ./src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why MinHash + LSH Matters
&lt;/h2&gt;

&lt;p&gt;Tools like dry4python compare every function against every other function — O(n²). With 10,000 functions, that's 50 million comparisons. PyChase's MinHash + LSH approach reduces this to near-linear time, making it viable for &lt;strong&gt;large monorepos and CI pipelines&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Clone Types&lt;/th&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PyChase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MinHash+LSH (O(n))&lt;/td&gt;
&lt;td&gt;Type-1,2,3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pip install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text, JSON, CSV, HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dry4python&lt;/td&gt;
&lt;td&gt;Brute-force (O(n²))&lt;/td&gt;
&lt;td&gt;Type-2 only&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pip install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text, JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jscpd&lt;/td&gt;
&lt;td&gt;Token hash&lt;/td&gt;
&lt;td&gt;Type-1,2&lt;/td&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;Text, JSON, HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SonarQube&lt;/td&gt;
&lt;td&gt;Custom AST&lt;/td&gt;
&lt;td&gt;Type-1,2&lt;/td&gt;
&lt;td&gt;DB + server + scanner&lt;/td&gt;
&lt;td&gt;Web dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pychase
pychase &lt;span class="nt"&gt;--threshold&lt;/span&gt; 0.55 &lt;span class="nt"&gt;--min-lines&lt;/span&gt; 2 &lt;span class="nt"&gt;--min-nodes&lt;/span&gt; 10 ./src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/Mayne-X/PyChase" rel="noopener noreferrer"&gt;https://github.com/Mayne-X/PyChase&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Docs&lt;/strong&gt;: &lt;a href="https://github.com/Mayne-X/PyChase/wiki" rel="noopener noreferrer"&gt;https://github.com/Mayne-X/PyChase/wiki&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;PyPI&lt;/strong&gt;: [&lt;a href="https://pypi.org/project/pychase/" rel="noopener noreferrer"&gt;https://pypi.org/project/pychase/&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>python</category>
      <category>refactoring</category>
      <category>opensource</category>
      <category>codequality</category>
    </item>
  </channel>
</rss>
