<?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: Jiangang Chen</title>
    <description>The latest articles on DEV Community by Jiangang Chen (@wulun811).</description>
    <link>https://dev.to/wulun811</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%2F4087094%2F533943c5-fbdf-4821-93f2-b751fa3897f3.jpg</url>
      <title>DEV Community: Jiangang Chen</title>
      <link>https://dev.to/wulun811</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wulun811"/>
    <language>en</language>
    <item>
      <title>How we cut repo-wide symbol indexing for LLM agents from 30s to 98ms</title>
      <dc:creator>Jiangang Chen</dc:creator>
      <pubDate>Thu, 20 Aug 2026 18:51:52 +0000</pubDate>
      <link>https://dev.to/wulun811/how-we-cut-repo-wide-symbol-indexing-for-llm-agents-from-30s-to-98ms-1mn2</link>
      <guid>https://dev.to/wulun811/how-we-cut-repo-wide-symbol-indexing-for-llm-agents-from-30s-to-98ms-1mn2</guid>
      <description>&lt;h2&gt;
  
  
  How we cut repo-wide symbol indexing for LLM agents from 30s to 98ms
&lt;/h2&gt;

&lt;p&gt;If your coding agent has ever stalled for tens of seconds on "what's in this repo?" — or burned hundreds of tokens re-reading a file after a failed edit — this is the story of why that happens and how we fixed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — we rebuilt code tooling for agents that have no hands, no eyes, and no memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;repo_map&lt;/code&gt; in &lt;strong&gt;98ms&lt;/strong&gt; (was tens of seconds): Rust tree-sitter parse daemon + SQLite index + incremental self-heal&lt;/li&gt;
&lt;li&gt;Every write is &lt;strong&gt;transactional&lt;/strong&gt;, with an undo journal that survives &lt;code&gt;kill -9&lt;/code&gt; — no more silently lost work&lt;/li&gt;
&lt;li&gt;Quality gates are &lt;strong&gt;deterministic&lt;/strong&gt; (zero LLM calls) and honestly scoped&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;44 tools&lt;/strong&gt; across read / analyze / edit / gate / verify / system — MIT, zero-build deploy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;LiuHe&lt;/strong&gt; (&lt;a href="https://github.com/wulun811/LiuHe" rel="noopener noreferrer"&gt;https://github.com/wulun811/LiuHe&lt;/a&gt;) is a code-operation toolchain designed for LLMs rather than humans: Node orchestration, a Rust tree-sitter parse daemon, a SQLite symbol index, and transactional journal-backed writes. MIT, v0.4.6, zero-build deploy (no cargo, no &lt;code&gt;npm install&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;This post is the architecture story: what was slow, what we changed, and the numbers we measured while doing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 44 tools, at a glance
&lt;/h2&gt;

&lt;p&gt;Six families, all deterministic, all reproducible from &lt;code&gt;benchmarks/&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read &amp;amp; index&lt;/strong&gt; — &lt;code&gt;read_symbol&lt;/code&gt; (version-anchored), &lt;code&gt;symbol_search&lt;/code&gt;, &lt;code&gt;code_search&lt;/code&gt;, &lt;code&gt;repo_map&lt;/code&gt; (98ms, paginated skeleton), &lt;code&gt;reindex&lt;/code&gt;, &lt;code&gt;dep_graph&lt;/code&gt;, &lt;code&gt;references&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze&lt;/strong&gt; — &lt;code&gt;impact_analysis&lt;/code&gt;, &lt;code&gt;call_chain&lt;/code&gt;, &lt;code&gt;trace_symbol&lt;/code&gt; (constant tracing), &lt;code&gt;inspect&lt;/code&gt;, &lt;code&gt;sweep_dead_code&lt;/code&gt;, &lt;code&gt;config_drift&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edit&lt;/strong&gt; — &lt;code&gt;edit_batch&lt;/code&gt; (4-level tolerant matching), &lt;code&gt;edit_transaction&lt;/code&gt; (atomic + undo journal), &lt;code&gt;rename_symbol&lt;/code&gt;, &lt;code&gt;git_worktree&lt;/code&gt;, &lt;code&gt;edit_sandbox&lt;/code&gt;, &lt;code&gt;edit_collision_guard&lt;/code&gt;, &lt;code&gt;diff_facts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gate&lt;/strong&gt; — &lt;code&gt;code_review&lt;/code&gt;, &lt;code&gt;security_review&lt;/code&gt;, &lt;code&gt;code_quality&lt;/code&gt;, &lt;code&gt;style_sniffer&lt;/code&gt;, &lt;code&gt;guard_patterns&lt;/code&gt;, &lt;code&gt;naming_consistency&lt;/code&gt;, &lt;code&gt;dependency_gatekeeper&lt;/code&gt;, &lt;code&gt;fix_imports&lt;/code&gt;, &lt;code&gt;mock_sync&lt;/code&gt; — zero LLM calls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt; — &lt;code&gt;test_bridge&lt;/code&gt;, &lt;code&gt;find_tests&lt;/code&gt;, &lt;code&gt;verify_pipeline&lt;/code&gt;, &lt;code&gt;debug_runner&lt;/code&gt;, &lt;code&gt;tsc_check&lt;/code&gt;, &lt;code&gt;patch_parser&lt;/code&gt;, &lt;code&gt;spec_gen&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System&lt;/strong&gt; — &lt;code&gt;health&lt;/code&gt; (self-healing), &lt;code&gt;gc&lt;/code&gt;, &lt;code&gt;feedback&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've watched an agent burn thousands of tokens re-reading a file because a &lt;code&gt;sed&lt;/code&gt; didn't match, or lose work to a silently botched write — these are the failure modes this toolkit exists for. Everything below is about making those tools fast, safe, and cheap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: every query re-parsed the world
&lt;/h2&gt;

&lt;p&gt;Our first version answered "what symbols exist in this repo?" by walking the tree and parsing every file on every request. On a 347-file project that was &lt;strong&gt;tens of seconds&lt;/strong&gt;. On a real Ansible repo of 1,482 files it was worse — and agents ask for repo maps &lt;em&gt;constantly&lt;/em&gt; (every tool-call needs file → symbol → reference context).&lt;/p&gt;

&lt;p&gt;The fix came in three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Rust parse daemon&lt;/strong&gt; — all CPU-bound AST work lives in Rust (tree-sitter + tokio + rayon), talking to Node over a Unix socket. Zero-copy source slicing, no per-node N-API boundary crossings, true parallelism.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A SQLite index&lt;/strong&gt; — parse results go straight into SQLite (WAL mode, per-workspace). Every subsequent query becomes a point lookup instead of a re-parse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental self-heal&lt;/strong&gt; — mtime + dirty flags re-extract only changed files; if the Rust binary's sha256 changes, the whole DB is marked dirty and rebuilt automatically. "Forgot to rebuild the index" is prevented by construction.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result: full index of 1,482 files in 9.7s (153 files/s); repo map afterwards: 98ms.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why parsing lives outside Node
&lt;/h2&gt;

&lt;p&gt;The original tree-sitter binding inside Node had two failure modes: a parse exception killed the entire MCP process (on average every 2–4 hours of use), and GC pauses + per-node JS↔C crossings made batch indexing stall.&lt;/p&gt;

&lt;p&gt;The Rust daemon fixes both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crash isolation via &lt;code&gt;catch_unwind&lt;/code&gt;&lt;/strong&gt; — a panic in the parser becomes a &lt;code&gt;PARSE_PANIC&lt;/code&gt; error code; the MCP server keeps running. Users forgive slow, never dead.&lt;/li&gt;
&lt;li&gt;No GC pauses in the parse path; rayon gives real parallelism without &lt;code&gt;worker_threads&lt;/code&gt; startup costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Writing code without hands
&lt;/h2&gt;

&lt;p&gt;Human tools assume you have hands, eyes, and memory. An LLM has none. Three compensations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No hands → atomic operations.&lt;/strong&gt; &lt;code&gt;edit_transaction&lt;/code&gt; is all-or-nothing; every write produces an undo journal. We tested &lt;code&gt;kill -9&lt;/code&gt; mid-write: the half-written transaction rolls back, source files untouched.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No eyes → structured output.&lt;/strong&gt; Every tool returns machine-consumable JSON, never prose the model has to parse. Errors carry &lt;code&gt;suggestion&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;next_action&lt;/code&gt; — an executable recovery call the model reissues verbatim instead of guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No memory → self-contained calls.&lt;/strong&gt; Every call carries &lt;code&gt;workspace_dir&lt;/code&gt;; writes are version-anchored (optimistic concurrency), so even if the model forgets the version it read, the write &lt;strong&gt;fails loudly&lt;/strong&gt; instead of silently corrupting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the "silent corruption" point: while building with a default agent tool stack, one overwrite write silently lost 400+ lines — surfaced ~40 turns later, by luck. We stopped betting on "models will get better" and moved the safety into the tool layer.&lt;/p&gt;

&lt;p&gt;Errors aren't a dead end — they're an interface. Every failure carries a stable code, a human-readable suggestion, and a &lt;code&gt;next_action&lt;/code&gt; that is executable, not advice:&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;"error"&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;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VERSION_CONFLICT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"base_version mismatch: FILE_CHANGED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Re-read the file and regenerate the batch."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"next_action"&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;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"read_symbol"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"params"&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;"locator"&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;"file_path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/api.js"&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;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;The model doesn't parse the suggestion and decide what to do — it reissues &lt;code&gt;next_action&lt;/code&gt; verbatim and recovers. Successful calls carry a &lt;code&gt;next_step&lt;/code&gt; the same way. Errors become signposts with navigation instead of dead ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;edit_batch&lt;/code&gt;: tolerant matching, paranoid writing
&lt;/h2&gt;

&lt;p&gt;LLMs generate &lt;code&gt;old_string&lt;/code&gt; anchors with mistakes humans rarely make: collapsed double spaces, truncated line ends, curly quotes where the code has straight ones. A bare &lt;code&gt;no_match&lt;/code&gt; sends the model off to re-read the whole file — thousands of tokens per failed match.&lt;/p&gt;

&lt;p&gt;Matching degrades in four stages: exact → trailing-whitespace-stripped → edit-distance candidates (similarity ≥ 0.5) → diagnostics (whitespace visualized, 17 Unicode confusable pairs listed). A typical failure reads: &lt;em&gt;"candidate at line 42, similarity 0.87 — you used curly quotes, the code has straight ones."&lt;/em&gt; Usually one retry fixes it.&lt;/p&gt;

&lt;p&gt;The write side is paranoid: symlink guards, unique temp file names, TOCTOU check between match and commit, rename retries for Windows AV file locks, post-write syntax check (&lt;code&gt;node --check&lt;/code&gt; / &lt;code&gt;py_compile&lt;/code&gt; / &lt;code&gt;JSON.parse&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Deterministic quality gates, honestly scoped
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;security_review&lt;/code&gt;, &lt;code&gt;code_review&lt;/code&gt;, &lt;code&gt;sweep_dead_code&lt;/code&gt; are pure regex/AST — &lt;strong&gt;zero LLM calls&lt;/strong&gt;. Same input, same output; CI-safe and auditable.&lt;/p&gt;

&lt;p&gt;We state the boundary explicitly: these tools do not cover control flow, data flow, or cross-module semantics. Zero findings ≠ safe; a high score ≠ healthy. A deterministic pattern scanner that admits its scope beats a "comprehensive security" claim every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tool audits itself
&lt;/h2&gt;

&lt;p&gt;30+ rounds of "LiuHe reviews LiuHe" — every bug found becomes a regression test. Real fixes from those rounds: a scope filter scanning outside its target directory, dead-code false positives on registration patterns, constant tracing missing read sites, SQL parameterization cleanup. Assertions grew every round: &lt;strong&gt;2,013 JS + 92 Rust&lt;/strong&gt;, full chain green.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the name: 六合 (six harmonies)
&lt;/h2&gt;

&lt;p&gt;LiuHe (六合, "six harmonies") names the six design constraints applied to every tool in the toolkit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contract&lt;/strong&gt; — parameters are self-describing; ambiguity returns candidates instead of guessing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guard&lt;/strong&gt; — dry-run, collision, and syntax checks run before anything executes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persist&lt;/strong&gt; — every operation is atomic, idempotent, and undoable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frugal&lt;/strong&gt; — incremental returns, batching, and trimming keep token spend down&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observable&lt;/strong&gt; — trace ids, pipeline steps, and a recovery path on every failure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace-back&lt;/strong&gt; — misuse data feeds back into thresholds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The three compensations earlier (hands / eyes / memory) are the user-facing summary; these six are the per-tool checklist behind them. The AST layer that enforces them is called Malong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measured numbers (not paper benchmarks)
&lt;/h2&gt;

&lt;p&gt;All under a real &lt;code&gt;docker --memory=512m&lt;/code&gt; cgroup:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;repo_map&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;98ms&lt;/strong&gt; (was tens of seconds)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full index&lt;/td&gt;
&lt;td&gt;1,482 files in 9.7s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;128 concurrent / 256 in-flight, &lt;strong&gt;zero OOM&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak RSS&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;134MB&lt;/strong&gt; (~26% of limit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;~588 calls/s (60–600× realistic agent demand)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hot-file storm&lt;/td&gt;
&lt;td&gt;32-way read/write mix, zero torn writes, &lt;code&gt;integrity_check&lt;/code&gt; PASS, 95/95 conflicts rejected as &lt;code&gt;FILE_LOCKED&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token savings&lt;/td&gt;
&lt;td&gt;↓65.3% (7,673 → 2,662 est. on same task)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Honest boundary:&lt;/strong&gt; throughput doesn't scale with concurrency — &lt;code&gt;better-sqlite3&lt;/code&gt;'s synchronous queries serialize on the Node event loop. We evaluated &lt;code&gt;worker_threads&lt;/code&gt; and decided the risk wasn't worth the gain. 588 calls/s is already overkill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where the token savings come from:&lt;/strong&gt; tiered tool-description compression (44 tools ≈ 1.33k tokens — core tools keep full descriptions, low-frequency ones shrink to ≤70 chars, verbose ones ≤230, with the detail deferred to &lt;code&gt;next_step&lt;/code&gt; hints), incremental returns with explicit pagination instead of dumping everything, and batch endpoints (&lt;code&gt;read_symbols&lt;/code&gt;, &lt;code&gt;write_symbols&lt;/code&gt;) that cut round-trips. Same task: 7,673 → 2,662 estimated tokens (↓65.3%) and 6 calls → 3 (↓50%).&lt;/p&gt;

&lt;p&gt;All benchmarks are reproducible from &lt;code&gt;benchmarks/&lt;/code&gt; and &lt;code&gt;tests/&lt;/code&gt; in the repo (concurrency correctness: &lt;code&gt;tests/test-mvp-concurrency.js&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Day-one DeepSeek Harness support
&lt;/h2&gt;

&lt;p&gt;We also shipped first-day support for DeepSeek Harness (dsh web) — one line to register, all 44 tools exposed as &lt;code&gt;malong__*&lt;/code&gt; with &lt;code&gt;workspace_dir&lt;/code&gt; auto-filled from the conversation's workspace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dsh plugin &lt;span class="nt"&gt;--profile&lt;/span&gt; web add @jieai/dsh-malong-bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full guide in the repo: &lt;code&gt;malong/dsh/DSH-INTEGRATION.md&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Zero-build deploy (no cargo, no &lt;code&gt;npm install&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/wulun811/LiuHe liuhe &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;liuhe/malong
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.local/bin
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; ../releases/malong-liuhe-0.4.6-linux-x86_64.tar.gz
&lt;span class="nb"&gt;cp &lt;/span&gt;malong-parse/target/release/malong-parse ~/.local/bin
malong-parse &amp;amp;   &lt;span class="c"&gt;# start the parse daemon&lt;/span&gt;
node &lt;span class="nt"&gt;--max-old-space-size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;512 &lt;span class="nt"&gt;--expose-gc&lt;/span&gt; mcp-server.js &lt;span class="nt"&gt;--workspace&lt;/span&gt; /path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;better-sqlite3&lt;/code&gt; is unavailable, it falls back to vendored &lt;code&gt;sql.js&lt;/code&gt; WASM — no install, no compile, no network.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/wulun811/LiuHe" rel="noopener noreferrer"&gt;https://github.com/wulun811/LiuHe&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs site: &lt;a href="https://wulun811.github.io/LiuHe" rel="noopener noreferrer"&gt;https://wulun811.github.io/LiuHe&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Changelog: &lt;a href="https://github.com/wulun811/LiuHe/blob/master/CHANGELOG.md" rel="noopener noreferrer"&gt;https://github.com/wulun811/LiuHe/blob/master/CHANGELOG.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skepticism welcome — all numbers above are self-measured and reproducible. If this resonates with an agent failure you've had, try it, break it, and tell us where we're wrong — the repo is &lt;a href="https://github.com/wulun811/LiuHe" rel="noopener noreferrer"&gt;wulun811/LiuHe&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>rust</category>
      <category>llm</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
