LiuHe

Community Developer tools

Code tools for LLMs to read, understand and modify code, using a tree-sitter parser, SQLite index and transactional writes.

Install

The installation steps are in the documentation below. Documentation

Documentation

From the project's README on GitHub, refreshed weekly. Links open on GitHub.

Contents
  1. Malong LiuHe(码龙·六合工具)
  2. Core Idea
  3. Performance (Measured)
  4. Language Support
  5. Tool Overview
  6. Architecture
  7. Self-Hosting (Dogfooding)
  8. Scan Boundaries (limits acknowledged; committed within)
  9. Quick Start
  10. Testing
  11. License
  12. Changelog

Malong LiuHe(码龙·六合工具)

LLM-Native Code Operations Toolkit — Code tooling reinvented for the LLM that has no hands, no eyes, and no memory.

English | 简体中文 | Docs | GitHub

-65%25-blue)

Malong LiuHe is a toolkit built for LLMs rather than humans. It ships two components:

  • malong/ — an MCP toolset whose default tier is the Six-He line (13 tools: code_task → code_read → code_patch / code_batch → code_check → code_control, with task state, evidence and structured next_action hand-back built in); the classic full catalog (44) and the diagnostic tier (18) are one env away — MALONG_INTERFACE=classic / MALONG_INTERFACE=diagnostic. The catalog spans symbol read/write, indexing, impact analysis, reference tracing, call graphs, dead-code detection, code review, security scanning, atomic batch editing, test orchestration, pipeline verification, plus capability discovery (code_query mode=capabilities/capability) and the ADR-018 full-call outlet (invoke_capability) — served to the LLM over MCP (JSON-RPC over stdio). Since 0.5.24 the Six-He line is the default; classic remains the full catalog.
  • malong-parse/ — a Rust parsing service: a tree-sitter-based multi-language symbol extraction engine (JavaScript/TypeScript/TSX/Python/Go/Rust/C/C++/Java/Bash), talking to the toolset over a Unix socket, with an LRU tree cache and batched parallel extraction.

Core Idea

Traditional tools (git, sed, IDE) assume a user with hands, eyes, and memory. An LLM has none of these. Malong LiuHe is redesigned around that fact:

MissingDesign Consequence
No handsOperations must be atomic, undoable, retryable (edit_transaction with rollback and undo journal)
No eyesOutput must be structured and self-explanatory (JSON for direct consumption; errors carry suggestion/next_action)
No memoryEvery call is self-contained (takes workspace_dir); optimistic concurrency with version anchors (read_symbol → write_symbol(base_version) conflict state machine)

Performance (Measured)

MetricValueNote
Small-file read P951ms50 runs, warmed
Small-file write P957ms30 runs, incl. post-write re-index
repo_map98msdown from tens of seconds (SQLite index + Rust parsing)
MemoryRSS 134MB / 26%under a real docker --memory=512m cgroup limit
Concurrency128 concurrent / 256 in-flight requests, zero OOM32-way mixed read+write on one hot file, no tearing, DB integrity_check PASS
Throughput~588 calls/ssingle-threaded ceiling — 60–600× real LLM demand
Token estimate (fixed-path)↓65.3%scripted measure-trail.js: 6-step legacy chain → 3-call primitives, 7673 → 2662 chars/4 est. Fixed editor path only — not a host-vs-malong nor an agentic-conversation result.
Call reduction (fixed-path)↓50.0%6 calls (legacy chain) → 3 calls (primitives); same scripted path
Tool-description compression44 classic tools ≈ 1.33k tokenstiered: core kept, low-freq ≤70 chars, verbose ≤230; detail flows via next_step hints
Default-tier catalog tax (per turn)13 tools = 16.5 KB ≈ 4.86k tokensdescriptions 2.0 KB (≈0.60k) + inputSchema 14.5 KB (≈4.26k) — the schema is 88% of it; to shrink the catalog, cut the parameter surface, not the prose
Index throughput538 files / 7sscoped reindex, measured
dry_run fidelity47/47golden-hash comparison across 3 languages, 100%
Concurrent writes to same symbol16/16exactly one winner + one conflict, zero silent overwrites

Language Support

LanguageSymbol ExtractionReference Extraction
JavaScript / TypeScript / TSX / JSX / MTS / CTS✓✓
Python✓✓
Go✓✓
Rust (impl blocks / trait / enum semantics)✓✓
C / C++ (incl. headers)✓✓
Java✓✓
Bash✓✓

Tool Overview

CategoryTools
Six-He line (graph + stateful — recommended daily entry)code_task (resolve + plan) → code_read (materials + read_ref) → code_patch / code_batch / code_maintain (journaled writes) → code_check (evidence) → code_control (status / resume / expand / reopen / job); plus code_status, code_query, code_audit, code_worktree, invoke_capability, edit_transaction — 13 tools, env-gated
I/O primitivesread_symbol (symbol read + version), write_symbol / write_symbols (safe write: conflict state machine + atomic write + undo)
Index & searchreindex, symbol_search, code_search (keyword + regex intent patterns — NOT semantic search), repo_map (98ms file map; skeleton pagination: page/page_size/prefix — truncated output always carries the full top-level skeleton with page numbers)
Analysisimpact_analysis (blast radius + risk), call_chain, references, dep_graph, inspect (outline + refs + call chain in one), trace_symbol (constant tracing + hardcoded copies)
Editingedit_batch, edit_transaction (atomic txn + rollback + cross-session lock + dry-run preview + create), edit_collision_guard (write conflict detection), sandbox_validate (pre-write validation), diff_facts (symbol changes + test sync), rename_symbol (atomic cross-file rename), git_worktree (isolated branch + verify + merge)
Quality gatescode_review, security_review (regex security patterns), code_quality (5-dim probe), style_sniffer, guard_patterns, naming_consistency, exception_guard, config_drift, dependency_gatekeeper, fix_imports, sweep_dead_code, mock_sync — all pure regex/AST, zero LLM calls, deterministic
Engineeringtest_bridge (run/suggest/discover), find_tests, verify_pipeline (lint/test/typecheck stages), debug_runner (error analysis), patch_parser (SEARCH/REPLACE), tsc_check, spec_gen, active_todos
Systemhealth, gc, feedback

Long test suites must run in the background. The MCP request has a hard 120s ceiling and a foreground stage is capped at 110s, so a suite that takes minutes is reported as failed — that is a request-budget truncation, not a code defect. Run it as a background job instead: code_check with run: true, async: true (600s cap), then poll with code_control(action="job").

Architecture

┌─────────────────────────┐     ┌──────────────────────────────┐
│  LLM Client (MCP)       │     │  malong-parse (Rust daemon)  │
│  malong/ 13 six-he      │◄───►│  tree-sitter, 10 languages   │
│  (+44/18 gated)         │     │  LRU tree cache 50MB / batch │
│  Unix socket client     │     │  catch_unwind crash recovery │
└─────────────────────────┘     └──────────────────────────────┘
  • All parsing is done by the Rust service (zero tree-sitter bindings on the Node side)
  • Index is SQLite (WAL mode, multi-process safe), isolated per workspace
  • LRU tree cache (50MB / 5min TTL), batched extraction 50 files/batch
  • Daemon multi-session safety: circuit breaker + liveness probe + cross-session coordinated restart (O_EXCL lock) — a slow request in one session never stalls others

Self-Hosting (Dogfooding)

30+ rounds of "Malong reviews Malong": the toolset audits and fixes its own code, with dozens of real bugs fixed and locked by tests — including directory-scope filtering gaps, false dead-code reports for registration patterns, lost constant read-sites, and SQL parameterization cleanup. Every round grew the suite (now 166 JS test files, full chain 0 failures). Latest round (r5): cross-file reference resolution is now import-aware — member calls such as path.join no longer bind to same-named local symbols (216 false bindings in this repo alone), cross-language (Python↔JS) links are blocked by a language-family filter, and aliases resolve through the import graph (ESM specifier scanning added on the JS side) — locked by test-crossfile-resolve (14 assertions, red→green); the DSH bridge also now pins MALONG_STATE_DIR when spawning the server, locked by test-dsh-bridge.

Scan Boundaries (limits acknowledged; committed within)

Deterministic scanners only — regex pattern matching and reference graphs. No control-flow, data-flow, or cross-module semantic coverage. 0 findings ≠ clean; high scores ≠ healthy.

  • security_review scans: injection (eval/Function-ctor, exec/spawn string building, template ${}, $() substitution, SQL concat), XSS, hardcoded secrets, CORS *, timing/insecure compare, dotenv. Not scanned: SSRF, XXE, deserialization, auth/logic flaws, control-flow defects.
  • sweep_dead_code reference scope: import graph + fixed text-ref fallback (.sh/.json/.md etc.); CLI-string references count as alive (miss-over-delete). Not scanned: dynamic/reflection wiring.
  • Commitment: issues in scope get fixed; covered patterns are test-locked; new rules must stay within committed categories.

Quick Start

npm ci installs better-sqlite3 (the full SQLite backend); this is the default recommended path:

# 1) Get the parsing daemon — download a prebuilt binary from releases/, or build:
cd malong-parse && cargo build --release && cp target/release/malong-parse ~/.local/bin
malong-parse &                                   # start the daemon (Unix socket)

# 2) Install the toolset (npm ci installs the full better-sqlite3 backend)
cd ../malong && npm ci

# 3) Register the MCP server (works with any MCP client, e.g. opencode / Claude Desktop)
#    opencode (project-root opencode.json; Windows paths use double backslashes, Linux/macOS forward slashes):
#    {
#      "mcp": {                                    # opencode V2 native: servers grouping (V1 used direct mcp.<name>)
#        "servers": {
#          "malong": {
#            "type": "local",
#            "command": ["node", "--max-old-space-size=512", "N:\\repo\\liuhe\\malong\\mcp-server.js", "--workspace", "N:\\repo\\liuhe"],
#            # default since 0.5.24 = Six-He line (13 tools); this block is optional now — delete it for the classic 44 catalog
#            "environment": { "MALONG_INTERFACE": "graph", "MALONG_ENTRY_STATE": "1" }
#          }
#        }
#      }
#    }
#    Claude Desktop (verified on Windows: %APPDATA%\Claude\claude_desktop_config.json):
#    {
#      "mcpServers": {
#        "malong": { "command": "node", "args": ["/path/to/malong/mcp-server.js"], "env": { "MALONG_INTERFACE": "graph", "MALONG_ENTRY_STATE": "1" } }
#      }
#    }

# 4) Ask your LLM: "search for the symbol 'handle' in my workspace"

#    DeepSeek Harness (dsh web) — auto session-workspace convenience (extra, optional):
#    Run once on the dsh host (Linux/macOS):
#      Option A (npm, one line — full backend + platform binary included):
#        dsh plugin --profile web add @jieai/dsh-malong-bridge
#        pkill -f "dsh web"; dsh web --port 3456 --host 0.0.0.0 --trusted-host <LAN IP>
#      Option B (script, points at a checkout of this repo):
#        bash malong/dsh/install-dsh.sh         # idempotent; edits ~/.dsh/profiles/web/cordis.patch.yml with backup
#    The bridge exposes the Six-He line (13 tools: code_task/code_read/code_patch/...) as malong__* and auto-fills workspace_dir from the
#    current conversation's workspace (no per-call path needed; explicit paths still win).
#    Need the classic full catalog (44) or the diagnostic tier (18)? export MALONG_INTERFACE=classic|diagnostic on the dsh host.
#    Full guide incl. index rules: malong/dsh/DSH-INTEGRATION.md
#    Troubleshooting: if EVERY malong__* call hangs until timeout, the bridge's
#    mcp-server subprocess is gone. The bridge now auto-restarts it (exponential
#    backoff, pending calls fail fast with "restarting — retry shortly"); if that
#    keeps failing, restart dsh web: kill <dsh web pid> && dsh web --port 3456 ...

SQL backend note: the default is the full better-sqlite3 backend. If npm install fails (offline / no build toolchain / Node < 20), the server automatically degrades to the vendored sql.js WASM sandbox backend (malong/vendor/, zero-dependency, no network) — the startup log shows which backend is active and the upgrade command. Data files are fully compatible between backends (both are SQLite).

Zero-build deployment (degraded path: sandbox / offline environments)

For environments with Node >= 20 and no npm access (no npm ci, no native compilation), everything runs from the repo files as-is (Linux/Windows — the prebuilt binaries are linux-x86_64 and windows-x86_64). On this path SQLite runs on the sql.js sandbox backend (degraded):

# 0) Clone, then enter the toolset directory:
git clone <repo-url> liuhe && cd liuhe/malong

# 1) Parse daemon — prebuilt binary from releases/ (no cargo needed):
mkdir -p ~/.local/bin
tar -xzf ../releases/malong-liuhe-0.5.27-linux-x86_64.tar.gz
cp malong-parse/target/release/malong-parse ~/.local/bin
malong-parse &                                   # start the daemon (socket: /tmp/malong-parse-$UID.sock)

# 2) Run the toolset — zero npm install:
node --max-old-space-size=4096 mcp-server.js --workspace /path/to/project
# vendored SQLite (sql.js WASM) auto-enabled when better-sqlite3 is unavailable

# 3) Self-check (30s, optional):
node tests/test-db-adapter.js   # 22 assertions: sql.js backend + persistence
node tests/test-mcp-server.js   # 37 assertions: MCP stdio + daemon round-trip

Windows users: use malong-liuhe-0.5.27-windows-x86_64.tar.gz from GitHub Releases (contains malong-parse.exe), extract and put it on PATH; the MCP server auto-starts the daemon, so step 1's malong-parse & is not required. The mkdir -p/tar -xzf above are Unix syntax — on Windows use any extractor (tar -xzf works on Win10+).

Note: if the daemon is not running, parse-dependent tools (symbol extraction etc.) degrade; the SQLite-backed tools (repo-map / code-index / health-check) still work.

  • See THIRD_PARTY_NOTICES.md for the vendored component.

What the LLM sees back:

{
  "results": [
    { "name": "handle", "type": "function", "start_line": 6, "end_line": 12, "file": "app.js" },
    { "name": "handle_login", "type": "function", "start_line": 5, "end_line": 9, "file": "src/auth.py" }
  ],
  "count": 2,
  "next_step": "Before modifying found symbols, check blast radius: impact_analysis(...)"
}
Build the Rust parsing service
cd malong-parse
cargo build --release
cp target/release/malong-parse ~/.local/bin/   # or add to PATH
malong-parse &                                   # daemon (Unix socket: /tmp/malong-parse-$(id -u).sock)

Prebuilt binaries for Linux x86_64 are committed under releases/ (with .sha256 checksums) — pick one up instead of building if you prefer.

Platforms: Linux and macOS use the Unix socket; on Windows the daemon listens on TCP 127.0.0.1:31001 (set MALONG_PORT to override) — the MCP server probes and auto-starts malong-parse.exe on startup, so no manual launch is needed (if you use the parse-client API directly outside MCP, start it manually). Set MALONG_SOCKET to override the Unix socket path.

Install the toolset
cd malong
npm ci
npm test          # 166 test files (daemon must be running)
Start the MCP server
cd malong
node --max-old-space-size=512 mcp-server.js --workspace /path/to/project

Register the MCP server with any MCP-capable LLM client and the tools become available. For opencode, register in the project root opencode.json (the environment block is optional since 0.5.24 — the default tier already is the Six-He line, 13 tools; set MALONG_INTERFACE=classic for the classic 44-tool catalog):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "malong": {
        "type": "local",
        "command": ["node", "--max-old-space-size=512", "malong/mcp-server.js", "--workspace", "."],
        "environment": { "MALONG_INTERFACE": "graph", "MALONG_ENTRY_STATE": "1" }
      }
    }
  }
}

Windows note: relative paths in --workspace and malong/mcp-server.js resolve against the directory where opencode is launched; pass absolute paths (escape backslashes as \\ in JSON) if you start it elsewhere. The daemon is auto-started by the MCP server — no need to launch malong-parse.exe manually.

For opencode V2 details — config shape, tool visibility (codemode), and troubleshooting — see malong/opencode/OPENCODE-V2.md.

Configuration (environment variables)

All optional — sensible defaults apply when unset.

VariableDefaultPurpose
MALONG_STATE_DIR~/.config/malongRoot of MCP state since 0.5.0: workspace indexes (workspaces/<hash>/code-index.db) plus usage / feedback / edit-stats. Legacy per-repo data/malong-mcp (seeded via --workspace) is migrated on first launch in an isolated child process (copy→verify→delete; fail-soft, source kept on failure); pre-0.3.37 ~/.config/opencode/ reads still fall back.
MALONG_SKIP_STATE_MIGRATIONunsetSet to 1 to skip legacy-state migration at startup (emergency escape; old directory left untouched).
MALONG_SOCKET/tmp/malong-parse-$(id -u).sockUnix socket path to the parse daemon (Linux / macOS).
MALONG_PORT31001TCP port for the parse daemon (Windows).
MALONG_PARSE_BINnpm platform pkg / ~/.local/binBinary used when the client auto-starts the daemon. Resolution order: this env → @jieai/malong-parse-<os>-<arch> npm platform package (installed as an optional dependency of @jieai/dsh-malong-bridge) → ~/.local/bin/malong-parse → malong-parse/target/release (dev tree).
MALONG_PARSE_MODErust-serviceParse transport. Only rust-service is supported (builtin / shadow are rejected).
MALONG_WS_GC_DAYS14Days a workspace index cache may sit untouched before health cleanup prunes it; 0 disables.
MALONG_INTERFACEgraphTool tier. Default (unset) = the Six-He line (13 tools: code_task/code_read/code_status/code_query + 8 stateful entries + edit_transaction). classic = the full 44-tool catalog; diagnostic = 18 (Six-He line + 5 analyzers).
MALONG_ENTRY_STATEonThe state layer (S1–S5 task state machine + ADR-018 invoke_capability) is allowed by default; set 0 for the read-only 5-tool tier.
MALONG_PYTHONunsetExplicit interpreter for Python test runs (test_bridge / verify_pipeline); overrides the auto-detected project venv (.venv/venv/env next to the project root).
Suppressing security false positives

security_review is deliberately conservative, so benign patterns (a hash used as a cache key, process.exit in a CLI entry) can trip it. Two explicit, auditable suppression mechanisms exist — neither ever auto-suppresses injection rules.

Inline — append malong-ignore to a line to suppress all findings on it, or malong-ignore[eval,exec-cmd] for specific rules (a reason after : is encouraged):

const id = crypto.createHash('md5').update(p).digest('hex') // malong-ignore: cache-dir name, not security

Config — add a securityIgnore array to .ai-patterns.json (the same file guard_patterns reads). Each entry takes files (* / ** globs) and/or rules; omit one side to match all:

{ "securityIgnore": [ { "files": ["**/mcp-server.js"], "rules": ["process-exit"] } ] }

Suppressed findings are dropped from the score but counted in the summary's suppressed field, so nothing is hidden silently. Injection rules (eval / exec / SQL / spawn) are only ever suppressed by an explicit marker or entry you authored — never heuristically.

Journal auto-cleanup

Every safe write (write_symbol / write_symbols / edit_batch) leaves an undo journal under .malong/journal/. Terminal transactions (committed / rolled_back / abandoned / failed) older than a TTL (default 24h, configurable) are pruned automatically — throttled to at most one scan per hour per workspace, so it costs nothing. In-flight (created / staged) and needs_review (external change awaiting human review) journals are never auto-deleted. This only ever touches the tool's own rollback backups — never your source files.

Using with Claude Code

Verified end-to-end with Claude Code 2.x. The MCP layer is standard JSON-RPC over stdio, so any MCP client (Claude Code, codex, opencode, Claude Desktop…) connects the same way.

1) Prerequisites — Node >= 20 and the parsing daemon running (see the Zero-build deployment or Build the Rust parsing service sections above).

2) Install Claude Code

npm install -g @anthropic-ai/claude-code

3) Point Claude Code at an Anthropic-compatible provider

Claude Code needs an LLM backend. Any Anthropic-compatible endpoint works — set the variables below (or manage them with cc-switch):

export ANTHROPIC_BASE_URL="https://your-provider/anthropic"   # any Anthropic-compatible endpoint
export ANTHROPIC_AUTH_TOKEN="your-api-key"                     # never commit this
export ANTHROPIC_MODEL="your-model"                            # a model your provider serves

With cc-switch: npm i -g @cc-switch/cli, cc-switch new my-provider (fill in the same ANTHROPIC_* keys under env), cc-switch switch my-provider, then eval $(cc-switch export).

4) Register the MCP server

claude mcp add liuhe -- node /path/to/malong/mcp-server.js --workspace /path/to/project
claude mcp list        # → "liuhe … ✔ Connected"

5) Use it — start claude in your project and ask, or run headless:

claude -p "index the workspace with reindex, then find createDb with symbol_search" \
  --allowedTools "mcp__liuhe__reindex" "mcp__liuhe__symbol_search"

Tools are exposed as mcp__liuhe__<tool> (e.g. mcp__liuhe__health, mcp__liuhe__symbol_search, mcp__liuhe__repo_map). Run reindex (optionally blocking=true) once per workspace first, so symbol search / impact analysis have an index to query.

Using with codex

Verified end-to-end with codex (same JSON-RPC-over-stdio MCP layer).

Version note: recent codex releases force the OpenAI Responses API (wire_api = "responses"). Use a version that still supports wire_api = "chat" together with MCP — verified with 0.50.0: npm install -g @openai/codex@0.50.0.

1) Prerequisites — Node >= 20 and the parsing daemon running (see above).

2) Configure ~/.codex/config.toml — point codex at any OpenAI-compatible provider (example below: OpenCode Zen) and register the MCP server:

model = "deepseek-v4-flash"
model_provider = "opencode-zen"

[model_providers.opencode-zen]
name = "OpenCode Zen"
base_url = "https://opencode.ai/zen/go/v1"   # any OpenAI-compatible endpoint
wire_api = "chat"
env_key = "OPENCODE_ZEN_API_KEY"             # codex reads the API key from this env var

[mcp_servers.liuhe]
command = "node"
args = ["/path/to/malong/mcp-server.js", "--workspace", "/path/to/project"]

3) Run — export the API key, then start codex:

export OPENCODE_ZEN_API_KEY="your-api-key"   # never commit this
codex exec "index the workspace with reindex, then find createDb with symbol_search"

Tools are exposed by the malong-mcp server; the prefix follows the name you register it under — opencode malong_<tool> (e.g. malong_health, malong_symbol_search), Claude Code mcp__liuhe__<tool>, the DSH bridge malong__<tool>. Run reindex once per workspace first so symbol search has an index to query.

Testing

  • Rust: cargo test (97 assertions: per-language extraction + protocol framing/decoding + cache LFU + server dispatch/priority queue + batch_extract + deep-nesting guards + hello handshake)
  • JS: 166 test files (authoritative list: scripts.test in package.json; includes primitives / tool-registry / manifest-quality / write-runtime / edit-transaction-ext / verify-pipeline, the dogfood r12–r30 end-to-end series, plus G0/G1 capability-contract / capability-catalog / invoke-capability / invoke-stdio suites)
  • Total: 166 JS test files, full chain 0 failures (plus cargo test: 97 assertions)
  • One-shot: ./scripts/ci.sh (self-contained: cargo test + npm test + dogfood; reuses or auto-starts the daemon)

License

MIT

Changelog

See CHANGELOG.md for the full release history.

Frequently asked questions

What is LiuHe?

Code tools for LLMs to read, understand and modify code, using a tree-sitter parser, SQLite index and transactional writes.

How do I install LiuHe?

Follow the installation steps in its documentation, shown on this page and in its repository.

Is LiuHe open source?

Yes. Its code is on GitHub under the MIT license.

Who maintains LiuHe?

It is published by wulun811. AI.tn lists it but does not maintain or endorse it.

From the community awesome-mcp-servers lists and the project's GitHub repository. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.