<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title></title>
    <description>graphscope blog</description>
    <link>https://graphscope.io/blog/</link>
    <atom:link href="https://graphscope.io/blog/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 02 Apr 2026 13:35:17 +0000</pubDate>
    <lastBuildDate>Thu, 02 Apr 2026 13:35:17 +0000</lastBuildDate>
    <generator>Jekyll v4.4.1</generator>
    
      <item>
        <title>Dissecting Claude Code: A Graph-Powered Deep Dive into an AI Coding Agent&apos;s Architecture</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;We indexed &lt;strong&gt;1,906 source files&lt;/strong&gt;, &lt;strong&gt;9,848 functions&lt;/strong&gt;, and &lt;strong&gt;22,678 call edges&lt;/strong&gt; using &lt;a href=&quot;https://github.com/alibaba/neug/tree/main/skills/codegraph&quot;&gt;CodeGraph&lt;/a&gt; — a code intelligence skill powered by &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG&lt;/a&gt;, an open-source embedded graph database — to reveal what lies beneath the surface of one of the most ambitious AI coding tools ever built.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-numbers-at-a-glance&quot;&gt;The Numbers at a Glance&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Metric&lt;/th&gt;
      &lt;th&gt;Count&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Source Files&lt;/td&gt;
      &lt;td&gt;1,906&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Functions&lt;/td&gt;
      &lt;td&gt;9,848&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Call Edges&lt;/td&gt;
      &lt;td&gt;22,678&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Import Edges&lt;/td&gt;
      &lt;td&gt;15,743&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Modules&lt;/td&gt;
      &lt;td&gt;306&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Classes&lt;/td&gt;
      &lt;td&gt;128&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Claude Code is a &lt;strong&gt;TypeScript monolith&lt;/strong&gt; running on &lt;strong&gt;Bun + Ink&lt;/strong&gt; (React for terminals). &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.tsx&lt;/code&gt; alone exceeds 4,700 lines, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REPL.tsx&lt;/code&gt; tops 5,000 lines with 288 outgoing function calls — the highest fan-out of any component in the system.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;1-architecture-five-layers-one-gravity-well&quot;&gt;1. Architecture: Five Layers, One Gravity Well&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-04-02-claude-code/01-architecture.png&quot; alt=&quot;Architecture Overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;CodeGraph’s layer discovery reveals an &lt;strong&gt;onion-ring architecture&lt;/strong&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/utils&lt;/code&gt; as the gravitational center. The five layers, from top to bottom:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entry Points&lt;/strong&gt; — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REPL.tsx&lt;/code&gt; (288 calls, 236 imports), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.tsx&lt;/code&gt; (275 calls, 163 imports), and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;print.ts&lt;/code&gt; (164 calls, CLI pipeline). These are the three doors into Claude Code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI Layer&lt;/strong&gt; — 131 files including the 113-file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;components/&lt;/code&gt; directory, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PromptInput&lt;/code&gt; (105 outgoing calls), the Buddy virtual pet system, and Ink’s custom terminal renderer (52 methods).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logic Layer&lt;/strong&gt; — 120 hooks, 80+ slash commands, 42 tools (from the 151-function BashTool to the 1-function SleepTool), and 14 keybinding files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service Layer&lt;/strong&gt; — Analytics (428 callers), MCP protocol (41 files), Permissions (41 files), Bridge remote control (33 files), the Swarm multi-agent system, and 7 task types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Foundation&lt;/strong&gt; — The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;utils/&lt;/code&gt; directory with 299 files absorbing &lt;strong&gt;5,951 incoming calls&lt;/strong&gt; — 6x more than the next highest module. It’s not a utility folder; it’s the bedrock of reality for this codebase.&lt;/p&gt;

&lt;h3 id=&quot;the-repl-a-component-that-imports-the-universe&quot;&gt;The REPL: A Component That Imports the Universe&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REPL.tsx&lt;/code&gt; imports from &lt;strong&gt;236 files&lt;/strong&gt; — more than any other file in the codebase. It connects to hooks, components, services, bridge, swarm, voice, cost-tracking, MCP, and keybindings. Yet it has &lt;strong&gt;0 callers&lt;/strong&gt; (fan-in = 0). It’s the root UI leaf that nobody calls into; it only calls out.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2-bridge-functions-the-nervous-system&quot;&gt;2. Bridge Functions: The Nervous System&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-04-02-claude-code/02-bridge-functions.png&quot; alt=&quot;Bridge Functions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;bridge function&lt;/strong&gt; is one called from the most distinct modules — the glue holding disparate subsystems together. CodeGraph identified these top bridges:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Function&lt;/th&gt;
      &lt;th&gt;File&lt;/th&gt;
      &lt;th&gt;Modules Spanned&lt;/th&gt;
      &lt;th&gt;Total Callers&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logForDebugging&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;debug.ts&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;90&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;911&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;analytics/index.ts&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;94&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;428&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logError&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;log.ts&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;77&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;413&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;fileStateCache.ts&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;64&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;290&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jsonStringify&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;slowOperations.ts&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;63&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;248&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isEnvTruthy&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;envUtils.ts&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;47&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;194&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getGlobalConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;config.ts&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;44&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;163&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getCwd&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;cwd.ts&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;43&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;135&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logForDebugging&lt;/code&gt; is called from &lt;strong&gt;90 out of 306 modules&lt;/strong&gt; — nearly 1 in 3 modules feeds debug info through this single function. It’s the all-seeing eye of Claude Code.&lt;/p&gt;

&lt;p&gt;Notice the file name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slowOperations.ts&lt;/code&gt; housing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jsonStringify&lt;/code&gt; (248 callers, 63 modules). The team explicitly wraps JSON operations in a module named “slow” — a candid acknowledgment that serialization is a performance bottleneck they want to track.&lt;/p&gt;

&lt;p&gt;The top 3 bridge functions alone account for &lt;strong&gt;1,752 call edges&lt;/strong&gt; across &lt;strong&gt;261 module-boundaries&lt;/strong&gt;. Removing any one would fracture the entire system.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;3-the-permission-gateway-a-single-chokepoint&quot;&gt;3. The Permission Gateway: A Single Chokepoint&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-04-02-claude-code/03-permission-gateway.png&quot; alt=&quot;Permission Gateway&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One of the most architecturally significant findings: &lt;strong&gt;every tool execution flows through a single function&lt;/strong&gt; — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkPermissionsAndCallTool&lt;/code&gt;. It has only &lt;strong&gt;1 caller&lt;/strong&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;streamedCheckPermissionsAndCallTool&lt;/code&gt;) but calls &lt;strong&gt;30 different functions&lt;/strong&gt; spanning telemetry, permission rules, classifier checks, error handling, and analytics.&lt;/p&gt;

&lt;p&gt;This is a textbook &lt;strong&gt;Policy Enforcement Point (PEP)&lt;/strong&gt; — a single chokepoint where all 42 tools must pass through for authorization. The downstream functions include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;checkRuleBasedPermissions&lt;/strong&gt; — evaluates the rule engine&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;startSpeculativeClassifierCheck&lt;/strong&gt; — the “YOLO mode” classifier&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;resolveHookPermissionDecision&lt;/strong&gt; — hook-based overrides&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;logEvent + logOTelEvent&lt;/strong&gt; — dual telemetry (analytics + OpenTelemetry)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;startToolSpan / endToolSpan&lt;/strong&gt; — tracing boundaries&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;formatZodValidationError&lt;/strong&gt; — schema validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture makes it trivially easy to add security policies, audit logging, and rate limiting without modifying any individual tool.&lt;/p&gt;

&lt;h3 id=&quot;the-1511-complexity-ratio&quot;&gt;The 151:1 Complexity Ratio&lt;/h3&gt;

&lt;p&gt;Not all tools are created equal. BashTool has &lt;strong&gt;151 functions&lt;/strong&gt; (command parsing, sandboxing, permission verification, timeout management, output capture, cross-platform compatibility). SleepTool has &lt;strong&gt;1 function&lt;/strong&gt;. That’s a 151:1 complexity range across a unified interface.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Tool&lt;/th&gt;
      &lt;th&gt;Functions&lt;/th&gt;
      &lt;th&gt;Category&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;BashTool&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;151&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Shell execution&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;PowerShellTool&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;101&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Windows shell&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;AgentTool&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;91&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Multi-agent orchestration&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;LSPTool&lt;/td&gt;
      &lt;td&gt;35&lt;/td&gt;
      &lt;td&gt;Language server&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;FileEditTool&lt;/td&gt;
      &lt;td&gt;31&lt;/td&gt;
      &lt;td&gt;File operations&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;GrepTool&lt;/td&gt;
      &lt;td&gt;8&lt;/td&gt;
      &lt;td&gt;Search&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;SleepTool&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;Wait&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;4-the-buddy-system-a-gacha-game-inside-a-dev-tool&quot;&gt;4. The Buddy System: A Gacha Game Inside a Dev Tool&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-04-02-claude-code/04-buddy-system.png&quot; alt=&quot;Buddy System&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Perhaps the most delightful discovery: Claude Code contains a complete &lt;strong&gt;virtual pet system&lt;/strong&gt; with gacha mechanics, ASCII art animations, and RPG stats.&lt;/p&gt;

&lt;h3 id=&quot;how-companion-generation-works&quot;&gt;How Companion Generation Works&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Hash the User ID&lt;/strong&gt; with a salt (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;friend-2026-401&lt;/code&gt;) using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hashString()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Seed a Mulberry32 PRNG&lt;/strong&gt; with the hash value&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Roll deterministically&lt;/strong&gt; for species, rarity, eyes, hat, and stats&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cache the result&lt;/strong&gt; (the buddy renders every 500ms, can’t re-roll each frame)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The “bones” (species, rarity, stats) are &lt;strong&gt;regenerated from hash on every read&lt;/strong&gt; and never persisted to disk. Only the “soul” (user-chosen name and personality) is saved. This means:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Anti-cheat&lt;/strong&gt;: Users can’t edit their config to fake a Legendary rarity&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Schema-safe&lt;/strong&gt;: Changes to the species array won’t break saved companions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Deterministic&lt;/strong&gt;: Same user = same companion forever&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-hex-obfuscation-trick&quot;&gt;The Hex Obfuscation Trick&lt;/h3&gt;

&lt;p&gt;All 18 species names are encoded as hex character codes to dodge a build-time string filter:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;duck&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fromCharCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x75&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x63&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x6b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// &quot;duck&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;One species name collides with an internal model codename listed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;excluded-strings.txt&lt;/code&gt;, so the team encoded ALL species uniformly.&lt;/p&gt;

&lt;h3 id=&quot;gacha-rarity-distribution&quot;&gt;Gacha Rarity Distribution&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Rarity&lt;/th&gt;
      &lt;th&gt;Probability&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Common&lt;/td&gt;
      &lt;td&gt;60%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Uncommon&lt;/td&gt;
      &lt;td&gt;25%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Rare&lt;/td&gt;
      &lt;td&gt;10%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Epic&lt;/td&gt;
      &lt;td&gt;4%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Legendary&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1%&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Each companion has &lt;strong&gt;5 RPG stats&lt;/strong&gt;: DEBUGGING, PATIENCE, CHAOS, WISDOM, SNARK. The ASCII sprites are 5 lines tall, 12 columns wide, with 2-3 frames for idle animation. Frame &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-1&lt;/code&gt; in the 15-frame idle sequence triggers a rare blink animation.&lt;/p&gt;

&lt;p&gt;Here’s an actual duck sprite from the codebase:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    __
  &amp;lt;(· )___
   (  ._&amp;gt;
    `--´
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;CodeGraph’s impact analysis traces the call chain: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getCompanion()&lt;/code&gt; → &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompanionSprite&lt;/code&gt; → &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PromptInput&lt;/code&gt; (105 calls) → &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REPL&lt;/code&gt; (288 calls) → Terminal UI.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;5-dream-task-the-ai-that-dreams-while-you-code&quot;&gt;5. Dream Task: The AI That Dreams While You Code&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-04-02-claude-code/05-dream-task.png&quot; alt=&quot;Dream Task&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Claude Code has a &lt;strong&gt;background memory consolidation system&lt;/strong&gt; that literally runs while you work — the AI “dreams” about past sessions to improve its memory.&lt;/p&gt;

&lt;h3 id=&quot;the-four-gates-cheapest-first&quot;&gt;The Four Gates (Cheapest First)&lt;/h3&gt;

&lt;p&gt;Before dreaming begins, four gates must pass — ordered by computational cost:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Time Gate&lt;/strong&gt; (cost: 1 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stat()&lt;/code&gt; call) — Has 24 hours elapsed since the last dream?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scan Throttle&lt;/strong&gt; (cost: memory timestamp check) — Has 10 minutes passed since the last scan?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Session Gate&lt;/strong&gt; (cost: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readdir&lt;/code&gt;) — Are there 5+ new sessions to consolidate?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Lock Gate&lt;/strong&gt; (cost: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flock&lt;/code&gt;) — Is the file-based mutex free?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This ordering ensures &lt;strong&gt;cheap rejections happen first&lt;/strong&gt;. Most API turns exit at gate 1 with a single stat call.&lt;/p&gt;

&lt;h3 id=&quot;the-four-phases-of-dreaming&quot;&gt;The Four Phases of Dreaming&lt;/h3&gt;

&lt;p&gt;Once the gates pass, a restricted subagent forks with &lt;strong&gt;read-only Bash permissions&lt;/strong&gt; (only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;head&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail&lt;/code&gt;):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Orient&lt;/strong&gt; — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt; the memory directory to understand current state&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Gather&lt;/strong&gt; — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; recent session transcripts for patterns and reusable knowledge&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Consolidate&lt;/strong&gt; — Write/update memory files with distilled knowledge&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Prune&lt;/strong&gt; — Keep the memory index under 25KB, entries under 150 characters&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;the-filesystem-retry-trick&quot;&gt;The Filesystem Retry Trick&lt;/h3&gt;

&lt;p&gt;When a dream is killed mid-flight, it calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rollbackConsolidationLock(priorMtime)&lt;/code&gt; to &lt;strong&gt;rewind the lock file’s modification time&lt;/strong&gt;. This makes the Time Gate pass again on the next API turn — a retry mechanism built into the filesystem itself.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;6-swarm-multi-agent-orchestration&quot;&gt;6. Swarm: Multi-Agent Orchestration&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-04-02-claude-code/06-swarm-system.png&quot; alt=&quot;Swarm System&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The most architecturally ambitious module: a &lt;strong&gt;three-tier backend abstraction&lt;/strong&gt; for spawning and managing teams of AI agents.&lt;/p&gt;

&lt;h3 id=&quot;backend-detection-priority-chain&quot;&gt;Backend Detection Priority Chain&lt;/h3&gt;

&lt;p&gt;When a teammate is spawned, the system probes the environment:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Priority&lt;/th&gt;
      &lt;th&gt;Backend&lt;/th&gt;
      &lt;th&gt;Lines&lt;/th&gt;
      &lt;th&gt;Detection Method&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;P1&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;TmuxBackend&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;765&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ORIGINAL_USER_TMUX&lt;/code&gt; env var&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;P2&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;ITermBackend&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;370&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TERM_PROGRAM&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;it2 session list&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;P3&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;InProcessBackend&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;340&lt;/td&gt;
      &lt;td&gt;Always available (fallback)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The &lt;strong&gt;PaneBackendExecutor&lt;/strong&gt; adapter wraps tmux/iTerm2 into the same &lt;strong&gt;TeammateExecutor&lt;/strong&gt; interface that InProcessBackend implements directly. This lets the system degrade gracefully: tmux → iTerm2 → in-process.&lt;/p&gt;

&lt;h3 id=&quot;why-asynclocalstorage&quot;&gt;Why AsyncLocalStorage?&lt;/h3&gt;

&lt;p&gt;When agents are backgrounded (Ctrl+B), multiple agents run &lt;strong&gt;concurrently in the same Node.js process&lt;/strong&gt;. AppState is a single shared mutable object. If Agent A’s telemetry reads it, it might get Agent B’s context.&lt;/p&gt;

&lt;p&gt;AsyncLocalStorage isolates each async execution chain, giving each agent its own identity bubble — without requiring process isolation.&lt;/p&gt;

&lt;h3 id=&quot;task-id-design&quot;&gt;Task ID Design&lt;/h3&gt;

&lt;p&gt;Each task gets a unique ID: a &lt;strong&gt;single-letter prefix&lt;/strong&gt; + 8 random base-36 characters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; = bash, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; = agent, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt; = remote, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt; = teammate, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;w&lt;/code&gt; = workflow, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m&lt;/code&gt; = monitor, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d&lt;/code&gt; = dream&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives instant type identification from the ID string alone, with 36^8 ≈ 2.8 trillion combinations.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;7-cost-tracker-follow-the-money&quot;&gt;7. Cost Tracker: Follow the Money&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-04-02-claude-code/07-cost-tracker.png&quot; alt=&quot;Cost Tracker&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The cost tracking system handles &lt;strong&gt;7 pricing tiers&lt;/strong&gt; with dynamic tier selection for Opus 4.6:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Model&lt;/th&gt;
      &lt;th&gt;Input/1M&lt;/th&gt;
      &lt;th&gt;Output/1M&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Haiku 3.5&lt;/td&gt;
      &lt;td&gt;$0.80&lt;/td&gt;
      &lt;td&gt;$4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Sonnet&lt;/td&gt;
      &lt;td&gt;$3&lt;/td&gt;
      &lt;td&gt;$15&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Opus 4.5&lt;/td&gt;
      &lt;td&gt;$5&lt;/td&gt;
      &lt;td&gt;$25&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Opus 4/4.1&lt;/td&gt;
      &lt;td&gt;$15&lt;/td&gt;
      &lt;td&gt;$75&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Opus 4.6 (fast)&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;$30&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;$150&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getOpus46CostTier(fastMode)&lt;/code&gt; dynamically selects the tier based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;response_speed&lt;/code&gt; — fast mode costs 2x.&lt;/p&gt;

&lt;h3 id=&quot;the-billing-access-gate&quot;&gt;The Billing Access Gate&lt;/h3&gt;

&lt;p&gt;The display logic reveals thoughtful product thinking:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Subscribers (Max/Pro)&lt;/strong&gt;: Costs are &lt;strong&gt;hidden&lt;/strong&gt; (flat rate — showing costs would be confusing)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;API-key users with admin/billing roles&lt;/strong&gt;: Costs are &lt;strong&gt;displayed&lt;/strong&gt; (they’re paying per-token)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is controlled by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasConsoleBillingAccess()&lt;/code&gt;, which checks &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DISABLE_COST_WARNINGS&lt;/code&gt; env, subscriber status, auth tokens, and org/workspace roles.&lt;/p&gt;

&lt;h3 id=&quot;what-gets-tracked&quot;&gt;What Gets Tracked&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;totalCostUSD&lt;/code&gt; — cumulative dollar amount&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;totalAPIDuration&lt;/code&gt; — time spent waiting for API responses&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;totalToolDuration&lt;/code&gt; — time spent executing tools&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linesAdded / linesRemoved&lt;/code&gt; — code change volume&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modelUsage&lt;/code&gt; — per-model token breakdown&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fpsMetrics&lt;/code&gt; — terminal rendering performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this persists to project config and survives session restarts via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;restoreCostStateForSession()&lt;/code&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;8-the-loneliest-1265&quot;&gt;8. The Loneliest 1,265&lt;/h2&gt;

&lt;p&gt;CodeGraph found &lt;strong&gt;1,265 isolated functions&lt;/strong&gt; — functions with zero callers AND zero callees. Out of 9,848 total, that’s &lt;strong&gt;12.8%&lt;/strong&gt; sitting in complete isolation.&lt;/p&gt;

&lt;p&gt;Where do they live?&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;File&lt;/th&gt;
      &lt;th&gt;Total Functions&lt;/th&gt;
      &lt;th&gt;Why Isolated&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap/state.ts&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;212&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Getters/setters called dynamically&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sessionStorage.ts&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;153&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Dynamic property access&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yoga-layout/index.ts&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;134&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;FFI binding layer&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap/state.ts&lt;/code&gt; alone has 212 functions — the densest file in the codebase. It’s a global state machine that vends getters and setters for everything from session IDs to model strings. Static analysis can’t see dynamic property access, so they appear “isolated” even though they’re heavily used at runtime.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;9-the-class-hierarchy-oop-at-the-boundaries&quot;&gt;9. The Class Hierarchy: OOP at the Boundaries&lt;/h2&gt;

&lt;p&gt;With 128 classes in a primarily functional codebase, where does OOP live?&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Class&lt;/th&gt;
      &lt;th&gt;Methods&lt;/th&gt;
      &lt;th&gt;Purpose&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Node&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;91&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Yoga layout FFI binding&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cursor&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;59&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Terminal cursor management&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ink&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;52&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Custom React terminal renderer&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YogaLayoutNode&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Flexbox layout engine&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebSocketTransport&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;WebSocket client&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TmuxBackend&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Tmux pane management&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CCRClient&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;24&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;API transport layer&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The top 4 classes are all &lt;strong&gt;rendering infrastructure&lt;/strong&gt;. The business logic (tools, permissions, cost tracking, buddy) is overwhelmingly functional — closures, hooks, and module-level state. Classes appear only at the boundaries: transport protocols, terminal abstractions, and system backends.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;10-patterns-worth-stealing&quot;&gt;10. Patterns Worth Stealing&lt;/h2&gt;

&lt;h3 id=&quot;deterministic-generation-without-persistence&quot;&gt;Deterministic Generation Without Persistence&lt;/h3&gt;

&lt;p&gt;The buddy system regenerates &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bones&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash(userId)&lt;/code&gt; every time. Only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;soul&lt;/code&gt; persists. This eliminates schema migration headaches AND prevents config-file cheating.&lt;/p&gt;

&lt;h3 id=&quot;gate-ordering-by-cost&quot;&gt;Gate Ordering by Cost&lt;/h3&gt;

&lt;p&gt;The dream task checks: in-memory flag → stat a file → list a directory → acquire a lock. Each gate is more expensive than the last, so cheap rejections happen first.&lt;/p&gt;

&lt;h3 id=&quot;single-letter-task-id-prefixes&quot;&gt;Single-Letter Task ID Prefixes&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt;ash, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt;gent, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt;emote, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt;eammate, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;w&lt;/code&gt;orkflow, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m&lt;/code&gt;onitor, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d&lt;/code&gt;ream — instant type identification from the ID string alone.&lt;/p&gt;

&lt;h3 id=&quot;honest-function-names&quot;&gt;Honest Function Names&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getFeatureValue_CACHED_MAY_BE_STALE&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slowOperations.ts&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;writeFileSyncAndFlush_DEPRECATED&lt;/code&gt; — names that force callers to understand the tradeoffs.&lt;/p&gt;

&lt;h3 id=&quot;asynclocalstorage-for-concurrent-identity&quot;&gt;AsyncLocalStorage for Concurrent Identity&lt;/h3&gt;

&lt;p&gt;When multiple agents share a process, don’t use global state for identity. Use AsyncLocalStorage to give each async execution chain its own context.&lt;/p&gt;

&lt;h3 id=&quot;single-permission-gateway&quot;&gt;Single Permission Gateway&lt;/h3&gt;

&lt;p&gt;Route all 42 tools through one function. Adding a new security policy means changing one file, not 42.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Claude Code is not just an AI coding assistant — it’s a &lt;strong&gt;miniature operating system&lt;/strong&gt; for AI agents. Through CodeGraph’s structural analysis, we’ve uncovered:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;utils&lt;/code&gt; foundation with &lt;strong&gt;5,951 incoming calls&lt;/strong&gt; acting as bedrock&lt;/li&gt;
  &lt;li&gt;A permission system where &lt;strong&gt;all 42 tools pass through a single gateway&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;A virtual pet with &lt;strong&gt;gacha mechanics and anti-cheat architecture&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;An AI that &lt;strong&gt;dreams about its memories&lt;/strong&gt; during idle hours&lt;/li&gt;
  &lt;li&gt;A &lt;strong&gt;three-tier multi-agent orchestration system&lt;/strong&gt; spanning tmux, iTerm2, and in-process&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;1,265 isolated functions&lt;/strong&gt; (12.8%) sitting in silence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The graph never lies. Behind every great product is an architecture that tells its own story — you just need the right tools to read it.&lt;/p&gt;
</description>
        <pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2026/04/02/Dissecting-Claude-Code.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2026/04/02/Dissecting-Claude-Code.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>Following 94 Million Relationships Down the Rabbit Hole</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-24-explorative-bi-title.png&quot; alt=&quot;explorative-bi-title&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We ran an experiment: take a real question, point it at a massive academic knowledge graph, and keep asking follow-ups to see how deep LLM-driven analysis can actually go.&lt;/p&gt;

&lt;p&gt;The question: &lt;strong&gt;“What impact has the Russia-Ukraine conflict had on Russian academia?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The data comes from &lt;a href=&quot;https://www.openaire.eu/&quot;&gt;OpenAIRE&lt;/a&gt;, one of Europe’s largest open research data platforms: 22 million entities, 94 million relationships, spanning publications, authors, institutions, funding sources, and journals. Too large to feed into any LLM directly — but perfect for structured analysis.&lt;/p&gt;

&lt;p&gt;Here’s how the investigation unfolded.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;question-1-did-publication-output-actually-decline&quot;&gt;Question 1: Did publication output actually decline?&lt;/h2&gt;

&lt;p&gt;The obvious starting point. We matched &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Publication ↔ Organization&lt;/code&gt; patterns across the graph and aggregated by country and year to track Russia’s publication trend.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Year&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Publications&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;YoY Change&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Cumulative&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2020&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;9,544&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2021&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;8,976&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;-6.0%&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;-6.0%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2022&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;8,548&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;-4.8%&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;-10.4%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2023&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;7,732&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;-9.5%&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;-19.0%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2024&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;4,686&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;-39.4%&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;-50.9%&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;A mild decline before the war, accelerating sharply after 2022, nearly halved by 2024.&lt;/p&gt;

&lt;p&gt;But is this Russia-specific, or a global trend? We sliced the same analytical structure differently — global publication volume actually &lt;em&gt;increased&lt;/em&gt; in 2022. Comparing 2021→2024: Russia dropped 47.8%, far exceeding the US and Germany at 27.6%, while China grew 14.8%.&lt;/p&gt;

&lt;p&gt;This isn’t a global downturn. It’s a cliff — and it’s Russia’s alone.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-24-explorative-bi-1.png&quot; alt=&quot;Russian Scholar Publication Trend&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;question-2-did-the-funding-dry-up&quot;&gt;Question 2: Did the funding dry up?&lt;/h2&gt;

&lt;p&gt;When publication output drops, the first instinct is to follow the money.&lt;/p&gt;

&lt;p&gt;We extended our analysis by adding a Funding dimension on top of the existing structure — not starting over, but incrementally expanding what we’d already built.&lt;/p&gt;

&lt;p&gt;The result: the European Commission (EC) had been a major funder of Russian research. After 2022, EC completely cut off funding for projects involving Russian institutions — while continuing to fund 26 Ukrainian institutions. This aligns perfectly with the EC’s official policy announcements.&lt;/p&gt;

&lt;p&gt;The money did dry up. But does that explain everything?&lt;/p&gt;

&lt;h2 id=&quot;question-3-are-journals-shutting-the-door-too&quot;&gt;Question 3: Are journals shutting the door too?&lt;/h2&gt;

&lt;p&gt;We pivoted to a different angle, adding a Publisher dimension to the structure from Question 1: which journals changed their stance toward Russian papers around 2022?&lt;/p&gt;

&lt;p&gt;Finding: EDP Sciences dramatically reduced publications from Russian institutions after 2022. Further investigation revealed that EDP Sciences had publicly declared support for Ukraine. And crucially, their publication volume from other countries didn’t see a comparable drop — this wasn’t a general contraction, it was selective.&lt;/p&gt;

&lt;p&gt;Funding was being cut. Publishing channels were narrowing.&lt;/p&gt;

&lt;h2 id=&quot;question-4-what-happened-to-the-collaboration-network&quot;&gt;Question 4: What happened to the collaboration network?&lt;/h2&gt;

&lt;p&gt;The previous questions looked at individual factors. We zoomed out to the big picture — querying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Author(country=RU) → Publication → Organization&lt;/code&gt; to map how Russia’s collaboration with each country changed over time.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Partner Country&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;2021&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;2024&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Change&lt;/th&gt;
      &lt;th&gt;Country Type&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Turkey&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;988&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;16&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;-98.4%&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Non-Western, no sanctions&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Germany&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;656&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;46&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;-93.0%&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Western, sanctions&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;USA&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3,614&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;271&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;-92.5%&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Western, sanctions&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;China&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;570&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;112&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;-80.4%&lt;/td&gt;
      &lt;td&gt;Non-Western, no sanctions&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Wait — the steepest drop is Turkey?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;-98.4%. A non-Western country. A country that imposed no sanctions on Russia. And yet the collaboration decline is &lt;em&gt;worse&lt;/em&gt; than with the US or Germany.&lt;/p&gt;

&lt;p&gt;This breaks a seemingly natural assumption: that the decline is primarily sanctions-driven. If sanctions were the main cause, Western countries should show the steepest drops. But the data tells a different story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanctions are part of the picture, but the deeper shift is systemic: the entire international academic network is distancing itself from Russia.&lt;/strong&gt; It’s not that certain countries stopped cooperating — Russia is being structurally marginalized from the global research fabric.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-24-explorative-bi-2.png&quot; alt=&quot;Key Finding: Turkey Non-Western Dropped More&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-could-we-keep-asking&quot;&gt;Why could we keep asking?&lt;/h2&gt;

&lt;p&gt;Looking back at these four steps, each finding naturally raised the next question. This “follow the thread” experience feels intuitive — analysis &lt;em&gt;should&lt;/em&gt; work this way.&lt;/p&gt;

&lt;p&gt;But if you’ve used traditional data analysis tools, you know reality is different. The typical workflow looks like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ask question → get result → want to follow up → realize the data model doesn’t have that dimension → ask a data engineer to redesign the schema → rebuild the wide table → rerun the query → finally see the result → want to follow up again → redesign again → …&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Every follow-up costs as much as the first question.&lt;/strong&gt; Three questions means three full analysis cycles from scratch. So most analyses stop at the surface — not because people don’t want to go deeper, but because going deeper is prohibitively expensive.&lt;/p&gt;

&lt;p&gt;Text-to-SQL and NL2BI tools solve the problem of “how to ask the first question more easily” — having an LLM translate natural language into queries. That’s genuinely useful, but it doesn’t solve the follow-up problem. The SQL gets generated, but the underlying data model is still rigid, intermediate results are still discarded, and every new question still requires full recomputation.&lt;/p&gt;

&lt;p&gt;What we set out to solve is exactly this: &lt;strong&gt;make follow-up questions dramatically cheaper than the first one.&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Step&lt;/th&gt;
      &lt;th&gt;Question&lt;/th&gt;
      &lt;th&gt;Operation&lt;/th&gt;
      &lt;th&gt;What was reused&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1&lt;/td&gt;
      &lt;td&gt;Did output decline?&lt;/td&gt;
      &lt;td&gt;Match Pub↔Org on graph, aggregate by year+country&lt;/td&gt;
      &lt;td&gt;—&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2&lt;/td&gt;
      &lt;td&gt;Did funding dry up?&lt;/td&gt;
      &lt;td&gt;Add Funding dimension&lt;/td&gt;
      &lt;td&gt;Pub-Org structure from Step 1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3&lt;/td&gt;
      &lt;td&gt;Are journals biased?&lt;/td&gt;
      &lt;td&gt;Add Publisher dimension&lt;/td&gt;
      &lt;td&gt;Pub-Org structure from Step 1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;4&lt;/td&gt;
      &lt;td&gt;How much did collaborations drop?&lt;/td&gt;
      &lt;td&gt;Match Author→Pub→Org, aggregate by country&lt;/td&gt;
      &lt;td&gt;Underlying data structures&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The analytical structure built in Step 1 was reused across all subsequent steps. Each follow-up wasn’t “start over” — it was “take one more step from where we left off.”&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;how-it-works-under-the-hood&quot;&gt;How it works under the hood&lt;/h2&gt;

&lt;p&gt;Keeping the follow-up chain going requires three things simultaneously: the analytical structure must be dynamically extensible, intermediate results must persist, and computation over massive data must be fast enough for interactive use. We tackle each with a specific design.&lt;/p&gt;

&lt;h3 id=&quot;hypergraph-data-model-a-schema-that-grows-with-your-questions&quot;&gt;Hypergraph Data Model: a schema that grows with your questions&lt;/h3&gt;

&lt;p&gt;Traditional analytical data models (star/snowflake schemas) are designed upfront. You must decide on all dimensions before asking any questions — miss one, and you start over.&lt;/p&gt;

&lt;p&gt;We designed a Hypergraph-based data model with a composable operator algebra:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Source&lt;/strong&gt;: perform pattern matching on the raw data graph to produce a hypergraph — the starting point&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Join&lt;/strong&gt;: add new dimensions to an existing hypergraph — the ability to extend on follow-up&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;View&lt;/strong&gt;: materialize intermediate results — the system’s “memory” of what’s been computed&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;DrillDown / RollUp / Slice / Dice&lt;/strong&gt;: multidimensional slicing and aggregation on hypergraphs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These operators form a closed algebra: freely composable and chainable. This is what powers the “add a dimension and keep going” experience in the case study above — the schema isn’t predefined, it grows as your curiosity leads.&lt;/p&gt;

&lt;h3 id=&quot;unbiased-sampling-sub-second-responses-over-94-million-relationships&quot;&gt;Unbiased Sampling: sub-second responses over 94 million relationships&lt;/h3&gt;

&lt;p&gt;Whether you can sustain a chain of follow-ups depends heavily on how long each step takes. If every question takes five minutes to run, you’ll lose patience by Step 3.&lt;/p&gt;

&lt;p&gt;But the core operation behind these analyses is subgraph matching — exhaustively computing this over a large-scale graph is prohibitively expensive. Our approach: unbiased sampling. Instead of enumerating all matches, we uniformly sample a subset and use statistical methods to estimate aggregates. “Unbiased” means the estimates don’t systematically skew high or low.&lt;/p&gt;

&lt;p&gt;For analytical tasks, this trade-off is remarkably effective: what matters is “did something change, which direction, who changed most” — not whether every number is exact to the last unit. In practice, COUNT estimates have an average error rate of just &lt;strong&gt;0.27%&lt;/strong&gt; — trend-level conclusions stay perfectly intact while computation cost drops by one to two orders of magnitude.&lt;/p&gt;

&lt;h3 id=&quot;neug-co-located-storage-and-computation&quot;&gt;NeuG: co-located storage and computation&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG&lt;/a&gt; is our graph storage engine. The key design decision: sampling-based subgraph matching algorithms are implemented directly in the storage layer, so computation executes where the data lives — no need to shuttle data to a separate system.&lt;/p&gt;

&lt;p&gt;Many systems don’t bottleneck on the operators themselves, but on data movement. NeuG’s principle: &lt;strong&gt;the best optimization is not moving data at all.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the formal definitions of the hypergraph data model, operator design, and theoretical guarantees of the sampling algorithms, see our paper: &lt;a href=&quot;https://arxiv.org/abs/2603.10625&quot;&gt;A Hypergraph-Based Framework for Exploratory Business Intelligence&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;benchmarks&quot;&gt;Benchmarks&lt;/h2&gt;

&lt;p&gt;Beyond the real-world case study above, we ran systematic evaluations on LDBC Social Network Benchmark datasets (SF1, SF3, SF10) across 13 analytical queries of varying complexity.&lt;/p&gt;

&lt;p&gt;On the largest scale, SF10 (~10GB), &lt;strong&gt;ExBI was the only system to complete all 13 queries&lt;/strong&gt;. Neo4j completed 7; MySQL completed 2.&lt;/p&gt;

&lt;p&gt;Performance:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;vs. Neo4j: &lt;strong&gt;16.21x&lt;/strong&gt; average speedup, up to 146.25x&lt;/li&gt;
  &lt;li&gt;vs. MySQL: &lt;strong&gt;46.67x&lt;/strong&gt; average speedup, up to 230.53x&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speed doesn’t come at the cost of accuracy — COUNT average error rate is 0.27%, MAX error is near zero.&lt;/p&gt;

&lt;p&gt;For the full experimental design and analysis, see the &lt;a href=&quot;https://arxiv.org/abs/2603.10625&quot;&gt;paper&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try it yourself&lt;/h2&gt;

&lt;p&gt;We integrated this analytical capability into &lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;OpenClaw&lt;/a&gt; by adding NeuG-related data loading and analysis &lt;a href=&quot;https://github.com/Louyk14/neug/tree/main/skills&quot;&gt;skills&lt;/a&gt;. The case study above was conducted entirely in this environment.&lt;/p&gt;

&lt;table&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;img src=&quot;/blog/assets/images/2026-03-24-explorative-bi-3.jpg&quot; alt=&quot;OpenAIRE Schema&quot; /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;img src=&quot;/blog/assets/images/2026-03-24-explorative-bi-4.jpg&quot; alt=&quot;Analysis Report&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;NeuG: https://github.com/alibaba/neug&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;NeuG data loading and analysis skills: https://github.com/Louyk14/neug/tree/main/skills&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Docker (code + OpenAIRE dataset, ready to use): https://hub.docker.com/r/shunyangli/neugbi&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Paper: &lt;a href=&quot;https://arxiv.org/abs/2603.10625&quot;&gt;A Hypergraph-Based Framework for Exploratory Business Intelligence&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Full analysis report: &lt;a href=&quot;http://neug.oss-cn-beijing.aliyuncs.com/neugbi/ru_ua_conflict_research_report_en.pdf&quot;&gt;Impact of the Russia-Ukraine War on Russian Academia&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 24 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2026/03/24/Following-94-Million-Relationships.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2026/03/24/Following-94-Million-Relationships.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>We X-Rayed OpenClaw with a Graph Database — Here&apos;s the Technical Debt We Found</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-19-openclaw-technical-debt-title.png&quot; alt=&quot;openclaw-technical-debt-title&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;When a codebase grows to 21,000 functions connected by 35,000 call edges, code review alone isn’t enough. We ran OpenClaw through NeuG’s graph database and surfaced structural problems that traditional tools can’t see.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-a-graph-perspective&quot;&gt;Why a Graph Perspective?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;OpenClaw&lt;/a&gt; is a popular AI gateway project — 18,000+ commits, 6,000+ TypeScript files, and 21,000+ functions, with new versions shipping almost daily. In our previous post, we looked at OpenClaw from the user’s perspective and found that the heartbeat mechanism was consuming far more tokens than anyone expected.&lt;/p&gt;

&lt;p&gt;This time, we go deeper. From a developer’s perspective: &lt;strong&gt;what structural debt has fast iteration quietly accumulated?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional code review and static analysis tools catch a lot, but they struggle to answer structural questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Which functions are “time bombs” — where a bug would cause maximum blast radius?&lt;/li&gt;
  &lt;li&gt;Which code is dead weight, confusing new contributors who think it’s still active?&lt;/li&gt;
  &lt;li&gt;Which module is the system’s structural hub — touch it, and half the codebase shakes?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The answers to these questions live in &lt;strong&gt;relationships&lt;/strong&gt;, not in lines of code.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-approach-turn-the-codebase-into-a-graph&quot;&gt;The Approach: Turn the Codebase into a Graph&lt;/h2&gt;

&lt;p&gt;We built a code knowledge graph using &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG&lt;/a&gt; (graph database) and &lt;a href=&quot;https://github.com/alibaba/zvec&quot;&gt;zvec&lt;/a&gt; (vector database):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Nodes&lt;/strong&gt;: functions, classes, modules, files&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Edges&lt;/strong&gt;: call relationships, import dependencies, commit history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s what the graph looks like at scale:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Type&lt;/th&gt;
      &lt;th&gt;Count&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Source files&lt;/td&gt;
      &lt;td&gt;6,062&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Functions&lt;/td&gt;
      &lt;td&gt;21,057&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Call edges&lt;/td&gt;
      &lt;td&gt;35,761&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Import edges&lt;/td&gt;
      &lt;td&gt;25,883&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Classes&lt;/td&gt;
      &lt;td&gt;233&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Modules&lt;/td&gt;
      &lt;td&gt;318&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;21,000 functions connected by 35,000 call edges. Once the graph is built, hard structural questions become Cypher queries.&lt;/p&gt;

&lt;p&gt;The full analysis pipeline is packaged as &lt;a href=&quot;https://github.com/alibaba/neug/tree/main/skills/codegraph&quot;&gt;CodeGraph Skill&lt;/a&gt; — open source and fully reproducible.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;finding-1-high-risk-functions&quot;&gt;Finding 1: High-Risk Functions&lt;/h2&gt;

&lt;h3 id=&quot;defining-risk-score&quot;&gt;Defining Risk Score&lt;/h3&gt;

&lt;p&gt;We define a &lt;strong&gt;risk score&lt;/strong&gt; for each function to quantify its potential blast radius:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Risk Score = fan_in × fan_out
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;fan-in&lt;/strong&gt;: how many functions call it (dependency pressure)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;fan-out&lt;/strong&gt;: how many functions it calls (dependency complexity)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The product represents the blast radius — how much of the system breaks if this function has a bug.&lt;/p&gt;

&lt;p&gt;Detecting fan-out is straightforward; most IDE tools can do it. But fan-in requires a full-codebase scan — exactly where a graph database shines. This is one of the built-in capabilities of our &lt;a href=&quot;https://github.com/alibaba/neug/tree/main/skills/codegraph&quot;&gt;CodeGraph Skill&lt;/a&gt;: it ships with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hotspots()&lt;/code&gt; method that handles the full-graph traversal for you, so finding the highest-risk functions across the entire codebase is a single call:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;functions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hotspots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;topk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Top 5 by risk score:&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Function&lt;/th&gt;
      &lt;th&gt;File&lt;/th&gt;
      &lt;th&gt;fan-in&lt;/th&gt;
      &lt;th&gt;fan-out&lt;/th&gt;
      &lt;th&gt;Risk Score&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;startGatewayServer&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;src/gateway/server.impl.ts&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;103&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1030&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;createConfigIO&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;src/config/io.ts&lt;/td&gt;
      &lt;td&gt;18&lt;/td&gt;
      &lt;td&gt;56&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1008&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;runEmbeddedPiAgent&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;src/agents/pi-embedded-runner/run.ts&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
      &lt;td&gt;67&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;938&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;loadOpenClawPlugins&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;src/plugins/loader.ts&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
      &lt;td&gt;36&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;720&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;runCronIsolatedAgentTurn&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;src/cron/isolated-agent/run.ts&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;60&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;660&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;These functions sit at the core of critical execution paths. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startGatewayServer&lt;/code&gt; bootstraps the entire service; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createConfigIO&lt;/code&gt; generates all configuration; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runEmbeddedPiAgent&lt;/code&gt; orchestrates embedded Pi Agent execution.&lt;/p&gt;

&lt;p&gt;Here’s an interesting observation about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createConfigIO&lt;/code&gt;: configuration parsing rarely gets prioritized for test coverage — it “seems safe.” But with 18 callers and 56 outgoing calls, &lt;strong&gt;by structural risk metrics it’s one of the most dangerous functions in the entire codebase&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;filtering-for-the-real-high-risk-core&quot;&gt;Filtering for the Real High-Risk Core&lt;/h3&gt;

&lt;p&gt;We wrote a custom Cypher query to filter out low-level utility functions (high fan-in, low fan-out) and focus on functions that are simultaneously heavily depended upon &lt;em&gt;and&lt;/em&gt; highly complex:&lt;/p&gt;

&lt;div class=&quot;language-cypher highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;f:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:CALLS&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;g:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WITH&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;DISTINCT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fan_out&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:CALLS&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;h:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WITH&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fan_out&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;DISTINCT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fan_in&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fan_in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fan_out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f.name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fan_in&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fan_out&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The result was surprising: &lt;strong&gt;only 17 functions&lt;/strong&gt; in the entire codebase meet both criteria. Every one of them is a critical, high-risk node:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Function&lt;/th&gt;
      &lt;th&gt;File&lt;/th&gt;
      &lt;th&gt;fan-in&lt;/th&gt;
      &lt;th&gt;fan-out&lt;/th&gt;
      &lt;th&gt;Risk Score&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;startGatewayServer&lt;/td&gt;
      &lt;td&gt;src/gateway/server.impl.ts&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;103&lt;/td&gt;
      &lt;td&gt;1030&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;createConfigIO&lt;/td&gt;
      &lt;td&gt;src/config/io.ts&lt;/td&gt;
      &lt;td&gt;18&lt;/td&gt;
      &lt;td&gt;56&lt;/td&gt;
      &lt;td&gt;1008&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;runEmbeddedPiAgent&lt;/td&gt;
      &lt;td&gt;src/agents/pi-embedded-runner/run.ts&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
      &lt;td&gt;67&lt;/td&gt;
      &lt;td&gt;938&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;loadOpenClawPlugins&lt;/td&gt;
      &lt;td&gt;src/plugins/loader.ts&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
      &lt;td&gt;36&lt;/td&gt;
      &lt;td&gt;720&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;runCronIsolatedAgentTurn&lt;/td&gt;
      &lt;td&gt;src/cron/isolated-agent/run.ts&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;60&lt;/td&gt;
      &lt;td&gt;660&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;getReplyFromConfig&lt;/td&gt;
      &lt;td&gt;src/auto-reply/reply/get-reply.ts&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
      &lt;td&gt;24&lt;/td&gt;
      &lt;td&gt;480&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;runMessageAction&lt;/td&gt;
      &lt;td&gt;src/infra/outbound/message-action-runner.ts&lt;/td&gt;
      &lt;td&gt;21&lt;/td&gt;
      &lt;td&gt;22&lt;/td&gt;
      &lt;td&gt;462&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;loadPluginManifestRegistry&lt;/td&gt;
      &lt;td&gt;src/plugins/manifest-registry.ts&lt;/td&gt;
      &lt;td&gt;22&lt;/td&gt;
      &lt;td&gt;16&lt;/td&gt;
      &lt;td&gt;352&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;createOpenClawTools&lt;/td&gt;
      &lt;td&gt;src/agents/openclaw-tools.ts&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;24&lt;/td&gt;
      &lt;td&gt;240&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fetchWithSsrFGuard&lt;/td&gt;
      &lt;td&gt;src/infra/net/fetch-guard.ts&lt;/td&gt;
      &lt;td&gt;24&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;240&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;resolveCommandSecretRefsViaGateway&lt;/td&gt;
      &lt;td&gt;src/cli/command-secret-gateway.ts&lt;/td&gt;
      &lt;td&gt;15&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
      &lt;td&gt;210&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fetchRemoteMedia&lt;/td&gt;
      &lt;td&gt;src/media/fetch.ts&lt;/td&gt;
      &lt;td&gt;18&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;198&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;loadModelCatalog&lt;/td&gt;
      &lt;td&gt;src/agents/model-catalog.ts&lt;/td&gt;
      &lt;td&gt;18&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;198&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;resolveApiKeyForProvider&lt;/td&gt;
      &lt;td&gt;src/agents/model-auth.ts&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;15&lt;/td&gt;
      &lt;td&gt;195&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;start&lt;/td&gt;
      &lt;td&gt;src/gateway/client.ts&lt;/td&gt;
      &lt;td&gt;12&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;156&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;resolveAuthProfileOrder&lt;/td&gt;
      &lt;td&gt;src/agents/auth-profiles/order.ts&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;121&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;createClackPrompter&lt;/td&gt;
      &lt;td&gt;src/wizard/clack-prompter.ts&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;110&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;These 17 functions are the structural pressure points of the system. Any change to them deserves extra scrutiny.&lt;/p&gt;

&lt;h3 id=&quot;finding-zombie-functions&quot;&gt;Finding Zombie Functions&lt;/h3&gt;

&lt;p&gt;We plotted the fan-in distribution across all functions as a histogram. NeuG’s Python SDK makes this straightforward — query results flow directly into pandas or matplotlib. The distribution reveals that most functions have fan-in and fan-out values below 2, meaning OpenClaw’s code is largely linear: most functions sit in a simple “one-in, one-out” position in the call chain.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-19-openclaw-technical-debt-1.png&quot; alt=&quot;fan-in and fan-out distribution histogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What stands out: &lt;strong&gt;over 20% of all functions have fan-in = 0&lt;/strong&gt; — they are never called by anything. After filtering out legitimate entry points and framework hooks, &lt;strong&gt;more than 2,000 functions remain that are true zombie code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a concrete example. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assertPublicHostname&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/infra/net/ssrf.ts&lt;/code&gt; has zero callers in the current codebase. A git bisect reveals:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5bd550&lt;/code&gt;: the function is introduced and actively used&lt;/li&gt;
  &lt;li&gt;Commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b62355&lt;/code&gt;: its logic is migrated to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resolvePinnedHostname&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;The old function is never deleted — likely out of caution — and silently becomes a zombie&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real harm isn’t the wasted lines. It’s what happens next: a new contributor finds the function, assumes it’s still relevant, builds something on top of it, and then spends hours debugging a dead code path.&lt;/p&gt;

&lt;p&gt;In a project with OpenClaw’s pace of change, a 20% zombie function rate is a significant cognitive tax on everyone who reads the code.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;finding-2-the-over-coupled-module&quot;&gt;Finding 2: The Over-Coupled Module&lt;/h2&gt;

&lt;p&gt;We analyzed the 20 most recent bug reports. Of 57 root-cause function candidates, &lt;strong&gt;24 — 42% — pointed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/agents&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To understand why, we ran a Cypher query to inspect &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agents&lt;/code&gt;’ call relationships with the rest of the system:&lt;/p&gt;

&lt;div class=&quot;language-cypher highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;m1:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;agents&apos;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:BELONGS_TO&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;f1:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:DEFINES_FUNC&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;func1:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:CALLS&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;func2:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:DEFINES_FUNC&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;f2:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:BELONGS_TO&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;m2:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m2.name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;agents&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m2.name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call_count&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call_count&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DESC&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The numbers below show bidirectional call counts between modules (a→b = calls from module a into module b):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;agents &amp;lt;-&amp;gt; reply              a→b=19    b→a=117
agents &amp;lt;-&amp;gt; infra              a→b=108   b→a=15
agents &amp;lt;-&amp;gt; pi-embedded-runner a→b=19    b→a=88
agents &amp;lt;-&amp;gt; tools              a→b=38    b→a=55
agents &amp;lt;-&amp;gt; plugins            a→b=45    b→a=40
agents &amp;lt;-&amp;gt; gateway            a→b=9     b→a=60
agents &amp;lt;-&amp;gt; src                a→b=35    b→a=31
agents &amp;lt;-&amp;gt; models             a→b=1     b→a=63
agents &amp;lt;-&amp;gt; sessions           a→b=46    b→a=5
agents &amp;lt;-&amp;gt; auth-profiles      a→b=24    b→a=12
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In total, &lt;strong&gt;30+ modules have bidirectional dependencies with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agents&lt;/code&gt;&lt;/strong&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reply&lt;/code&gt; module calls into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agents&lt;/code&gt; 117 times; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi-embedded-runner&lt;/code&gt; calls it 88 times; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;models&lt;/code&gt; calls it 63 times. The vast majority of the system’s business logic flows through this one module.&lt;/p&gt;

&lt;p&gt;We visualized the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reply-&amp;gt;agents&lt;/code&gt; call relationships using neug-ui:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-19-openclaw-technical-debt-2.png&quot; alt=&quot;agents module call relationship visualization&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agents&lt;/code&gt; is the structural hub of the system. A single-line change there can ripple across half the codebase. The fact that 42% of bugs trace back to this module isn’t bad luck — it’s an architectural consequence.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-graph-analysis-reveals-that-other-tools-dont&quot;&gt;What Graph Analysis Reveals That Other Tools Don’t&lt;/h2&gt;

&lt;p&gt;Code review catches function-level issues. Static analysis handles syntax and import-level concerns. Graph analysis fills the gap between them — &lt;strong&gt;cross-file, cross-module structural problems&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Traditional tools can tell you:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Which line has a syntax error&lt;/li&gt;
  &lt;li&gt;Which function has high cyclomatic complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NeuG can tell you:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;How many functions are affected by a single change&lt;/li&gt;
  &lt;li&gt;Which code is dead but still confusing contributors&lt;/li&gt;
  &lt;li&gt;Which module is the structural load-bearing wall of the system&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;When a codebase outgrows what human reviewers can hold in their heads, structural problems can only be found through structural queries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;three-recommendations-for-openclaw&quot;&gt;Three Recommendations for OpenClaw&lt;/h2&gt;

&lt;p&gt;Based on this analysis, the three highest-leverage improvements:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Decouple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/agents&lt;/code&gt;&lt;/strong&gt;: With 30+ modules in bidirectional dependency, start by defining clear interface boundaries between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agents&lt;/code&gt; and its heaviest callers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reply&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi-embedded-runner&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;models&lt;/code&gt;). Even partial decoupling would significantly reduce blast radius.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Prioritize test coverage for high-risk functions&lt;/strong&gt;: Functions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createConfigIO&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startGatewayServer&lt;/code&gt; are structurally critical but likely undertested. A bug there propagates everywhere. Cover them first.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Clean up zombie functions&lt;/strong&gt;: 2,000+ dead functions are actively misleading contributors. Running a graph-based dead code analysis and removing confirmed zombies is a high-ROI cleanup with low risk.&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Analysis powered by &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG&lt;/a&gt; graph database and CodeScope code analysis engine. Full index completed in approximately 4 minutes.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 19 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2026/03/19/OpenClaw-Technical-Debt-Analysis.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2026/03/19/OpenClaw-Technical-Debt-Analysis.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>OpenClaw Users: Why Is Your Token Budget Disappearing Out of Nowhere?</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-18-openclaw-token-cost-title.png&quot; alt=&quot;openclaw-token-cost-title&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Turns out, heartbeat has been quietly eating your tokens all along.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;OpenClaw&lt;/a&gt; has become one of the hottest open-source AI gateway projects. With 18,000+ commits and a rapidly growing community, it connects messaging platforms — Telegram, Discord, Slack, MS Teams, Lark, Matrix, and more — to various LLM providers. For many teams building AI-powered chatbots and agents, OpenClaw has become the go-to solution.&lt;/p&gt;

&lt;p&gt;But as adoption grows, so do user complaints — and one issue stands out: &lt;strong&gt;token consumption is way higher than expected&lt;/strong&gt;. Users report mysterious token budget drains, conversation histories that grow without bound, and system prompts bloating to 29K characters. Some hit the 200K token limit repeatedly, even with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightContext: true&lt;/code&gt; configured. These aren’t edge cases — they’re common pain points affecting real users and real budgets.&lt;/p&gt;

&lt;p&gt;What’s going on? Is it a misconfiguration? A model issue? Or something deeper in the codebase itself?&lt;/p&gt;

&lt;p&gt;To find out, we analyzed the entire OpenClaw codebase using &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG&lt;/a&gt; (graph database) + &lt;a href=&quot;https://github.com/alibaba/zvec&quot;&gt;zvec&lt;/a&gt; (vector index), producing a code knowledge graph with &lt;strong&gt;21,057 functions and 35,761 call edges&lt;/strong&gt;. What we discovered was surprising: one of the biggest token consumers is hiding in plain sight — the &lt;strong&gt;heartbeat mechanism&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we start from the end-user perspective and trace how a supposedly “lightweight” timer became a token-eating machine. Follow-up articles will cover the extension developer and core maintainer perspectives.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-problem-session-history-that-never-stops-growing&quot;&gt;The Problem: Session History That Never Stops Growing&lt;/h2&gt;

&lt;p&gt;If you are using OpenClaw and experiencing any of the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Conversation history that grows indefinitely without being truncated&lt;/li&gt;
  &lt;li&gt;A system prompt that bloats unexpectedly (one user reported 29K characters)&lt;/li&gt;
  &lt;li&gt;Repeatedly hitting the model’s 200K token limit&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightContext: true&lt;/code&gt; configured in HEARTBEAT.md, but with no noticeable effect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is likely not a misconfiguration or a model issue. One easily overlooked cause is OpenClaw’s &lt;strong&gt;heartbeat mechanism&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-is-heartbeat-secretly-doing&quot;&gt;What Is Heartbeat Secretly Doing?&lt;/h2&gt;

&lt;p&gt;OpenClaw’s heartbeat is a periodic timer. By design, it is supposed to be a lightweight tick that keeps the agent alive. We traced its call chain using &lt;a href=&quot;https://github.com/codescope/codescope&quot;&gt;CodeScope&lt;/a&gt;, and the results were surprising.&lt;/p&gt;

&lt;h3 id=&quot;step-1-locate-all-heartbeat-related-code&quot;&gt;Step 1: Locate All Heartbeat-Related Code&lt;/h3&gt;

&lt;p&gt;CodeScope provides two retrieval methods: text search (string matching) and semantic search (vector similarity). For a well-named codebase like OpenClaw, keyword search is usually sufficient to locate the core code. We query all functions containing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heartbeat&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-cypher highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;f:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f.name&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;CONTAINS&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;heartbeat&apos;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f.name&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;CONTAINS&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Heartbeat&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f.name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f.file_path&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f.file_path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The query returns &lt;strong&gt;68 functions&lt;/strong&gt; spread across 10 modules — infra, auto-reply, gateway, config, cron, and others. We visualized the results using &lt;a href=&quot;https://graphscope.io/neug/en/getting_started/neug_ui/&quot;&gt;neug-ui&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-18-openclaw-heartbeat-1.png&quot; alt=&quot;heartbeat functions distribution&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The infra module has the heaviest heartbeat presence, and most of it is concentrated in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heartbeat-runner.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is where conventional approaches stop.&lt;/strong&gt; Once you have the 68 functions and the core file, the usual next step is to feed the code to an LLM and ask it to explain. That process consumes tokens itself, and what you get back is a text description — not a queryable structure. You cannot directly ask: “Who calls whom?”, “How deep does the call chain go?”, “Which function is the structural center?”&lt;/p&gt;

&lt;p&gt;Graph analysis takes a different approach: &lt;strong&gt;instead of reading code content, we model the function-to-function call relationships as a graph&lt;/strong&gt;, turning structural questions into graph queries.&lt;/p&gt;

&lt;h3 id=&quot;step-2-find-the-core-entry-point-via-the-call-graph&quot;&gt;Step 2: Find the Core Entry Point via the Call Graph&lt;/h3&gt;

&lt;p&gt;We build a connectivity graph from the call relationships among the 68 functions and group them by connected component. The largest component contains &lt;strong&gt;45 functions&lt;/strong&gt;, indicating they form a tightly coupled core module. The remaining 19 components average just 1.2 functions each — mostly standalone interface or configuration functions.&lt;/p&gt;

&lt;p&gt;We then ran centrality analysis on the largest component: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runHeartbeatOnce&lt;/code&gt; connects &lt;strong&gt;27 functions within 3 hops&lt;/strong&gt;. The second-ranked function connects only 6. The gap is decisive: &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runHeartbeatOnce&lt;/code&gt; is the core entry point of the entire heartbeat mechanism&lt;/strong&gt;. Results below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-18-openclaw-heartbeat-2.png&quot; alt=&quot;runHeartbeatOnce centrality&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-3-expand-the-call-chain--what-does-it-actually-touch&quot;&gt;Step 3: Expand the Call Chain — What Does It Actually Touch?&lt;/h3&gt;

&lt;p&gt;We expand the multi-hop outgoing edges of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runHeartbeatOnce&lt;/code&gt; to find all context-loading functions it directly or indirectly calls:&lt;/p&gt;

&lt;div class=&quot;language-cypher highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Find context-loading functions in the runHeartbeatOnce call chain&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;f:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;runHeartbeatOnce&apos;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:CALLS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;t:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t.name&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;CONTAINS&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Context&apos;&lt;/span&gt;
   &lt;span class=&quot;ow&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t.name&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;CONTAINS&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Workspace&apos;&lt;/span&gt;
   &lt;span class=&quot;ow&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t.name&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;CONTAINS&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Session&apos;&lt;/span&gt;
   &lt;span class=&quot;ow&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t.name&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;CONTAINS&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Prompt&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t.name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t.file_path&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t.file_path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Results:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-03-18-openclaw-heartbeat-3.png&quot; alt=&quot;context-loading functions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every heartbeat tick triggers all of these functions&lt;/strong&gt; — loading the workspace directory, building a full session context, generating a complete prompt. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runHeartbeatOnce&lt;/code&gt; has &lt;strong&gt;15 direct callees&lt;/strong&gt;, each involved in parsing heartbeat configuration and assembling context. This is the structural root cause of heartbeat being far heavier than its design intended.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-doesnt-lightcontext-true-help&quot;&gt;Why Doesn’t &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightContext: true&lt;/code&gt; Help?&lt;/h2&gt;

&lt;p&gt;You may have set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightContext: true&lt;/code&gt; in HEARTBEAT.md, expecting heartbeat to load only a lightweight context.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightContext&lt;/code&gt; is a configuration flag, but it cannot change the structure of the call chain. As long as the dependency tree of heartbeat remains intact, every tick must load the workspace, build the session context, and traverse multiple modules. This is a path determined by the code structure — it cannot be bypassed by a flag.&lt;/p&gt;

&lt;p&gt;We also analyzed the modification frequency of the most recent 200 commits: 4 out of 21 functions in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;context-pruning&lt;/code&gt; module (responsible for context trimming) have been repeatedly modified recently. This indicates the OpenClaw team is aware of the context bloat problem and is actively working on a fix — but a stable solution is not yet available.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;codegraph-reproduce-this-analysis-yourself&quot;&gt;CodeGraph: Reproduce This Analysis Yourself&lt;/h2&gt;

&lt;p&gt;We have packaged the entire analysis workflow into a &lt;a href=&quot;https://github.com/alibaba/neug/tree/main/skills/codegraph&quot;&gt;CodeGraph Skill&lt;/a&gt;, published inside NeuG. You can use it to reproduce every query in this article.&lt;/p&gt;

&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CodeScope requires Python 3.10+ and PyTorch 2.4+.&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;codegraph-ai
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Environment variables:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Use HuggingFace offline mode if you have already downloaded the models&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;HF_HUB_OFFLINE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Set the database directory&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CODESCOPE_DB_DIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/path/to/your/project/.codegraph&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;building-the-index&quot;&gt;Building the Index&lt;/h3&gt;

&lt;p&gt;Index the OpenClaw repository:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Build the index (first run)&lt;/span&gt;
codegraph init &lt;span class=&quot;nt&quot;&gt;--repo&lt;/span&gt; /path/to/openclaw &lt;span class=&quot;nt&quot;&gt;--lang&lt;/span&gt; auto &lt;span class=&quot;nt&quot;&gt;--commits&lt;/span&gt; 100
&lt;span class=&quot;c&quot;&gt;# Check index status&lt;/span&gt;
codegraph status &lt;span class=&quot;nt&quot;&gt;--db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CODESCOPE_DB_DIR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sample output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;============================================================
CodeScope Index Summary
============================================================
  Files:      7083  (+ 5774 external)
  Functions:  24173  (+ 0 historical)
  Call edges: 41269
  Vectors:    24173
  Imports:    28877
  Classes:    255
  Modules:    380
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once indexed, you can query the graph via CLI or Python SDK.&lt;/p&gt;

&lt;h3 id=&quot;cli&quot;&gt;CLI&lt;/h3&gt;

&lt;p&gt;Check the database status:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;codegraph status &lt;span class=&quot;nt&quot;&gt;--db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CODESCOPE_DB_DIR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sample output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;============================================================
CodeScope Index Status: /path/to/.codegraph
============================================================

Graph:
  File        :     12,857
  Function    :     24,173
  Class       :        255
  Module      :        380
  Commit      :        100

Edges:
  CALLS       :     41,269
  TOUCHES     :        605
  MODIFIES    :          0

Backfill: 0/100 commits have MODIFIES edges
  100 commits still need backfill

Vectors: 24,173 function embeddings
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Natural language query:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;codegraph query &lt;span class=&quot;s2&quot;&gt;&quot;Who calls runHeartbeatOnce?&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CODESCOPE_DB_DIR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Question type: structural
Retrieved 6 evidence items in 76ms:

[1] (caller) executeJobCore (src/cron/service/timer.ts) — hop=1, relevance=0.000
[2] (caller) createGatewayReloadHandlers (src/gateway/server-reload-handlers.ts) — hop=2, relevance=0.000
[3] (caller) startGatewayServer (src/gateway/server.impl.ts) — hop=2, relevance=0.000
[4] (caller) executeJob (src/cron/service/timer.ts) — hop=2, relevance=0.000
[5] (caller) executeJobCoreWithTimeout (src/cron/service/timer.ts) — hop=2, relevance=0.000
[6] (caller) buildGatewayCronService (src/gateway/server-cron.ts) — hop=1, relevance=0.000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Generate a full architecture report with multi-dimensional analysis:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;codegraph analyze &lt;span class=&quot;nt&quot;&gt;--db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CODESCOPE_DB_DIR&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; architecture-report.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;python-sdk&quot;&gt;Python SDK&lt;/h3&gt;

&lt;p&gt;For more complex queries — such as the multi-hop call chain traversal used in this analysis — call the CodeGraph Python API directly, using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runHeartbeatOnce&lt;/code&gt; as an example:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;HF_HUB_OFFLINE&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1&apos;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;codegraph.core&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CodeScope&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CodeScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;CODESCOPE_DB_DIR&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&apos;&apos;
    MATCH (f:Function {name: &apos;runHeartbeatOnce&apos;})-[:CALLS*1..3]-&amp;gt;(t:Function)
    WHERE t.name CONTAINS &apos;Context&apos;
       OR t.name CONTAINS &apos;Workspace&apos;
       OR t.name CONTAINS &apos;Session&apos;
       OR t.name CONTAINS &apos;Prompt&apos;
    RETURN t.name, t.file_path
    ORDER BY t.file_path
&apos;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; @ &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We will continue to publish more analysis angles on OpenClaw. If you want to explore further or try your own queries, give CodeGraph a try.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-you-can-do-now-four-practical-mitigations&quot;&gt;What You Can Do Now: Four Practical Mitigations&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Treat heartbeat as a heavyweight operation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do not assume heartbeat is lightweight. When estimating token budgets, count every heartbeat tick as a real consumption event. Do not rely on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightContext: true&lt;/code&gt; to save tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Reduce heartbeat trigger frequency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your use case does not strictly depend on real-time heartbeat behavior, lowering the trigger frequency is the most direct and effective way to reduce token consumption. Fewer ticks = fewer full context loads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Manually cap session history length&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do not rely on OpenClaw to auto-truncate conversation history. Explicitly set a maximum history count in your configuration to prevent unbounded accumulation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Monitor for periodic token spikes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enable token usage monitoring on the LLM provider side. If you observe periodic, clock-like token spikes (rather than growth correlated with conversation length), heartbeat is likely triggering full context loads on schedule.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;We dissected heartbeat across three analytical layers:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Function distribution&lt;/strong&gt;: 68 heartbeat-related functions spread across 10+ modules, with the heaviest concentration in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heartbeat-runner.ts&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Call graph centrality&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runHeartbeatOnce&lt;/code&gt; is the core entry point — 15 direct callees, 27 functions reachable within 3 hops&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Call chain expansion&lt;/strong&gt;: every tick loads the workspace directory and builds full session context, with a load comparable to processing a complete user message&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Together, these findings explain one observation: &lt;strong&gt;heartbeat is designed as a lightweight timer, but its actual execution path is structurally equivalent to a full message-processing pipeline.&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightContext: true&lt;/code&gt; cannot override this. Until an official fix is available, reducing heartbeat trigger frequency and manually capping session history length are the most effective mitigations.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;This analysis is based on a scan of the OpenClaw codebase using &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG&lt;/a&gt; graph database and &lt;a href=&quot;https://github.com/alibaba/zvec&quot;&gt;zvec&lt;/a&gt; vector index.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 18 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2026/03/18/OpenClaw-User-Token-Cost-Analysis.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2026/03/18/OpenClaw-User-Token-Cost-Analysis.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>AI-Powered Open Source Development Management: NeuG&apos;s Exploration and Practice</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-02-12-neug-ai-dev-title.jpg&quot; alt=&quot;neug-ai-dev-title&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG&lt;/a&gt; is a lightweight, high-performance embedded graph database open-sourced by the &lt;a href=&quot;https://graphscope.io&quot;&gt;GraphScope&lt;/a&gt; team. It can be installed with a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip install neug&lt;/code&gt; and is designed for local analytics and real-time transaction processing. In this article, we share how we leverage AI capabilities to manage NeuG’s development workflow. In the future, we will further explore how NeuG’s graph computing capabilities can empower AI in return.&lt;/p&gt;

&lt;p&gt;We invite you to follow and star &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG repository&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;For more technical details, please refer to the &lt;a href=&quot;https://graphscope.io/neug/&quot;&gt;NeuG official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;pain-points-in-open-source-development-lack-of-comprehensive-project-management&quot;&gt;Pain Points in Open Source Development: Lack of Comprehensive Project Management&lt;/h2&gt;

&lt;p&gt;Managing open source software projects is one of the biggest pain points in the development process. If an engineer only focuses on writing code without an efficient management and tracking mechanism, the final product will struggle to be delivered on time. This is because open source projects inherently possess dynamic uncertainty — requirements can change at any moment.&lt;/p&gt;

&lt;p&gt;In recent months, AI Coding capabilities have been rapidly improving. However, we have found that the imbalance between development and management has actually worsened: developers can leverage the latest and most powerful models to rapidly generate large volumes of code, but this seemingly functional yet poorly readable and architecturally weak code only adds to the project management burden. As code accumulates, it may well be that only the large language model itself can deconstruct such a complex repository.&lt;/p&gt;

&lt;p&gt;In reality, we don’t lack coding capability. On the contrary, in open source projects, designing and breaking down solutions and tracking development progress are far more important. Taking our team’s &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;NeuG&lt;/a&gt; development as an example, the upfront PRD design and discussion can take up a third or even more of the entire development cycle. The recently popular “vibe-coding” is really only suitable for personal projects built from scratch — for serious development scenarios like databases, it is virtually inapplicable.&lt;/p&gt;

&lt;p&gt;Based on these reflections, we tried introducing AI tools into NeuG development in the role of “manager” rather than “developer,” covering the entire lifecycle from requirements analysis and task decomposition to GitHub synchronization and tracking.&lt;/p&gt;

&lt;h2 id=&quot;spec-driven-the-best-development-paradigm-for-neug&quot;&gt;Spec-Driven: The Best Development Paradigm for NeuG&lt;/h2&gt;

&lt;p&gt;In our early exploration, we still followed a “vibe-coding”-style workflow, letting AI directly manage requirements. We iterated through multiple versions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Developers write PRD documents, and the Coding Agent parses the context to decompose tasks, syncing them to GitHub.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The Coding Agent parses the Markdown structure of PRD documents before decomposing tasks.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The Coding Agent converts PRD documents into a standardized intermediate format before parsing and decomposing tasks.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Throughout this exploration, we continuously encountered common pain points such as detail loss from overly long contexts and inconsistent outputs. However, we gradually realized that a structured context might be the paradigm best suited for NeuG development. Many AI products also adopt similar structured contexts — for example, DingTalk’s meeting minutes allow pre-selecting templates, and some project documentation tools offer fully customized templates. After testing, we found that while enforcing output format alignment makes some content read a bit stiffly (for example, some development tasks simply don’t need corresponding unit tests), the completeness of such documents effectively reduces omissions — trimming is always easier than patching.&lt;/p&gt;

&lt;p&gt;Meanwhile, a wealth of Spec-Driven tools have been open-sourced, and we were among the first to try them. We found that the paradigm of “write project specifications first, then generate project code” highly aligned with our needs. Taking GitHub’s official &lt;a href=&quot;https://github.com/github/spec-kit/tree/main&quot;&gt;speckit&lt;/a&gt; as an example, here’s a brief explanation of what Spec-Driven involves and what each step does:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Specify&lt;/strong&gt;. In this phase, users provide a requirements description. This phase doesn’t involve specific technology stacks but focuses on product-level analysis: Who will use it? What features does it provide? What problems does it solve? What are the inputs and outputs? What is the interaction flow?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Plan&lt;/strong&gt;. In this phase, the AI tool generates a comprehensive development plan. This phase focuses on designing how to incorporate the requirement into the existing codebase, which modules are affected, and what constraints must be maintained. It therefore requires comprehensive code, architecture, and constraint information, with strict confirmation from development experts.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Tasks&lt;/strong&gt;. In this phase, the AI tool further decomposes the Plan into several executable tasks. Each task is a minimal, independently runnable code unit, making it convenient for the AI tool to test after code completion. Simply put, each task can be viewed as a standalone function.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Implement&lt;/strong&gt;. In this phase, the AI tool incrementally completes each task from the Tasks phase. Thanks to the well-prepared Specify, Plan, and Tasks, the AI tool can generate more accurate code that integrates better with the existing context.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Additionally, these Spec-Driven tools interact with the Coding Agent through slash commands. This invocation style is completely transparent and flexible, and users can freely adjust the prompts in Markdown files to create their own specifications. As we encountered the problem of overly verbose generated content, we began migrating our daily development habits into prompts, which significantly improved results. Below, we use a simple example to illustrate how NeuG leverages the Spec-Driven development paradigm to improve efficiency.&lt;/p&gt;

&lt;h2 id=&quot;use-case-adding-multi-threaded-transaction-tests-to-neug&quot;&gt;Use Case: Adding Multi-threaded Transaction Tests to NeuG&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;: Transaction functionality is one of the most important — and most error-prone — modules in a database. NeuG’s transaction engine implements lock-free read-insert parallelism and serializable isolation based on MVCC (see &lt;a href=&quot;https://graphscope.io/blog/tech/2026/02/11/NeuG-Transaction-Mechanism.html&quot;&gt;NeuG Transaction Mechanism Explained&lt;/a&gt; for details). To ensure this module executes correctly, we need to add various transaction tests. We attempted to use the Spec-Driven approach to let the large language model handle the entire process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;specify-phase-task-expansion-and-analysis&quot;&gt;Specify Phase: Task Expansion and Analysis&lt;/h3&gt;

&lt;p&gt;In the Specify phase, users can provide a brief requirements description along with some draft documentation (no format or content requirements), and the model independently organizes, expands, and generates a complete PRD document.&lt;/p&gt;

&lt;p&gt;In NeuG’s previous development workflow, PRD document design was a crucial step. However, writing a complete PRD document was extremely tedious and difficult to account for all edge cases and special scenarios. During the model’s document generation process, we enforced a document structure where a requirement is split into multiple modules, each module is further decomposed into multiple tasks, and each task must include corresponding tests and verification to ensure document completeness.&lt;/p&gt;

&lt;p&gt;Even when a task genuinely doesn’t need testing or verification (for example, cycle detection can directly call a third-party library), we still ask the model to list relevant content whenever possible. If some redundant content truly needs to be removed, we can simply edit it ourselves or prompt the model to modify the document. From practical experience, “trimming excess” is always easier than “filling gaps.”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-02-12-neug-ai-dev-specify.png&quot; alt=&quot;Specify Phase Screenshot&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;plan-phase-persisting-implementation-details&quot;&gt;Plan Phase: Persisting Implementation Details&lt;/h3&gt;

&lt;p&gt;The Plan phase is primarily responsible for further refining technical details and technology choices that weren’t covered in the Specify phase.&lt;/p&gt;

&lt;p&gt;During NeuG’s product development, we found that many design decisions are difficult to reflect intuitively in code, and the related technical documentation often lacks maintenance, directly leading to collaboration and handoff difficulties. As a solution, we chose to persist extensive technical details during the Plan phase. This content effectively serves as supplementary context for the Coding Agent’s code generation and provides convenience when producing technical reports later.&lt;/p&gt;

&lt;p&gt;As shown in the figure below, we needed to standardize transaction generation ratios and data formats, and determine transaction execution strategies for multi-threaded scenarios. Additionally, transaction testing relies on specific testing workflows, requiring detailed descriptions of dependency graph construction, dependency analysis, and cycle detection algorithms. This content significantly improves the accuracy and consistency of subsequent code generation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-02-12-neug-ai-dev-plan.png&quot; alt=&quot;Plan Phase Screenshot&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;tasks-phase-decomposing-tasks-syncing-to-github&quot;&gt;Tasks Phase: Decomposing Tasks, Syncing to GitHub&lt;/h3&gt;

&lt;p&gt;In the Tasks phase, the Coding Agent generates several Modules and Tasks based on the previous documents and syncs them to GitHub Issues. Our hierarchical structure perfectly aligns with GitHub’s Sub-Issue feature, making it convenient to track the entire development progress of a requirement end-to-end.&lt;/p&gt;

&lt;p&gt;In NeuG’s past development, these Issues were created and linked manually — not only time-consuming and labor-intensive, but when a new requirement was inserted, older requirements were often overlooked. Through the Task phase tracking, we can not only generate Issues with one click but also persistently track the completion status of all Issues, preventing development tasks from stalling midway.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-02-12-neug-ai-dev-tasks.png&quot; alt=&quot;Tasks Phase Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, we customized our approach to NeuG’s development habits by creating separate Markdown files for each Module, storing detailed information about each task’s assignee, labels, and implementation details. This isolation ensures that when a requirement spans multiple parts of the project and requires collaboration from multiple developers, conflicts are avoided.&lt;/p&gt;

&lt;h4 id=&quot;github-sync-operations&quot;&gt;GitHub Sync Operations&lt;/h4&gt;

&lt;p&gt;In the Tasks phase, we need to sync tasks to GitHub for tracking. Specifically, multiple Module Issues are created under the main Issue, and each Module Issue further contains multiple Task Issues. The overall structure is consistent with the documentation and can be displayed very intuitively on GitHub.&lt;/p&gt;

&lt;p&gt;We also designed a set of synchronization rules tailored to our team’s development habits: initially, the entire Module Content is synced to the Issue body, but no specific Sub-Issues are created. Only when a specific task is about to be developed is the corresponding Issue created, and upon completion, the PR is merged and the Issue is closed. The reason for this design is that the overall plan continuously adjusts as development progresses — new requirements may be inserted or existing ones modified. Fixing the entire workflow at once would lead to high modification costs later.&lt;/p&gt;

&lt;p&gt;The figure below shows a development snapshot of the transaction testing requirement described above (displayed content differs slightly). We planned two Modules, each requiring 3 Tasks to complete. Currently, Tasks 101, 102, 201, and 202 have been completed, while the remaining two Tasks involve complex multi-query scenarios that require further support before implementation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-02-12-neug-ai-dev-github-sync.png&quot; alt=&quot;GitHub Sync Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To accommodate this usage pattern, we designed two separate Commands: sync-module and sync-task. They accept a Module ID or Task ID and generate the corresponding Issue, automatically completing the Sub-Issue linking. When the content of these Modules or Tasks is modified, the same two commands can be reused to update without needing to recreate.&lt;/p&gt;

&lt;h3 id=&quot;implement-phase-preserving-traditional-development&quot;&gt;Implement Phase: Preserving Traditional Development&lt;/h3&gt;

&lt;p&gt;In this phase, we don’t mandate the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/speckit.implement&lt;/code&gt;. Instead, we allow the task to be handed off to the corresponding developer for implementation. It doesn’t matter which tool they use to generate code (or even “old-school manual coding”), because the comprehensive context and specifications already provide sufficient constraints to naturally produce high-quality code.&lt;/p&gt;

&lt;p&gt;We also recognize the importance of testing, requiring that all Tasks must be supplemented with corresponding CI tests after implementation, ensuring they can execute correctly in an isolated test environment. This is also an area where current large language models excel, so we won’t elaborate further.&lt;/p&gt;

&lt;h2 id=&quot;github-integration-a-more-automated-issuepr-experience&quot;&gt;GitHub Integration: A More Automated Issue/PR Experience&lt;/h2&gt;

&lt;p&gt;Inspired by the Commands functionality, we further integrated more GitHub operations into the Coding Agent. Currently, we have implemented two core capabilities: Issue creation and PR creation. In these two Commands, we incorporated two very important paradigms:&lt;/p&gt;

&lt;h3 id=&quot;context-collection&quot;&gt;Context Collection&lt;/h3&gt;

&lt;p&gt;Context is critically important for Bug Issues. While Issue and PR creation already encourage users to fill in context thoroughly using templates, this step is extremely tedious. Our developers often need to copy terminal error messages, relevant code snippets, and error reproduction commands multiple times — and the useful information in these logs is minimal with poor readability.&lt;/p&gt;

&lt;p&gt;We introduced the create-issue and create-pr commands. Users can directly select relevant content, and the model reads the corresponding terminal or file content, automatically parsing and generating organized content for submission. Developers only need to review the final generated result, which is extremely convenient.&lt;/p&gt;

&lt;p&gt;Below is a simple example: by referencing error messages from the terminal and relevant source code, we prompt the model to submit an Issue and automatically configure the Parent Issue, Assignee, and Project information. In the era of large language models, this information doesn’t need to match exactly — a rough description is sufficient for the model to infer the best match.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;`/create-issue` [bash:15-20][main.cpp:150:210] Check the error messages and executed code, create an issue of type bug, link to parent issue #xx, assign to &quot;@user-xxx&quot;, and add to project &quot;Project-xxx&quot;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;creation-confirmation&quot;&gt;Creation Confirmation&lt;/h3&gt;

&lt;p&gt;When Git performs dangerous operations like merge or rebase, it typically displays a confirmation file for the user to review. Inspired by this, we believe that creating Issues and PRs can similarly incorporate a confirmation flow to verify Issue configurations.&lt;/p&gt;

&lt;p&gt;Specifically, before creating an Issue or PR, the Agent provides a file for user interaction to confirm the information to be submitted, with a structure roughly as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Issue Type: Bug
Issue Title: [BUG] &amp;lt;title&amp;gt;
Assignee: &amp;lt;assignee&amp;gt;
Labels: bug, &amp;lt;additional labels&amp;gt;
Project: NeuG v0.1
Parent Issue: #&amp;lt;parent-issue-id&amp;gt;

**Describe the bug**
A clear and concise description of what the bug is.

**Execution Logs**
The commands that can reproduce the issue.
1. Command 1: ...
2. Command 2: ...
...

**Expected behavior**
A clear and concise description of what you expected to happen.

**Error Message**
The error message in the terminal.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this temporary file, the configuration parameters for creating the Issue are listed in detail, along with the specific body content. Through this file, users can clearly confirm the Issue’s type, assignee, labels, project, parent issue, and other information. Only after user confirmation does the Agent create and execute the corresponding command. This semi-structured template also ensures greater consistency in subsequently generated commands, significantly reducing unexpected situations caused by users’ unfamiliarity with commands.&lt;/p&gt;

&lt;h2 id=&quot;agent-skills-support&quot;&gt;Agent Skills Support&lt;/h2&gt;

&lt;p&gt;Just as we were writing this blog post, another new paradigm — Agent Skills — was rolling out broadly. We won’t discuss the comparison between Commands and Skills here, but from a product design perspective, the advantage of Agent Skills lies in encouraging users to store large scripts, templates, and other information in separate folders, while keeping only concise but critical descriptions in the core file. Moreover, Agent Skills is fully compatible with Commands operations, invoked explicitly through slash commands. Therefore, we promptly migrated our commands to the Skills format, moving templates, scripts, and other content from prompts into independent files.&lt;/p&gt;

&lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.cursor
└── skills
    ├── speckit.specify
    │   ├── templates
    │   │   └── spec-template.md
    │   └── SKILL.md
    │
    ├── speckit.plan
    │   ├── templates
    │   │   └── plan-template.md
    │   └── SKILL.md
    │
    ├── speckit.tasks
    │   ├── templates
    │   │   ├── tasks-metadata-template.md
    │   │   └── tasks-module-template.md
    │   └── SKILL.md
    │
    ├── sync-modules
    │   └── SKILL.md
    │
    ├── sync-tasks
    │   └── SKILL.md
    │
    ├── create-issue
    │   ├── scripts
    │   │   └── gh-update.sh
    │   ├── templates
    │   │   ├── bug-issue.md
    │   │   └── feature-issue.md
    │   └── SKILL.md
    │
    └── create-pr
        ├── templates
        │   └── pull-request.md
        └── SKILL.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Throughout our experience with Spec tools, it became evident that using Coding Agents effectively involves a wealth of techniques — from the overall product application scenarios to the crafting of individual prompts, as well as various interaction paradigms and generation logic. These details are what truly unlock the model’s capabilities, and they explain why the same programming tools produce entirely different results in different people’s hands. In the future, we will continue exploring applications of large language model programming tools across various project development scenarios, letting AI truly unleash productivity.&lt;/p&gt;
</description>
        <pubDate>Thu, 12 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2026/02/12/AI-Powered-Development-Management-NeuG.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2026/02/12/AI-Powered-Development-Management-NeuG.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>Opensourcing NeuG</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-02-11-neug-title.jpg&quot; alt=&quot;neug-title&quot; /&gt;
We are pleased to announce the open source release of &lt;strong&gt;NeuG&lt;/strong&gt; (pronounced “new-gee”), a lightweight, high-performance embedded graph database designed for local analytics and real-time transaction processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;https://github.com/alibaba/neug&lt;/a&gt;&lt;br /&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: &lt;a href=&quot;https://graphscope.io/neug/en/overview/introduction/&quot;&gt;https://graphscope.io/neug/en/overview/introduction/&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-neug&quot;&gt;Why NeuG&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://graphscope.io&quot;&gt;GraphScope&lt;/a&gt; team has spent the past few years building large-scale graph computing engines. Along the way, we received consistent feedback from our community: many users don’t need distributed clusters. What they want is a graph database they can &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip install&lt;/code&gt;, explore data in Jupyter notebooks, run graph queries in Python scripts, and quickly spin up as a service when needed for production.&lt;/p&gt;

&lt;p&gt;This reminded us of what DuckDB did for relational data processing—an embeddable analytics database that doesn’t require deploying servers or configuring connection pools. Just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import duckdb&lt;/code&gt; and start working. We wanted to bring that same experience to graph data.&lt;/p&gt;

&lt;p&gt;NeuG is the result of that effort. It reuses the storage and query engine from GraphScope Flex (which achieved strong results on the &lt;a href=&quot;https://ldbcouncil.org/benchmarks/snb/interactive/2025-04-21-graphscope-flex-sf300/&quot;&gt;LDBC SNB Interactive benchmark&lt;/a&gt;), but with a redesigned interface layer that allows it to be embedded directly as a Python library. We also kept the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.serve()&lt;/code&gt; interface for switching to service mode when concurrent access is needed.&lt;/p&gt;

&lt;p&gt;NeuG is suited for scenarios where you need to process graph data locally and quickly: data science exploration, ML feature engineering, AI application prototyping, and lightweight applications where deployment simplicity matters.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;key-features&quot;&gt;Key Features&lt;/h2&gt;

&lt;h3 id=&quot;lightweight--embeddable&quot;&gt;Lightweight &amp;amp; Embeddable&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Lightweight&lt;/strong&gt;, all dependencies managed via third_party submodules&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Embeddable&lt;/strong&gt; design, currently supporting Python applications with more languages and platforms coming soon&lt;/li&gt;
  &lt;li&gt;Get started with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip install neug&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;neug&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;neug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Database&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/path/to/data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
    MATCH (a:Person)-[:KNOWS]-&amp;gt;(b:Person)
    RETURN a.name, b.name
&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dual-mode-architecture-htap&quot;&gt;Dual-Mode Architecture (HTAP)&lt;/h3&gt;

&lt;p&gt;NeuG provides two operational modes through a single lightweight core:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Mode&lt;/th&gt;
      &lt;th&gt;Use Case&lt;/th&gt;
      &lt;th&gt;Characteristics&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Embedded Mode&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Offline analytics, ML/AI pipelines&lt;/td&gt;
      &lt;td&gt;Import as a Python library, ideal for Jupyter notebooks, batch ETL, graph algorithm development&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Service Mode&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Online transactions, concurrent access&lt;/td&gt;
      &lt;td&gt;Call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.serve()&lt;/code&gt; to start a network service with multi-session ACID transactions&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;This design allows NeuG to adapt flexibly from prototyping to production deployment without changing your technology stack.&lt;/p&gt;

&lt;h3 id=&quot;cypher-native&quot;&gt;Cypher-Native&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Industry-standard Cypher query language&lt;/li&gt;
  &lt;li&gt;Built on &lt;a href=&quot;https://graphscope.io/blog/tech/2024/02/22/GOpt-A-Unified-Graph-Query-Optimization-Framework-in-GraphScope&quot;&gt;GOpt&lt;/a&gt;’s unified intermediate representation, designed for future &lt;a href=&quot;https://www.gqlstandards.org/&quot;&gt;ISO/GQL&lt;/a&gt; compatibility&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;extensible-by-design&quot;&gt;Extensible by Design&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Extension system inspired by PostgreSQL/DuckDB&lt;/li&gt;
  &lt;li&gt;Keep the core lean; add graph algorithms, vector search, and custom procedures through an extensible framework&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;acid-transactions&quot;&gt;ACID Transactions&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Embedded mode: Single-connection serial access with data consistency guarantees&lt;/li&gt;
  &lt;li&gt;Service mode: Multi-session concurrent transactions with read-write isolation&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;performance&quot;&gt;Performance&lt;/h2&gt;

&lt;p&gt;NeuG is built on the GraphScope Flex engine, which achieved industry-leading results on the &lt;strong&gt;LDBC SNB Interactive benchmark&lt;/strong&gt; using Cypher queries:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Metric&lt;/th&gt;
      &lt;th&gt;Result&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;80,000+ QPS&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Scale Factor&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;SF300 (~1 billion edges)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Audit Status&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Officially audited by LDBC&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;These results validate NeuG’s capability for high-concurrency transactional workloads. The full audit report is available on the &lt;a href=&quot;https://ldbcouncil.org/benchmarks/snb/interactive/2025-04-21-graphscope-flex-sf300/&quot;&gt;LDBC website&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;use-cases&quot;&gt;Use Cases&lt;/h2&gt;

&lt;p&gt;NeuG v0.1 is particularly suited for:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;AI/LLM Application Development&lt;/strong&gt;: Knowledge graph storage and querying for RAG systems and AI Agents&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Data Science &amp;amp; Research&lt;/strong&gt;: Graph exploration in Jupyter Notebooks—social network analysis, relationship mining, pattern discovery&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ML Feature Engineering&lt;/strong&gt;: Computing graph-structural features (node centrality, community structure, path patterns) as machine learning inputs&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Prototype to Production&lt;/strong&gt;: Use embedded mode for rapid iteration during development, switch to service mode for deployment—no technology stack changes required&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Edge Computing &amp;amp; Local-First Applications&lt;/strong&gt;: Run graph queries in resource-constrained environments without network connectivity&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;quick-start&quot;&gt;Quick Start&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Installation&lt;/span&gt;
pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;neug

&lt;span class=&quot;c&quot;&gt;# Verify installation&lt;/span&gt;
python &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;import neug; print(&apos;NeuG is ready!&apos;)&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;neug&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Create database and load sample data
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;neug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Database&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;./my_graph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_builtin_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;tinysnb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Execute queries
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
    MATCH (a:person)-[:knows]-&amp;gt;(b:person)-[:knows]-&amp;gt;(c:person),
          (a)-[:knows]-&amp;gt;(c)
    RETURN a.fName, b.fName, c.fName
&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; are mutual friends&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Switch to service mode
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;coming-soon-v02&quot;&gt;Coming Soon (v0.2)&lt;/h2&gt;

&lt;p&gt;v0.2 focuses on enhanced AI scenario support and data ecosystem integration:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Feature&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
      &lt;th&gt;Use Case&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Node.js Binding&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;TypeScript/JavaScript language binding&lt;/td&gt;
      &lt;td&gt;AI Agent development, web backend integration&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Graph Algorithm Extensions&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Leiden community detection and more&lt;/td&gt;
      &lt;td&gt;Knowledge graph clustering, entity grouping in GraphRAG&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Vector DB Extension&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Graph + vector hybrid retrieval&lt;/td&gt;
      &lt;td&gt;GraphRAG, semantic search + relationship reasoning&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Data Lake Integration&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;S3/OSS + Parquet format&lt;/td&gt;
      &lt;td&gt;Large-scale offline analytics, data platform integration&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Foreign Tables&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;Direct querying of external data sources&lt;/td&gt;
      &lt;td&gt;Interoperability with PostgreSQL, DuckDB, and relational ecosystems&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;technology-stack&quot;&gt;Technology Stack&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Query Language&lt;/strong&gt;: Cypher (ISO/GQL compatibility planned)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Query Optimization&lt;/strong&gt;: GOpt unified optimization framework&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Storage Engine&lt;/strong&gt;: GraphScope Flex&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Language Bindings&lt;/strong&gt;: Python (C++ API available, Node.js in development)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Platform Support&lt;/strong&gt;: Linux, macOS (x86_64, ARM64)&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;license&quot;&gt;License&lt;/h2&gt;

&lt;p&gt;NeuG is released under the Apache License 2.0.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;contributing&quot;&gt;Contributing&lt;/h2&gt;

&lt;p&gt;We welcome community participation and contributions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Star &amp;amp; Watch&lt;/strong&gt;: &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;https://github.com/alibaba/neug&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;

&lt;p&gt;NeuG is developed by the &lt;a href=&quot;https://graphscope.io&quot;&gt;GraphScope&lt;/a&gt; team at Alibaba, incorporating years of expertise in large-scale graph computing. We thank all developers who have contributed to this project.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Making graph data simple.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;https://github.com/alibaba/neug&lt;/a&gt;&lt;br /&gt;
Documentation: &lt;a href=&quot;https://graphscope.io/neug/en/overview/introduction/&quot;&gt;https://graphscope.io/neug/en/overview/introduction/&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 11 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2026/02/11/Opensourcing-NeuG.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2026/02/11/Opensourcing-NeuG.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>NeuG&apos;s High-Performance MVCC for Graph Workloads</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-02-11-neug-transaction-title.jpg&quot; alt=&quot;neug-transaction-title&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This article provides an in-depth look at NeuG’s transaction mechanism, which powers its high-throughput Transactional Processing (TP) capabilities while maintaining serializable isolation guarantees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NeuG Repository&lt;/strong&gt;: &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;https://github.com/alibaba/neug&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;executive-summary&quot;&gt;Executive Summary&lt;/h2&gt;

&lt;p&gt;NeuG is an embedded graph database supporting both Transactional Processing (TP) and Analytical Processing (AP) workloads through distinct execution models.&lt;/p&gt;

&lt;h3 id=&quot;operational-models--concurrency&quot;&gt;Operational Models &amp;amp; Concurrency&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Embedded mode&lt;/strong&gt;: Analytical queries run in embedded mode with concurrency managed at the Connection level. Within a given AP Connection, all queries (reads or writes) are executed serially. This model does not utilize the fine-grained parallel MVCC mechanism detailed for TP.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Service mode&lt;/strong&gt;: High-throughput TP operations are achieved via a single Write Connection managed by an internal service layer. This connection spawns multiple worker threads that execute in parallel, utilizing the MVCC and version management system described herein to enable lock-free read-insert parallelism and serializable isolation.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scope&lt;/strong&gt;: This document details the transaction mechanism powering the TP execution model. AP mode uses a simpler, connection-serialized approach for consistency.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;core-architecture--design-philosophy&quot;&gt;Core Architecture &amp;amp; Design Philosophy&lt;/h2&gt;

&lt;p&gt;The transaction design is driven by the need for maximal throughput on common graph operations. Recognizing that a dominant pattern is highly concurrent reads mixed with blind inserts, the system categorizes transactions to eliminate unnecessary synchronization. A global versioning system creates immutable snapshots for readers, while inserters proceed in parallel, coordinated only when modifying the same adjacency list.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;transaction-classification&quot;&gt;Transaction Classification&lt;/h2&gt;

&lt;p&gt;NeuG categorizes transactions into three types to optimize concurrency:&lt;/p&gt;

&lt;style&gt;
.transaction-table {
  width: 100%;
  table-layout: fixed;
}
.transaction-table td, .transaction-table th {
  padding: 12px 15px;
  vertical-align: top;
  word-wrap: break-word;
}
.transaction-table th:nth-child(1), .transaction-table td:nth-child(1) { width: 10%; white-space: nowrap; }
.transaction-table th:nth-child(2), .transaction-table td:nth-child(2) { width: 20%; }
.transaction-table th:nth-child(3), .transaction-table td:nth-child(3) { width: 30%; }
.transaction-table th:nth-child(4), .transaction-table td:nth-child(4) { width: 40%; }
&lt;/style&gt;

&lt;table class=&quot;transaction-table&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Key Property&lt;/th&gt;
&lt;th&gt;Concurrency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Read&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Graph traversal, point lookup&lt;/td&gt;
&lt;td&gt;Pure read; sees a versioned snapshot&lt;/td&gt;
&lt;td&gt;Parallel with all Inserts via MVCC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Insert&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Add vertices/edges&lt;/td&gt;
&lt;td&gt;Blind write; does not read existing graph&lt;/td&gt;
&lt;td&gt;Parallel with all Reads; fine-grained locks for edge adjacency lists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Update&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Complex CRUD&lt;/td&gt;
&lt;td&gt;Sees its own writes; can abort/rollback&lt;/td&gt;
&lt;td&gt;Currently exclusive; future two-phase design&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;em&gt;Focus: This article details the mechanisms for Read and Insert transactions within the TP worker pool.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;version-management-the-foundation-of-consistency&quot;&gt;Version Management: The Foundation of Consistency&lt;/h2&gt;

&lt;p&gt;NeuG maintains a global, monotonically increasing version timeline through two counters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Global Write Version (GWV)&lt;/strong&gt;: Atomic counter assigning unique IDs to write transactions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Global Read Version (GRV)&lt;/strong&gt;: The highest version where all prior writes are guaranteed committed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;transaction-version-assignment&quot;&gt;Transaction Version Assignment&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Read Transaction&lt;/strong&gt;: Starts with the current GRV as its snapshot version. GRV remains unchanged.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Insert Transaction&lt;/strong&gt;: Acquires the current GWV as its write version; GWV is atomically incremented.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;grv-advancement-logic&quot;&gt;GRV Advancement Logic&lt;/h3&gt;

&lt;p&gt;GRV advances only when a contiguous prefix of the version sequence is complete. A bit-set tracks completion within a sliding window.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2026-02-11-grv-advancement.png&quot; alt=&quot;GRV Advancement&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The example above demonstrates how GRV advances only when a contiguous prefix of transaction versions have completed. Although v₄ was already committed in STATE 1, GRV could not advance beyond v₀ because v₁ was still pending. Once v₁ commits, the continuous sequence v₀-v₂ becomes complete, allowing GRV to advance to v₂.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;mvcc-storage--visibility&quot;&gt;MVCC Storage &amp;amp; Visibility&lt;/h2&gt;

&lt;p&gt;NeuG implements a lightweight MVCC model optimized for graph workloads:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Single-Version Model&lt;/strong&gt;: Each vertex/edge stores exactly one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write_version&lt;/code&gt; (its creation version)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Visibility Rule&lt;/strong&gt;: A Read transaction with version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tₓ&lt;/code&gt; sees an element if and only if:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;element.write_version ≤ Tₓ
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This single-version approach simplifies storage and memory management while providing snapshot isolation for readers.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;concurrency-and-isolation-guarantees&quot;&gt;Concurrency and Isolation Guarantees&lt;/h2&gt;

&lt;h3 id=&quot;read-insert-parallelism&quot;&gt;Read-Insert Parallelism&lt;/h3&gt;

&lt;p&gt;Lock-free parallelism between reads and inserts is achieved because:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;No Read-Write Conflicts&lt;/strong&gt;: Insert transactions perform zero reads on existing graph data&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Non-Blocking Snapshot Reads&lt;/strong&gt;: Reads operate on an immutable version snapshot&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;write-write-coordination&quot;&gt;Write-Write Coordination&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Vertex Insertion&lt;/strong&gt;: Uniqueness is the caller’s precondition (assumed non-existent)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Edge Insertion&lt;/strong&gt;: Fine-grained, per-vertex adjacency locks prevent corruption when concurrent transactions add edges from the same source vertex. Lock atomicity prevents deadlocks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;serializable-isolation-guarantee&quot;&gt;Serializable Isolation Guarantee&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Reads&lt;/strong&gt;: A single version snapshot is inherently serializable&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Inserts&lt;/strong&gt;: Linearized by GWV assignment and persisted via WAL (see below). No internal read-dependencies ensure a deterministic, serializable order.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;insert-transaction-lifecycle--durability&quot;&gt;Insert Transaction Lifecycle &amp;amp; Durability&lt;/h2&gt;

&lt;p&gt;The lifecycle of an Insert transaction follows a carefully designed protocol to ensure both performance and durability:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. START &amp;amp; VERSION
   └── Assign GWV (e.g., v₇); atomically increment GWV to v₈

2. PREPROCESSING (Read-Only Phase)
   └── Validate IDs, schema, encode properties
   └── No graph modifications

3. COMMIT PERSISTENCE (Write-Ahead Log - WAL)
   └── Flush all mutation data to durable WAL
   └── This point defines durability
   └── On abort: log a minimal abort marker

4. ATOMIC APPLY
   └── Acquire necessary per-vertex adjacency locks
   └── Apply all vertex/edge inserts atomically, stamping with version v₇
   └── Update indexes

5. COMPLETION
   └── Mark transaction v₇ as complete in tracking bit-set
   └── Advance GRV if possible (e.g., from v₆ to v₇)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;recovery&quot;&gt;Recovery&lt;/h3&gt;

&lt;p&gt;After a crash, the system restores the last checkpoint and replays all committed WAL entries to guarantee durability. This design ensures that no committed transaction is lost while minimizing recovery time.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;performance-characteristics&quot;&gt;Performance Characteristics&lt;/h2&gt;

&lt;p&gt;The design choices in NeuG’s transaction mechanism deliver several performance benefits:&lt;/p&gt;

&lt;h3 id=&quot;high-read-throughput&quot;&gt;High Read Throughput&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Zero Lock Contention&lt;/strong&gt;: Read transactions never block on locks&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No Version Chain Traversal&lt;/strong&gt;: Single-version model eliminates multi-version lookup overhead&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Snapshot Isolation&lt;/strong&gt;: Readers see a consistent view without coordination&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;efficient-insert-processing&quot;&gt;Efficient Insert Processing&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Parallel Execution&lt;/strong&gt;: Multiple insert transactions execute simultaneously&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fine-Grained Locking&lt;/strong&gt;: Only edges sharing the same source vertex require coordination&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Minimal Synchronization&lt;/strong&gt;: No read-write conflicts to manage&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;predictable-latency&quot;&gt;Predictable Latency&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Lock-Free Reads&lt;/strong&gt;: Query latency is independent of write workload&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Deterministic Version Assignment&lt;/strong&gt;: Clear ordering of all transactions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;WAL-Based Durability&lt;/strong&gt;: Fast commit with background persistence&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;design-trade-offs&quot;&gt;Design Trade-offs&lt;/h2&gt;

&lt;h3 id=&quot;advantages&quot;&gt;Advantages&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Optimal for Read-Heavy Workloads&lt;/strong&gt;: Zero overhead for the common case of concurrent reads&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Simple Implementation&lt;/strong&gt;: Single-version storage reduces complexity&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Strong Guarantees&lt;/strong&gt;: Serializable isolation without complex protocols&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Predictable Performance&lt;/strong&gt;: Lock-free reads provide consistent latency&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;current-limitations&quot;&gt;Current Limitations&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Update Transactions&lt;/strong&gt;: Currently serialized; future work will enable greater concurrency&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Delete Operations&lt;/strong&gt;: Handled through Update transactions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Long-Running Transactions&lt;/strong&gt;: May delay GRV advancement temporarily&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;use-cases&quot;&gt;Use Cases&lt;/h2&gt;

&lt;p&gt;NeuG’s transaction mechanism is particularly well-suited for:&lt;/p&gt;

&lt;h3 id=&quot;real-time-graph-analytics&quot;&gt;Real-Time Graph Analytics&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Social Network Analysis&lt;/strong&gt;: Concurrent queries on user relationships while ingesting new connections&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Recommendation Systems&lt;/strong&gt;: Read-heavy workloads with periodic batch inserts&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fraud Detection&lt;/strong&gt;: Real-time pattern matching on continuously growing transaction graphs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;knowledge-graph-applications&quot;&gt;Knowledge Graph Applications&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;RAG Systems&lt;/strong&gt;: High-throughput entity lookups while incrementally building the knowledge base&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;AI Agents&lt;/strong&gt;: Parallel knowledge retrieval with concurrent fact insertion&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Semantic Search&lt;/strong&gt;: Snapshot-consistent queries during graph expansion&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;edge-computing&quot;&gt;Edge Computing&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Local-First Applications&lt;/strong&gt;: Embedded TP capabilities without distributed coordination&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;IoT Data Processing&lt;/strong&gt;: Continuous sensor data ingestion with real-time queries&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mobile Applications&lt;/strong&gt;: ACID guarantees in resource-constrained environments&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;future-work&quot;&gt;Future Work&lt;/h2&gt;

&lt;p&gt;The NeuG team is actively working on several enhancements to the transaction system:&lt;/p&gt;

&lt;h3 id=&quot;two-phase-update-transactions&quot;&gt;Two-Phase Update Transactions&lt;/h3&gt;

&lt;p&gt;Refining the Update transaction model to allow greater concurrency through:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Optimistic concurrency control&lt;/li&gt;
  &lt;li&gt;Conflict detection and resolution&lt;/li&gt;
  &lt;li&gt;Selective retry mechanisms&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;distributed-transactions&quot;&gt;Distributed Transactions&lt;/h3&gt;

&lt;p&gt;Extending the mechanism for distributed deployment:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Multi-node version coordination&lt;/li&gt;
  &lt;li&gt;Distributed WAL replication&lt;/li&gt;
  &lt;li&gt;Cross-shard transaction support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;advanced-optimizations&quot;&gt;Advanced Optimizations&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Adaptive Concurrency Control&lt;/strong&gt;: Dynamic adjustment based on workload patterns&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Version Garbage Collection&lt;/strong&gt;: Automatic cleanup of old versions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Intelligent Lock Management&lt;/strong&gt;: Reducing lock contention for hot vertices&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;implementation-details&quot;&gt;Implementation Details&lt;/h2&gt;

&lt;p&gt;For developers interested in the technical implementation:&lt;/p&gt;

&lt;h3 id=&quot;version-counter-design&quot;&gt;Version Counter Design&lt;/h3&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VersionManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gwv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AtomicCounter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Global Write Version
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AtomicCounter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Global Read Version
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;completion_bits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SlidingBitSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;assign_write_version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gwv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetch_and_increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_read_version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mark_complete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;completion_bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;try_advance_grv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;adjacency-lock-protocol&quot;&gt;Adjacency Lock Protocol&lt;/h3&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EdgeInserter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;insert_edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Acquire lock on source vertex&apos;s adjacency list
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertex_locks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Stamp with transaction version
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tx_version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adjacency_lists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;wal-format&quot;&gt;WAL Format&lt;/h3&gt;

&lt;p&gt;Each WAL entry contains:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Transaction ID (version)&lt;/li&gt;
  &lt;li&gt;Operation type (INSERT/UPDATE/ABORT)&lt;/li&gt;
  &lt;li&gt;Payload (vertices/edges with properties)&lt;/li&gt;
  &lt;li&gt;Checksum for integrity&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;comparison-with-other-approaches&quot;&gt;Comparison with Other Approaches&lt;/h2&gt;

&lt;h3 id=&quot;vs-traditional-rdbms-mvcc&quot;&gt;vs. Traditional RDBMS MVCC&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Feature&lt;/th&gt;
      &lt;th&gt;NeuG&lt;/th&gt;
      &lt;th&gt;Traditional RDBMS&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Version Storage&lt;/td&gt;
      &lt;td&gt;Single version per element&lt;/td&gt;
      &lt;td&gt;Multi-version chains&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Read Overhead&lt;/td&gt;
      &lt;td&gt;Zero lock contention&lt;/td&gt;
      &lt;td&gt;May need version traversal&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Write Model&lt;/td&gt;
      &lt;td&gt;Optimized for blind inserts&lt;/td&gt;
      &lt;td&gt;General-purpose updates&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Isolation Level&lt;/td&gt;
      &lt;td&gt;Serializable&lt;/td&gt;
      &lt;td&gt;Typically snapshot isolation&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;vs-graph-specific-systems&quot;&gt;vs. Graph-Specific Systems&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Feature&lt;/th&gt;
      &lt;th&gt;NeuG&lt;/th&gt;
      &lt;th&gt;Neo4j&lt;/th&gt;
      &lt;th&gt;JanusGraph&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Concurrency Model&lt;/td&gt;
      &lt;td&gt;MVCC&lt;/td&gt;
      &lt;td&gt;Lock-based&lt;/td&gt;
      &lt;td&gt;Optimistic locking&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Read Parallelism&lt;/td&gt;
      &lt;td&gt;Lock-free&lt;/td&gt;
      &lt;td&gt;Lock-based&lt;/td&gt;
      &lt;td&gt;Lock-free&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Transaction Scope&lt;/td&gt;
      &lt;td&gt;Local (embedded)&lt;/td&gt;
      &lt;td&gt;Local&lt;/td&gt;
      &lt;td&gt;Distributed&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Performance Focus&lt;/td&gt;
      &lt;td&gt;TP workloads&lt;/td&gt;
      &lt;td&gt;Mixed OLTP&lt;/td&gt;
      &lt;td&gt;OLAP-oriented&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;NeuG’s transaction mechanism delivers high-throughput serializable isolation for graph workloads by:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Categorizing transactions&lt;/strong&gt; into Read and Insert types&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Isolating them&lt;/strong&gt; via MVCC and versioned snapshots&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Synchronizing writes&lt;/strong&gt; with fine-grained locking and a global version order&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Guaranteeing durability&lt;/strong&gt; with a WAL-based commit protocol&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This design provides an optimal balance between performance, simplicity, and correctness for embedded graph database workloads. The system achieves lock-free read scalability while maintaining strong consistency guarantees—making it ideal for modern AI and analytics applications that require both high throughput and transactional integrity.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;learn-more&quot;&gt;Learn More&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href=&quot;https://github.com/alibaba/neug&quot;&gt;https://github.com/alibaba/neug&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Documentation&lt;/strong&gt;: &lt;a href=&quot;https://graphscope.io/neug/en/overview/introduction/&quot;&gt;https://graphscope.io/neug/en/overview/introduction/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Previous Post&lt;/strong&gt;: &lt;a href=&quot;https://graphscope.io/blog/tech/2026/02/11/Opensourcing-NeuG.html&quot;&gt;Opensourcing NeuG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Building robust graph transactions for the embedded era.&lt;/strong&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 11 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2026/02/11/NeuG-Transaction-Mechanism.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2026/02/11/NeuG-Transaction-Mechanism.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>New Breakthrough in Declarative Graph Benchmarking: GraphScope Flex Shatters LDBC SNB Interactive Benchmark World Record</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2023-07-20-title.jpg&quot; alt=&quot;release-note&quot; /&gt;
The &lt;a href=&quot;http://ldbcouncil.org/&quot;&gt;Linked Data Benchmark Council (LDBC)&lt;/a&gt; has released the latest results of its SNB Interactive Benchmark (via Declarative Queries), where &lt;a href=&quot;https://github.com/alibaba/GraphScope/tree/main/flex&quot;&gt;GraphScope Flex&lt;/a&gt; achieved a historic breakthrough with a throughput exceeding &lt;strong&gt;80,000&lt;/strong&gt; QPS (queries per second) – nearly &lt;strong&gt;twice&lt;/strong&gt; the performance of the previous record holder!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-06-13-ldbc-record.png&quot; alt=&quot;ldbc-record&quot; /&gt;&lt;/p&gt;

&lt;p&gt;LDBC is an internationally recognized authority in graph data and computing. Its Social Network Benchmark (SNB) simulates a Facebook-like social graph, covering CRUD operations, shortest-path queries, multi-hop traversals, and more, making it the industry’s gold standard for transactional online query performance evaluation. SNB supports two implementation approaches:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Imperative&lt;/strong&gt;: Requires graph experts to manually write and optimize queries in programming languages like C++.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Declarative&lt;/strong&gt;: Uses graph query languages like Cypher, with the system automatically optimizing execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this benchmark, GraphScope Flex exclusively used declarative Cypher queries for all test cases, demonstrating not only its leadership in declarative query optimization and execution but also its full-stack technical prowess – from underlying storage to high-level optimization.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;full-stack-optimization-synergistic-advancements-in-storage-and-compute&quot;&gt;Full-Stack Optimization: Synergistic Advancements in Storage and Compute&lt;/h2&gt;

&lt;p&gt;GraphScope Flex’s record-breaking performance is built on innovations across storage, compute, and scheduling:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Efficient Storage Structure&lt;/strong&gt;: Employs a compact adjacency list format with vertex/edge compression and memory layout optimizations, enabling larger graph datasets on the same hardware.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Intelligent Memory Management&lt;/strong&gt;: Enhances traversal locality via prefetching and caching, significantly reducing memory access latency.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;High-Concurrency Transaction Support&lt;/strong&gt;: Leverages MVCC (Multi-Version Concurrency Control) for high-throughput queries while maintaining low-latency data modification.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;End-to-End Vertical Optimization&lt;/strong&gt;: Coordinated optimizations across storage, compute, and scheduling layers ensure peak performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-milestone-in-declarative-graph-query-optimization&quot;&gt;A Milestone in Declarative Graph Query Optimization&lt;/h2&gt;

&lt;p&gt;Powered by its robust infrastructure, GraphScope Flex employs its in-house &lt;a href=&quot;https://graphscope.io/blog/tech/2024/02/22/GOpt-A-Unified-Graph-Query-Optimization-Framework-in-GraphScope&quot;&gt;GOpt Optimization Framework&lt;/a&gt; to intelligently transform declarative queries into high-performance execution plans:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Rule-Based Optimization (RBO)&lt;/strong&gt;: Pluggble heuristic rules (e.g., filter pushdown, field trimming, join fusion) optimize query plans, minimizing intermediate results and boosting efficiency.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Automatic Type Inference&lt;/strong&gt;: Dynamically deduces implicit type constraints in patterns, validating them against the data graph to avoid invalid traversals and improve cardinality estimation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost-Based Optimization (CBO)&lt;/strong&gt;: Uses high-order statistics and backend-registered cost models to search for optimal execution plans via branch-and-bound strategies, balancing data characteristics and system-specific implementations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The research behind GOpt has been accepted by &lt;a href=&quot;https://2025.sigmod.org/sigmod_industry_papers.shtml&quot;&gt;SIGMOD 2025&lt;/a&gt;. Additionally, we’ve published a detailed paper on arXiv outlining GraphScope’s optimizations for the LDBC SNB benchmark (&lt;a href=&quot;https://arxiv.org/abs/2503.22091&quot;&gt;paper link&lt;/a&gt;).&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;leading-in-both-declarative-and-imperative-snb-leaderboard&quot;&gt;Leading in Both Declarative and Imperative SNB Leaderboard&lt;/h2&gt;

&lt;p&gt;GraphScope currently holds the performance record for &lt;strong&gt;imperative queries&lt;/strong&gt; in the LDBC SNB Interactive benchmark. This latest breakthrough in declarative queries further cements its technical leadership – its declarative performance even surpasses other players’ records in imperative scenarios. This achievement proves that GraphScope Flex’s auto-optimized declarative queries are not only &lt;strong&gt;highly efficient&lt;/strong&gt; and &lt;strong&gt;user-friendly&lt;/strong&gt;, but also exceed manually tuned imperative solutions, dramatically lowering the barrier to high-performance graph querying.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The GraphScope team gratefully acknowledges the research contributions of Prof. Cheng Li (University of Science and Technology of China) and Prof. Ying Zhang (Zhejiang Gongshang University). Their rigorous prototype validation and performance benchmarking were instrumental in enhancing​the system’s performance during this benchmark evaluation.&lt;/p&gt;
</description>
        <pubDate>Thu, 12 Jun 2025 15:03:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2025/06/12/graphscope-flex-achieved-record-breaking-on-ldbc-snb-interactive-workload-declarative.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2025/06/12/graphscope-flex-achieved-record-breaking-on-ldbc-snb-interactive-workload-declarative.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>Why DuckDB Is Such A Good Database Product</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-10-title-picture.jpg&quot; alt=&quot;why-duckdb&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;tldr&quot;&gt;TL;DR&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;Although databases are ancient, they still provide guidance for LLMs development.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;DuckDB’s Success Formula&lt;/strong&gt;: Insight into trends + relentless focus on core competencies + extremely good product.&lt;/li&gt;
  &lt;li&gt;Everyone agrees on “big data,” but not everyone needs “big data.”&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://motherduck.com/blog/big-data-is-dead/&quot;&gt;“Big Data is Dead”&lt;/a&gt;, and large models are a better computational paradigm.&lt;/li&gt;
  &lt;li&gt;Be meticulous in initial technology selection, let data guide decisions, and avoid blind trust in authority.&lt;/li&gt;
  &lt;li&gt;Technology choices must always serve the product.&lt;/li&gt;
  &lt;li&gt;What appears “small and elegant” is actually the result of accumulated efforts in good products.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;It’s 2025, who still cares about databases? IT IS &lt;strong&gt;anyone who takes data seriously&lt;/strong&gt;. Since their inception in the 1970s, relational databases have remained the backbone of data management. Despite waves of NoSQL, NewSQL, and other trends, the dominance of traditional databases and SQL remains unshaken. At SIGMOD 2023, Don Chamberlin, co-creator of SQL, delivered a keynote titled &lt;a href=&quot;https://dl.acm.org/doi/10.1145/3555041.3589336&quot;&gt;“49 Years of Queries”&lt;/a&gt;, reflecting on the evolution of relational databases and SQL over nearly half a century. Chamberlin emphasized that the longevity of database systems stems from E. F. Codd’s foundational theories, such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Database_normalization&quot;&gt;Database Normalization&lt;/a&gt;&lt;/strong&gt;: Teaches structured data organization to eliminate redundancy.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Natural Language Queries&lt;/strong&gt;: A vision pursued since 1974 with Codd’s &lt;a href=&quot;https://dl.acm.org/doi/10.1145/1045283.1045298&quot;&gt;“Rendezvous”&lt;/a&gt; project, which led to SQL.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Relational_algebra&quot;&gt;Relational Algebra Closure&lt;/a&gt;&lt;/strong&gt;: Ensures uniform data formats for chained operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fast forward 55 years: large models dominate the AI landscape, unstructured data processing explodes, yet database theory remains deeply influential. Normalization principles guide large language model (LLM) training, inspiring slogans like &lt;a href=&quot;https://arxiv.org/pdf/2307.09288&quot;&gt;“Data Quality is All You Need”&lt;/a&gt;. Natural language queries finally thrive with LLMs (though perhaps too enthusiastically). Developers of agent systems now recognize the importance of &lt;a href=&quot;https://medium.com/@kyeg/unlocking-structured-outputs-with-agents-8b5a564b5d44&quot;&gt;closure and standardization&lt;/a&gt; in ensuring stable, end-to-end execution.&lt;/p&gt;

&lt;p&gt;In the ever-shifting tech world, databases stand out as a rare bastion of stability—flashy trends come and go, but &lt;strong&gt;foundational principles endure&lt;/strong&gt;. For database products, “mastering the fundamentals” (correctness, reliability, efficiency) remains paramount. This doesn’t imply stagnation. Instead, strong foundations empower us to navigate trends confidently. Enter &lt;a href=&quot;https://duckdb.org/&quot;&gt;DuckDB&lt;/a&gt;, a database that marries trend awareness with technical depth. This article explores how DuckDB’s team built a competitive product by &lt;strong&gt;balancing innovation and foundation&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;market-trends&quot;&gt;Market Trends&lt;/h1&gt;
&lt;p&gt;In 2023, MotherDuck founder Jordan Tigani’s blog &lt;a href=&quot;https://motherduck.com/blog/big-data-is-dead/&quot;&gt;“Big Data is Dead”&lt;/a&gt; sparked debate while crystallizing the rationale behind DuckDB’s embedded, lightweight, single-process design.&lt;/p&gt;

&lt;h2 id=&quot;debunking-big-data-mythsthree-truths&quot;&gt;Debunking “Big Data Myths”—Three Truths&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Most organizations don’t have “big” data&lt;/strong&gt;. Investor surveys reveal that even large B2B companies manage mere terabytes, with many operating on gigabytes. Internal data from SingleStore and others shows core datasets often fit in single-digit gigabytes. &lt;strong&gt;For most, data scale isn’t the bottleneck&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/blog/assets/images/2025-04-27-duckdb/1745314131999-6d1a31f8-cce4-4d16-b464-5ba953aab6b7.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Source: &lt;a href=&quot;https://motherduck.com/blog/big-data-is-dead/&quot;&gt;Big Data is Dead&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Storage-compute imbalance&lt;/strong&gt;. Modern architectures decouple storage and compute, but storage grows linearly while compute demand lags. Most analytics focus on recent data, leaving historical datasets underutilized. This “storage obsession” incurs maintenance costs for rarely accessed data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/blog/assets/images/2025-04-27-duckdb/1745314255837-38a43980-9230-431f-a704-c2f614d68426.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Source: &lt;a href=&quot;https://motherduck.com/blog/big-data-is-dead/&quot;&gt;Big Data is Dead&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Rapid data value decay&lt;/strong&gt;. Business data often loses relevance within weeks. Historical data serves audits or model training, not daily analytics. &lt;strong&gt;“Big data” is a game for the 1%&lt;/strong&gt;—most users operate within traditional single-machine capabilities.&lt;/li&gt;
&lt;/ol&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/blog/assets/images/2025-04-27-duckdb/1745314228128-11b4dbc0-2b5d-48db-8f65-146e40570add.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Source: &lt;a href=&quot;https://motherduck.com/blog/big-data-is-dead/&quot;&gt;Big Data is Dead&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-scale-up-revolution&quot;&gt;The Scale-Up Revolution&lt;/h2&gt;
&lt;p&gt;The “big data” era emerged when scaling out (distributed clusters) was cheaper than scaling up (powerful single machines). Today, hardware advancements flip this equation:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Memory/storage leaps&lt;/strong&gt;: DDR5 RAM hits 70GB/s bandwidth; NVMe SSDs approach DRAM latency.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unified architectures&lt;/strong&gt;: Apple’s M-series chips fuse CPU/GPU/NPU memory, slashing data movement overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result? Tasks once requiring Hadoop/Spark clusters now run efficiently on single machines. TPC-DS benchmarks show &lt;a href=&quot;https://mp.weixin.qq.com/s?__biz=MzU1NTg2ODQ5Nw==&amp;amp;mid=2247489796&amp;amp;idx=1&amp;amp;sn=f12a900681ff4d8ba5eb4aa2b38fc4db&amp;amp;chksm=fa8886daf63e08db5550fe6b4b5a46f42dfdf5fea6700cccb2d843844ce258bde47f4aa4904e#rd&quot;&gt;DuckDB outperforming Spark by 3-8x on 100GB datasets with 10x energy efficiency&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;large-models-vs-big-data&quot;&gt;Large Models vs. Big Data&lt;/h2&gt;
&lt;p&gt;Another significant reason for the decline of big data analytics lies in the gradual transition from “big data” to “large models.” As Large Language Models (LLMs) become the new technological cornerstone, the importance of traditional “big data” stacks is being re-evaluated. Large pre-trained models essentially act as &lt;a href=&quot;https://arxiv.org/pdf/2309.10668&quot;&gt;&lt;strong&gt;compression and distillation&lt;/strong&gt; of massive datasets&lt;/a&gt;. Insights that previously required labor-intensive analysis of terabytes of data are now embedded within these models. When people increasingly obtain information by querying models like GPT-4 instead of executing complex queries on logs or data warehouses, the underlying data processing and computational paradigms inevitably simplify.&lt;/p&gt;

&lt;p&gt;In this landscape, embedded databases like DuckDB thrive. Projects like DeepSeek’s &lt;a href=&quot;https://github.com/deepseek-ai/smallpond&quot;&gt;smallpond&lt;/a&gt; leverage DuckDB for lightweight, high-performance data processing.&lt;/p&gt;

&lt;h2 id=&quot;duckdbs-ascent&quot;&gt;DuckDB’s Ascent&lt;/h2&gt;
&lt;p&gt;Born in defiance of the ‘big data’ hype, DuckDB started with a simple insight: nobody was building an embedded analytical database. The chart below shows exactly what the creators saw missing:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/blog/assets/images/2025-04-27-duckdb/1745315954205-ef8dd17e-184b-4314-8d82-cde9a774a1eb.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Source：https://dl.acm.org/doi/10.1145/3299869.3320212)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Born in 2018, gaining explosive traction by 2022, DuckDB has by 2025 positioned itself as the de facto leader in the analytical processing database arena - an unprecedented rise for an embedded database:&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/blog/assets/images/2025-04-27-duckdb/1745316024111-fd54646d-162c-40d2-8c13-90c017f519a4.png&quot; width=&quot;800&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Source: &lt;a href=&quot;https://ossinsight.io/analyze/duckdb/duckdb#overview&quot;&gt;OSS Insight&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;product-excellence&quot;&gt;Product Excellence&lt;/h1&gt;
&lt;p&gt;DuckDB’s success isn’t just about riding the right trends - its killer product features deserve equal credit. While we could write volumes about its capabilities, let‘s highlight the most impressive ones.&lt;/p&gt;

&lt;h2 id=&quot;zero-copy-data-access&quot;&gt;Zero-Copy Data Access&lt;/h2&gt;
&lt;p&gt;DuckDB queries external files (CSV, Parquet) without importing data. Its vectorized engine and columnar format enable efficient scans, even with partial HTTP Range requests. For example:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;data.parquet&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Queries run directly on Pandas DataFrames or Arrow data, eliminating data duplication. This “Swiss Army knife” versatility aligns perfectly with data scientists’ workflows.&lt;/p&gt;

&lt;p&gt;Queries run directly on Pandas DataFrames or Arrow data, eliminating data duplication. &lt;strong&gt;This “Swiss Army knife” versatility aligns perfectly with data scientists’ workflows&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;httpfs-extension&quot;&gt;HTTPFS Extension&lt;/h2&gt;
&lt;p&gt;Drawing inspiration from PostgreSQL’s design, DuckDB was architected with extensibility as a first-class citizen from day one. Among its extensions, ​HTTPFS stands out as a stroke of genius. This extension enables direct access to HTTP(S) endpoints and cloud object storage (like S3) - meaning DuckDB can query remote data as if it were local tables, using nothing more than a URL.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;https://example.com/dataset/file.parquet&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;DuckDB automatically fetches only the required file segments via HTTP. For columnar formats like Parquet, it goes further by selectively retrieving just the needed columns, dramatically improving efficiency.&lt;/p&gt;

&lt;p&gt;This capability effectively complements the “big data” paradigm: users maintain large datasets in the cloud while pulling only relevant subsets for local analysis, even joining them with existing local datasets.&lt;/p&gt;

&lt;p&gt;In this quintessential &lt;strong&gt;“edge-cloud integration” scenario&lt;/strong&gt;, DuckDB delivers ad-hoc cloud data analysis &lt;strong&gt;without complex middleware&lt;/strong&gt; – streamlining data engineering workflows. Wait, isn’t this exactly how “datalakes” were supposed to work all along?&lt;/p&gt;

&lt;h2 id=&quot;the-ingenious-htap-strategy-of-seamlessly-integrating-oltpolap&quot;&gt;The Ingenious HTAP Strategy of Seamlessly Integrating OLTP/OLAP&lt;/h2&gt;

&lt;h3 id=&quot;the-pitfalls-of-htap&quot;&gt;The “Pitfalls” of HTAP&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hybrid_transactional/analytical_processing&quot;&gt;HTAP, or Hybrid Transactional/Analytical Processing&lt;/a&gt;, aims to provide both TP and AP capabilities within a single database. This presents an opportunity for both TP-oriented and AP-oriented databases to expand their business scenarios, making HTAP a fiercely contested battleground in the database market. But is HTAP really that great? Whether extending from TP to HTAP or vice versa, one risks falling into the seemingly sweet “trap” of HTAP:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Storage-Compute Dissonance&lt;/strong&gt;: OLTP relies on row-based storage (Row Store) for high-concurrency transactions, while OLAP requires column-based storage (Column Store) to accelerate aggregate computations. Forced integration necessitates maintaining two storage engines (e.g., row-store replicas + column-store replicas), leading to skyrocketing data synchronization overhead and consistency maintenance costs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Resource Contention and Performance Degradation&lt;/strong&gt;: OLTP’s short transactions (millisecond-level responses) compete with OLAP’s long queries (minute-level computations) for CPU, memory, and I/O resources.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Technological Conflict&lt;/strong&gt;: OLTP emphasizes ACID transactions and row-level locks, whereas OLAP only requires relaxed eventual consistency. For instance, full-table scans in analytical queries may trigger row-store lock contention, causing transactional operations to stall.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;why-not-leverage-the-big-players&quot;&gt;Why Not Leverage the “Big Players”?&lt;/h3&gt;
&lt;p&gt;DuckDB’s philosophy is: Instead of forcing a single system to handle both, let systems excelling in transactions and those specializing in analysis each play to their strengths, then bridge them. Thus, PostgreSQL and DuckDB—the two most scalable systems in the TP and AP domains—naturally converge.&lt;/p&gt;

&lt;p&gt;On one hand, DuckDB offers the Postgres Scanner extension, which can directly connect to a PostgreSQL database and map its tables as virtual views within DuckDB for querying. This allows DuckDB to act as an analytical accelerator, reading PostgreSQL’s live data without additional replication. This approach avoids the hassles of dual writes and asynchronous synchronization. During queries, data stored in PostgreSQL is efficiently read via its binary protocol, while analytical logic is executed within DuckDB.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;postgres_scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;dbname=myshinydb&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;public&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;mytable&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the other hand, the PostgreSQL ecosystem has seen a wave of extensions enhancing DuckDB’s AP capabilities, including the official pg_duckdb by DuckDB’s team.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/blog/assets/images/2025-04-27-duckdb/1745323859852-27f3b8fe-8447-4247-9430-4a26ab8d3d7a.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/duckdb/pg_duckdb&quot;&gt;pg_duckdb&lt;/a&gt;’s implementation, DuckDB aligns with PostgreSQL’s logical timestamp synchronization (Logical Timestamp Alignment), ensuring analytical queries are based on the latest consistent snapshot of the transactional database, avoiding dirty reads and phantom reads. Additionally, DuckDB leverages its Postgres Scanner to directly access PostgreSQL’s row-store tables, then uses its vectorized engine to execute OLAP queries, boosting AP performance without data replication. For example, in TPC-H benchmarks, third-party tests showed pg_duckdb achieving over &lt;a href=&quot;https://mp.weixin.qq.com/s?__biz=MzIzOTA2NjEzNQ==&amp;amp;mid=2454788670&amp;amp;idx=1&amp;amp;sn=24a3d2f17b8ad32dd7baed15598c4e28&amp;amp;chksm=ff377ebf7a2bfdf64db0980eddcdea4d586ee40f22ec68b865a5d3c464fcd7e745621b811583#rd&quot;&gt;1000x performance gains&lt;/a&gt; in complex analytical queries compared to native PostgreSQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PostgreSQL and DuckDB’s extensibility decouples the technical contradictions of OLTP and OLAP: PostgreSQL focuses on OLTP (e.g., order processing), DuckDB specializes in OLAP (e.g., real-time reporting), and the two achieve logical unity through in-process federated queries (rather than data copying).&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;graphscopes-attempts&quot;&gt;GraphScope’s Attempts&lt;/h3&gt;
&lt;p&gt;At this point, I can’t help but reflect on GraphScope’s attempt to extend graph analysis capabilities based on OLTP databases – the &lt;a href=&quot;https://github.com/GraphScope/GART&quot;&gt;GART project&lt;/a&gt; (unfortunately, GART’s latest commits are already six months old).&lt;/p&gt;

&lt;p&gt;GART’s original goal was to make OLTP databases the data source for graph analysis:&lt;/p&gt;

&lt;p&gt;OLTP databases offer mature data management solutions. In most enterprise applications, cleaned data first lands in OLTP databases (e.g., Ant Group’s OceanBase). Let GraphScope focus on graph analysis while leaving complex data management to mature OLTP databases. This vision aligns perfectly with DuckDB + PostgreSQL = HTAP. However, during GART’s development, GraphScope attempted to integrate graph analysis with transactional processing via real-time graph construction (Binlog parsing), but faced challenges:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Overly Heavy Architecture&lt;/strong&gt;: Required maintaining an independent graph storage and compute cluster, with overly long synchronization chains (introducing Kafka + GraphEngine).&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Limited Scenarios&lt;/strong&gt;: Strong reliance on external data warehouses made lightweight embedded graph analysis difficult. What if we adopted DuckDB and PostgreSQL’s design philosophy? Here’s a potential approach:&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Native Graph Operators&lt;/strong&gt;: Integrate libgrape-lite (or a lighter single-machine parallel version) via PostgreSQL’s extension interface to enable graph traversal, community detection, and other operations within the transactional database, avoiding cross-system data migration.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Federated Graph Computing&lt;/strong&gt;: Combine DuckDB’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read_parquet&lt;/code&gt; function to directly query graph data (via &lt;a href=&quot;https://graphar.apache.org/&quot;&gt;GraphAr&lt;/a&gt;) from cloud storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;product-oriented-extreme-performance&quot;&gt;Product-Oriented Extreme Performance&lt;/h1&gt;

&lt;p&gt;The previous chapters showcased some of DuckDB’s impressive product capabilities, but behind them all lies one defining characteristic: &lt;strong&gt;speed&lt;/strong&gt; – faster than large-scale Spark clusters, faster than PostgreSQL in OLTP scenarios. This performance stems from deliberate system design and architectural choices, such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Columnar Storage&lt;/strong&gt;: In analytical scenarios, computations typically only require a subset of columns. Traditional row storage would result in mostly inefficient scans, whereas columnar storage minimizes I/O by reading only relevant data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vectorized (Batch) Processing&lt;/strong&gt;: Operators process data in batches rather than row-by-row. This reduces function call overhead, improves cache utilization, and leverages modern hardware’s SIMD (Single Instruction Multiple Data) parallelism.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Zero-Copy Operations&lt;/strong&gt;: DuckDB meticulously avoids memory copies during data transformations. For example, when &lt;a href=&quot;https://duckdb.org/2021/12/03/duck-arrow.html&quot;&gt;reading Arrow data&lt;/a&gt;, DuckDB directly operates on Arrow memory buffers, and similarly outputs results in Arrow format. This enables seamless parsing of Arrow data within the query engine and direct Arrow-formatted result exports.&lt;/li&gt;
  &lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While these topics are widely discussed, let’s delve deeper into some of the early design choices highlighted in DuckDB’s research papers.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;computational-models&quot;&gt;Computational Models&lt;/h2&gt;

&lt;p&gt;During DuckDB’s development, two dominant computational models existed in the database field — &lt;strong&gt;Vectorized Execution&lt;/strong&gt; and &lt;strong&gt;Data-Centric Code Generation (Compiled Execution)&lt;/strong&gt; — with significant differences in architecture, performance characteristics, and use cases. Both models are backed by numerous well-known systems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Vectorized Execution&lt;/strong&gt;:
&lt;a href=&quot;https://ir.cwi.nl/pub/19958/19958B.pdf&quot;&gt;VectorWise&lt;/a&gt;, &lt;a href=&quot;https://www.redbooks.ibm.com/abstracts/tips1204.html&quot;&gt;DB2 BLU&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-overview?view=sql-server-ver16&quot;&gt;Columnar SQL Server&lt;/a&gt;, &lt;a href=&quot;https://github.com/UWQuickstep/quickstep&quot;&gt;Quickstep&lt;/a&gt;, etc.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Compiled Execution&lt;/strong&gt;:
&lt;a href=&quot;https://tableau.github.io/hyper-db/&quot;&gt;HyPer&lt;/a&gt;, &lt;a href=&quot;https://spark.apache.org/&quot;&gt;Apache Spark&lt;/a&gt;, &lt;a href=&quot;https://db.cs.cmu.edu/peloton/&quot;&gt;Peloton&lt;/a&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, comparing these models fairly is challenging. Directly contrasting real-world systems (e.g., HyPer vs. VectorWise) can lead to skewed conclusions due to differences in storage formats, parallelization strategies, etc. The DuckDB team adopted a &lt;strong&gt;unified experimental framework&lt;/strong&gt; for an apples-to-apples comparison:&lt;/p&gt;

&lt;h3 id=&quot;methodology&quot;&gt;Methodology&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Unified Framework&lt;/strong&gt;: Implemented both models in the same system — &lt;em&gt;Typer&lt;/em&gt; (compiled execution) and &lt;em&gt;Tectorwise&lt;/em&gt; (vectorized execution) — ensuring identical algorithms, data structures, and parallel frameworks.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Isolated Variables&lt;/strong&gt;: Only the execution engine was altered, eliminating interference from storage compression or optimizer variations.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cross-Scenario Validation&lt;/strong&gt;: Tested across TPC-H/SSB queries to analyze performance in compute-intensive, memory-bandwidth-sensitive, and other scenarios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is their comparative analysis from this &lt;a href=&quot;https://www.vldb.org/pvldb/vol11/p2209-kersten.pdf&quot;&gt;benchmark paper&lt;/a&gt;:&lt;/p&gt;

&lt;style&gt;
  .comparison-table {
    width: 100%;
    border-collapse: collapse;
    font-family: Arial, sans-serif;
    margin: 20px 0;
    box-shadow: 0 2px 3px rgba(0,0,0,0.1);
  }
  .comparison-table th {
    background-color: #f2f2f2;
    padding: 12px 15px;
    text-align: left;
    font-weight: bold;
    border-bottom: 2px solid #ddd;
  }
  .comparison-table td {
    padding: 10px 15px;
    border-bottom: 1px solid #ddd;
    vertical-align: top;
    min-width:150px;
  }
  .comparison-table tr:nth-child(even) {
    background-color: #f9f9f9;
  }
  .comparison-table tr:hover {
    background-color: #f1f1f1;
  }
  .comparison-table .dimension {
    font-weight: bold;
    color: #2c3e50;
  }
  .comparison-table .highlight {
    background-color: #e8f4f8;
  }
  @media screen and (max-width: 768px) {
    .comparison-table {
      display: block;
      overflow-x: auto;
    }
  }
&lt;/style&gt;

&lt;table class=&quot;comparison-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Comparison Dimension&lt;/th&gt;
      &lt;th&gt;Vectorized&lt;/th&gt;
      &lt;th&gt;Codegen (Compiled)&lt;/th&gt;
      &lt;th&gt;Why DuckDB Chose Vectorized&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td colspan=&quot;4&quot; class=&quot;dimension&quot;&gt;Performance Traits&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Compute-Intensive Workloads&lt;/td&gt;
      &lt;td&gt;Materializes intermediates; more instructions&lt;/td&gt;
      &lt;td&gt;Register-optimized; fewer instructions&lt;/td&gt;
      &lt;td class=&quot;highlight&quot;&gt;&lt;strong&gt;Memory access optimization&lt;/strong&gt;: OLAP workloads (e.g., hash joins/aggregations) benefit from lower memory stall cycles.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Memory-Bound Scenarios&lt;/td&gt;
      &lt;td&gt;Batch processing hides cache misses; optimized parallel memory access&lt;/td&gt;
      &lt;td&gt;Complex loops limit prefetching/out-of-order execution&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td colspan=&quot;4&quot; class=&quot;dimension&quot;&gt;Engineering Practicality&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Compilation Overhead&lt;/td&gt;
      &lt;td&gt;No runtime compilation; primitives pre-compiled&lt;/td&gt;
      &lt;td&gt;LLVM dynamic compilation adds latency (seconds for complex queries)&lt;/td&gt;
      &lt;td class=&quot;highlight&quot;&gt;&lt;strong&gt;Embedded-friendly&lt;/strong&gt;: No wait for JIT compilation; reduces first-run latency.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Debugging &amp;amp; Profiling&lt;/td&gt;
      &lt;td&gt;Isolated performance stats per primitive (e.g., selection/hash functions)&lt;/td&gt;
      &lt;td&gt;Fused operators in generated code obscure performance attribution&lt;/td&gt;
      &lt;td class=&quot;highlight&quot;&gt;&lt;strong&gt;Developer-friendly&lt;/strong&gt;: Easier for contributors to pinpoint optimizations.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td colspan=&quot;4&quot; class=&quot;dimension&quot;&gt;Hardware Compatibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;SIMD Optimization&lt;/td&gt;
      &lt;td&gt;Simple primitives enable manual vectorization (e.g., 8.4x speedup with AVX-512)&lt;/td&gt;
      &lt;td&gt;Complex loops rely on compiler auto-vectorization (limited to ICC)&lt;/td&gt;
      &lt;td class=&quot;highlight&quot;&gt;&lt;strong&gt;Future-proof&lt;/strong&gt;: Higher potential for SIMD utilization gains.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Multi-Core Parallelism&lt;/td&gt;
      &lt;td&gt;Balanced batch splitting in Morsel-Driven parallelism&lt;/td&gt;
      &lt;td&gt;Same framework, but complex code reduces HT efficiency (e.g., low gains on AMD)&lt;/td&gt;
      &lt;td class=&quot;highlight&quot;&gt;&lt;strong&gt;Thread scalability&lt;/strong&gt;: More balanced workload distribution.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td colspan=&quot;4&quot; class=&quot;dimension&quot;&gt;Functional Extensibility&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;OLTP Support&lt;/td&gt;
      &lt;td&gt;Inefficient for high-frequency single-row ops&lt;/td&gt;
      &lt;td&gt;Compiled stored procedures excel (ideal for HTAP)&lt;/td&gt;
      &lt;td class=&quot;highlight&quot;&gt;&lt;strong&gt;OLAP focus&lt;/strong&gt;: DuckDB targets analytics, not deep OLTP optimization.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dynamic Optimization&lt;/td&gt;
      &lt;td&gt;Supports runtime adaptation (e.g., dynamic aggregation)&lt;/td&gt;
      &lt;td&gt;Logic hardcoded in generated code; requires recompilation&lt;/td&gt;
      &lt;td class=&quot;highlight&quot;&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: Adapts to dynamic workloads.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td colspan=&quot;4&quot; class=&quot;dimension&quot;&gt;Storage Synergy&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Storage Synergy&lt;/td&gt;
      &lt;td&gt;Native fit for columnar formats (e.g., RLE/Dictionary)&lt;/td&gt;
      &lt;td&gt;Requires type conversion/decompression (added overhead)&lt;/td&gt;
      &lt;td class=&quot;highlight&quot;&gt;&lt;strong&gt;Columnar ecosystem&lt;/strong&gt;: Reduces intermediate data materialization.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Thus, DuckDB’s choice of vectorized execution was based on a &lt;strong&gt;systematic, comprehensive, textbook-grade evaluation&lt;/strong&gt; — even though &lt;a href=&quot;https://homepages.cwi.nl/~boncz/&quot;&gt;Peter Boncz&lt;/a&gt;, a pioneer of vectorized execution, was an early core advisor to DuckDB.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;high-efficiency-mvcc-implementation&quot;&gt;High-Efficiency MVCC Implementation&lt;/h2&gt;

&lt;p&gt;As an embedded database designed for analytical workloads, DuckDB’s concurrency control mechanism fundamentally differs from traditional OLTP databases. To address batch updates, columnar operations, high compression storage, and embedded lightweight requirements in analytical scenarios, DuckDB deeply optimized its &lt;a href=&quot;https://15721.courses.cs.cmu.edu/spring2019/papers/04-mvcc2/p677-neumann.pdf&quot;&gt;MVCC implementation strategy&lt;/a&gt; developed by the one and only &lt;a href=&quot;https://en.wikipedia.org/wiki/Thomas_Neumann&quot;&gt;Thomas Neumann&lt;/a&gt;, primarily solving:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Massive version management overhead&lt;/strong&gt;: Traditional row-level MVCC generates excessive redundant version data during batch updates&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Columnar compression vs. update conflicts&lt;/strong&gt;: Compressed column data cannot be updated in-place, requiring avoidance of frequent decompression/recompression&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Resource constraints in embedded scenarios&lt;/strong&gt;: Ensuring transaction efficiency under memory/storage limitations&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Analytical transaction characteristics&lt;/strong&gt;: Coexistence needs of long-running batch operations and high-concurrency queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below summarizes DuckDB’s innovative MVCC designs:&lt;/p&gt;

&lt;h3 id=&quot;optimizations-for-analytical-workloads&quot;&gt;&lt;strong&gt;Optimizations for Analytical Workloads&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Columnar Batch Granularity&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Row-level versions create massive Undo records during batch updates, consuming memory and incurring high scan costs&lt;/li&gt;
      &lt;li&gt;DuckDB uses “per 2048-row × per-column version metadata” to record entire batch modifications at once&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Storing Deltas Instead of Old Values&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Compressed pages cannot be modified in-place; Undo Buffer only records “change descriptions” while keeping old versions in original compressed blocks, minimizing write amplification&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;​&lt;strong&gt;Write Amplification-Minimized WAL/Checkpoint&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Bulk inserts (e.g., COPY 10GB CSV) first write directly to new data blocks, then log “block references” in WAL; commits atomically replace blocks, while rollbacks mark blocks as recyclable (avoiding “double writes”)&lt;/li&gt;
      &lt;li&gt;Default 16MB WAL threshold triggers auto-checkpoint (manual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CHECKPOINT&lt;/code&gt; supported); &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsync&lt;/code&gt; enforced pre-write for durability&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;lightweight--embedded-design&quot;&gt;&lt;strong&gt;Lightweight &amp;amp; Embedded Design&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Minimal Metadata&lt;/strong&gt;: 2048-row batch versions + columnar deltas ensure “zero cost when unmodified,” with memory usage scaling linearly only with modifications&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fast Startup&lt;/strong&gt;: Undo Buffer stored at data page tail; recovery only needs incremental WAL parsing. DuckDB survived 4000 TPCH refresh cycles in &lt;a href=&quot;https://github.com/dsrhaslab/lazyfs&quot;&gt;LazyFS&lt;/a&gt; power-failure/kill-process tests with zero data loss&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Compression-Friendly&lt;/strong&gt;: Version info is separated from data, keeping original column blocks compressed (no MVCC-triggered decompression/rewrites)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Single-Machine Concurrency&lt;/strong&gt;: Read transactions never block; conflicting batch writes auto-retry without lock contention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This design enables DuckDB to deliver ​&lt;strong&gt;near-zero-cost concurrent transactions&lt;/strong&gt; and ​&lt;strong&gt;analytical-grade throughput&lt;/strong&gt; in single-machine memory environments, meeting modern data science and local embedded applications’ demands for “lightweight, compressed, ready-to-use” performance.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;compilation-optimization-focused-efficiency-where-it-matters-most&quot;&gt;Compilation Optimization: Focused Efficiency Where It Matters Most&lt;/h2&gt;

&lt;p&gt;Traditional database systems rely on “heavyweight” optimizers, while DuckDB implements lightweight yet &lt;strong&gt;most&lt;/strong&gt;-practical optimization rules specifically tailored for embedded scenarios. For comparison, we examined the compiled file sizes of DuckDB versus two well-known optimization frameworks in the industry: &lt;a href=&quot;https://github.com/apache/calcite&quot;&gt;Calcite&lt;/a&gt; and &lt;a href=&quot;https://github.com/greenplum-db/gporca-archive&quot;&gt;ORCA&lt;/a&gt;:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/blog/assets/images/2025-04-27-duckdb/1745734878763-11ecef7d-9eb8-4620-9005-13fe7dcdbb5a.png&quot; width=&quot;600&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Clearly, these optimization frameworks are overly bulky for DuckDB’s needs. Although DuckDB’s engineers and researchers fully understand &lt;a href=&quot;https://duckdb.org/2024/11/14/optimizers.html&quot;&gt;the importance of query optimization for data systems, especially in analytical scenarios&lt;/a&gt;, they didn’t blindly pursue optimization perfection in their implementation. Instead, they strategically allocated their limited resources to the most critical areas, aligning with their vision of a “lightweight embedded analytical engine.” They achieved an elegant balance between optimization capability and resource consumption through multi-layered architectural innovations. Here are two particularly intentional design choices:&lt;/p&gt;

&lt;h3 id=&quot;rule-first-heuristic-optimization-framework&quot;&gt;&lt;strong&gt;Rule-First Heuristic Optimization Framework&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;DuckDB employs a two-stage heuristic optimization architecture:
	- &lt;strong&gt;First Stage&lt;/strong&gt;: Applies deterministic rewrite rules (e.g., predicate pushdown, expression simplification) based on logical equivalence, ensuring execution plan safety with minimal overhead (O(1) time complexity).
 	- &lt;strong&gt;Second Stage&lt;/strong&gt;: Performs lightweight statistics-based cost optimization, focusing only on critical paths (e.g., join ordering) with limited search scope. Dynamic pruning strategies keep optimization time within milliseconds.&lt;/p&gt;

&lt;h3 id=&quot;statistics-independent-cardinality-estimation-model&quot;&gt;&lt;strong&gt;Statistics-Independent Cardinality Estimation Model&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;DuckDB addresses the challenge of computing/missing statistics in embedded scenarios (e.g., when querying Parquet/CSV files directly where histograms can’t be precomputed) by introducing:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Foreign Key Inference Engine&lt;/strong&gt;: Automatically detects implied PK-FK relationships in schemas to build dynamic equivalence sets.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Selectivity Propagation Model&lt;/strong&gt;: Enables multi-table join cardinality estimation via chain calculations like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;card(A⋈B) = card(A) * card(B) / tdom&lt;/code&gt;, achieving over 90% accuracy without stored statistics.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;DuckDB didn’t just ride the “big data backlash” —- it weaponized it using a good product. By combining:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;​&lt;strong&gt;Vectorized Execution&lt;/strong&gt; (2-8x faster than Spark on 100GB datasets)&lt;/li&gt;
  &lt;li&gt;​&lt;strong&gt;Zero-Copy Workflows&lt;/strong&gt; (Arrow/Parquet as first-class citizens)&lt;/li&gt;
  &lt;li&gt;​&lt;strong&gt;PostgreSQL Symbiosis&lt;/strong&gt; (1000x+ OLAP speedups via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postgres_scan()&lt;/code&gt;)
…it redefined what’s possible in single-node analytics, achieving 90% of “big data” outcomes with 10% of the complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DuckDB’s success signals a paradigm shift:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Era&lt;/th&gt;
      &lt;th&gt;Dogma&lt;/th&gt;
      &lt;th&gt;DuckDB’s Answer&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;​&lt;strong&gt;2000s&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;“Normalize all data”&lt;/td&gt;
      &lt;td&gt;“Query raw Parquet”&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;​&lt;strong&gt;2010s&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;“Scale out or die”&lt;/td&gt;
      &lt;td&gt;“Scale up smarter”&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;​&lt;strong&gt;2020s&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;“ETL everything”&lt;/td&gt;
      &lt;td&gt;“Embed everywhere”&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;As LLMs democratize data access, DuckDB’s ​&lt;strong&gt;“small-data engine for a small-data world”&lt;/strong&gt; approach becomes prescient. The future belongs not to systems that demand data centralization, but to those that ​&lt;strong&gt;dissolve into the workflow&lt;/strong&gt; – invisible until needed, indispensable when used.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://dl.acm.org/doi/10.1145/3555041.3589336&quot;&gt;49 Years of Query&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.cs.cmu.edu/~pavlo/blog/2025/01/2024-databases-retrospective.html&quot;&gt;Databases in 2024: A Year in Review&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://motherduck.com/blog/big-data-is-dead/&quot;&gt;Big data is dead&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2309.10668&quot;&gt;Language Modeling Is Compression&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.vldb.org/pvldb/vol11/p2209-kersten.pdf&quot;&gt;Everything You Always Wanted to Know About Compiled and Vectorized Queries But Were Afraid to Ask&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://duckdb.org/2024/10/30/analytics-optimized-concurrent-transactions.html&quot;&gt;Analytics-Optimized Concurrent Transactions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://homepages.cwi.nl/~boncz/msc/2022-TomEbergen.pdf&quot;&gt;Join Order Optimization with (Almost) No Statistics&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://duckdb.org/2024/11/14/optimizers.html#expression-rewriter&quot;&gt;Optimizers: The Low-Key MVP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Sat, 26 Apr 2025 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2025/04/26/Why-DuckDB-Is-Such-A-Good-Database-Product.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2025/04/26/Why-DuckDB-Is-Such-A-Good-Database-Product.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
      <item>
        <title>GOpt Optimization Process: An In-depth Case Study Based on LDBC SNB Queries</title>
        <description>&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2024-02-22-title-picture.jpg&quot; alt=&quot;gopt&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In today’s data analysis landscape, the optimization of complex graph queries has been a persistent challenge for the industry. GOpt is an optimizer framework designed for complex graph queries and was officially presented at &lt;a href=&quot;https://arxiv.org/abs/2401.17786&quot;&gt;SIGMOD Industry 2025&lt;/a&gt;. Its core objective is to provide an efficient and universal optimization solution that adapts to various graph query languages and execution engines. In this article, we will delve into the key innovations of GOpt in unified graph query optimization and analyze its optimization process through specific query cases from &lt;a href=&quot;https://ldbcouncil.org/benchmarks/snb&quot;&gt;LDBC SNB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;GOpt achieves breakthroughs in the following areas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Seamless support for mainstream graph query languages: GOpt is compatible with current leading graph query languages, including &lt;a href=&quot;https://neo4j.com/docs/cypher-manual/current/introduction&quot;&gt;Cypher&lt;/a&gt; and &lt;a href=&quot;https://tinkerpop.apache.org&quot;&gt;Gremlin&lt;/a&gt;, with future plans to further support the graph query standard &lt;a href=&quot;https://www.gqlstandards.org&quot;&gt;GQL&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Unified optimization of complex patterns: Deep optimization of various complex patterns such as Triangle, Path, Square, Clique, etc. Figure Fig.1 illustrates the various complex pattern forms supported by GOpt.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/complex_patterns.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.1 Complex Patterns Supported by GOpt.&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Support for multi-pattern features in Cypher queries: GOpt first represents multi-patterns according to Cypher semantics as Inner/Left/Anti Joins, converting optimizations between multiple patterns into optimizations for Joins, thus directly reusing mature Join optimization rules from relational databases. Fig.2 showcases the various multi-pattern queries supported by GOpt and their internal representations within GOpt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/multi_patterns.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.2 Multi-Patterns Supported by GOpt.&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Integration with popular graph query execution engines: In a previous article &lt;a href=&quot;https://mp.weixin.qq.com/s/07w8YaH0VmhgJXJkDN0KUg&quot;&gt;Revolution: Enhancing Neo4j Efficiency with GOpt&lt;/a&gt;, we integrated GOpt into the Neo4j engine. Figure Fig.3 compares the execution effects of Neo4j and the GOpt optimization plans on the Neo4j engine. Within the &lt;a href=&quot;https://ldbcouncil.org/benchmarks/snb&quot;&gt;LDBC Social Network Benchmark (LDBC SNB)&lt;/a&gt; standard test suite (where IC and BI represent Interactive-Complex and Business Intelligence queries respectively), GOpt brings an average improvement of 15.8X for Neo4j. We have further integrated GOpt into the GraphScope engine, achieving an average query performance improvement of 243.4X compared to GraphScope’s built-in rule-based optimizer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/neo4_vs_gopt.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.3 Time Cost of LDBC Queries on Neo4j.&lt;/div&gt;

&lt;p&gt;In this article, we will further explore points 1, 2, and 3, delving deeply into the optimization process of GOpt. We have chosen standard queries from LDBC SNB as a case study to intuitively demonstrate GOpt’s optimization process. Regarding point 4, GOpt has designed a dedicated Physical Converter layer. However, due to the excessive focus on underlying implementations, we will release subsequent articles on our official account to further decrypt this part, mainly covering: “How to Integrate GOpt with Neo4j?” and “How to Integrate GOpt with DuckDB?”. Stay tuned.&lt;/p&gt;

&lt;h2 id=&quot;optimization-process&quot;&gt;Optimization Process&lt;/h2&gt;

&lt;p&gt;Fig.4 illustrates the system framework of GOpt, which mainly consists of the following three layers:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Query Parser&lt;/strong&gt;: Cypher/Gremlin queries first undergo syntax checking via &lt;a href=&quot;https://www.antlr.org&quot;&gt;Antlr&lt;/a&gt;, followed by conversion of the Antlr AST into an initial GIR structure through the GIRBuilder Tool.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;GIR Optimizer&lt;/strong&gt;: Applies optimizations based on the GIR structure, performing transform operations on the input GIR structure and outputting an optimized GIR structure. Depending on the implementation of transforms, optimizations can be executed based on heuristic or top-down search approaches.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Physical Convertor&lt;/strong&gt;: Further converts the physical execution plan into code that can be executed by backend engines.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/gopt_overview.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.4 System Overview of GOpt.&lt;/div&gt;

&lt;h3 id=&quot;gir-structure&quot;&gt;GIR Structure&lt;/h3&gt;

&lt;p&gt;Firstly, let’s introduce what the GIR structure is. GIR (Graph Intermediate Representation) is a graph query language-independent intermediate data structure for graph queries, encompassing definitions of data models and a series of operator combinations for manipulating these data models.&lt;/p&gt;

&lt;p&gt;The data model in GIR consists of graph data types and basic data types. Graph data types include Vertex (nodes), Edge (relationships), Path (paths), etc. Basic data types refer to Integer (integer), Float (floating point), String (character), Array/Map/Set (composite types), etc. GIR adopts data formats from relational databases: each data tuple contains multiple items, each with a name and a value, where the value type can be either a graph data type or a basic data type.&lt;/p&gt;

&lt;p&gt;Operator combinations in GIR include graph operators and relational operators.&lt;/p&gt;

&lt;p&gt;Graph operators define how queries retrieve graph data, including:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;GET_VERTEX: Represents fetching node data sources from a graph database or retrieving endpoints from input edge data.&lt;/li&gt;
  &lt;li&gt;EXPAND_EDGE: Represents fetching edge data sources from a graph database or expanding adjacent edges from input node data.&lt;/li&gt;
  &lt;li&gt;EXPAND_PATH: Represents expanding paths composed of multiple edges from input node data.&lt;/li&gt;
  &lt;li&gt;MATCH_PATTERN: Expresses the Match Clause in Cypher or Gremlin as a unified structure. In GIR, there are two ways to represent this: a. A composite structure consisting of the aforementioned graph operators, marked by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MATCH_START&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MATCH_END&lt;/code&gt; indicating the start and end of graph operators. b. Represented as a Graph structure using &lt;a href=&quot;https://jgrapht.org&quot;&gt;JGraphT&lt;/a&gt;. These two structures are equivalent and can be converted interchangeably, as shown in Fig.5(c), where the Match Clause in the left-side query is represented uniformly in both forms.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Relational operators include Filter, Sort, Limit, Unfold, Project, Group, Join, Union. The support for them in GOpt is consistent with traditional databases, hence we will not elaborate further here. As illustrated in Fig.5(c), both Cypher query Fig.5(a) and Gremlin query Fig.5(b) are uniformly represented as corresponding GIR structures.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/GIR.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.5 GIR Representation of Query Example.&lt;/div&gt;

&lt;h2 id=&quot;optimization-strategies&quot;&gt;Optimization Strategies&lt;/h2&gt;

&lt;p&gt;Next, we introduce how GOpt optimizes queries based on the GIR structure. The entire optimization process in the GIR Optimizer can be represented as a Directed Acyclic Graph (DAG). Each node in the DAG represents a Strategy, which embodies the execution of one or more rules. The edges in the DAG represent the sequential order of rule execution. GOpt executes these rules according to the topological sort of the DAG graph. Figure 6 shows a series of Strategies implemented by GOpt and their corresponding DAG relationships.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/DAG.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Figure 6: DAG of Optimization Process in GOpt.&lt;/div&gt;

&lt;p&gt;The interface definition for Strategy is as follows:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Strategy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;GIRPlan&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;GIRPlan&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Based on this interface, GOpt provides two types of Strategy implementations: RuleBasedStrategy and PatternStrategy.&lt;/p&gt;

&lt;p&gt;RuleBasedStrategy includes a series of heuristic rules, where each rule specifically implements the transform function to perform equivalent transformations on the input GIRPlan and output the transformed GIRPlan. These rules are partly reused from Calcite, including: FieldTrim, SortProjectTrans, AggJoinTrans. Additionally, to handle specific optimizations related to graph data and operations, GOpt has implemented specialized rules for graph data models, including: FilterIntoPattern, JoinToPattern, ComSubPattern, EVFusion, DegFusion, PKIndex, and LateProject.&lt;/p&gt;

&lt;p&gt;PatternStrategy primarily optimizes the sequence of graph operators within Patterns, referred to as PatternOrders. The transform method takes a Logical GIRPlan, composed of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MATCH_PATTERN&lt;/code&gt; and other relational operators, as shown in Figure 7(a); it outputs a Physical GIRPlan representing the PatternOrder, consisting of a series of physical operators, as shown in Figure 7(b). The transform method executes a top-down search algorithm as described in the &lt;a href=&quot;https://arxiv.org/abs/2401.17786&quot;&gt;GOpt paper&lt;/a&gt;, obtaining a series of PatternOrders along with their respective costs, and selects the PatternOrder with the lowest cost as the output Physical GIRPlan.&lt;/p&gt;

&lt;p&gt;Finally, through the Physical Convertor, the Physical GIRPlan is converted into an Execution Plan supported by various engines. As shown in Figure 7(c), the Physical GIRPlan is converted into an Execution Plan supported by the GraphScope engine, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expand(v1-&amp;gt;v2, v3-&amp;gt;v2)&lt;/code&gt; is converted to the ExpandIntersect implementation. In the Neo4j engine, this operator is converted to the ExpandInto implementation, as shown in Figure 7(d).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/optimize.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Figure 7: Optimization and Physical Conversion of Query Example.&lt;/div&gt;

&lt;h1 id=&quot;case-study&quot;&gt;Case Study&lt;/h1&gt;

&lt;p&gt;We selected a query case from LDBC SNB that involves complex patterns, multiple patterns, and aggregate computations, which are common optimization requirements. We represent this query using Fig.8 and Cypher as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/query_case.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.8 Query Case Description.&lt;/div&gt;

&lt;div class=&quot;language-cypher highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// M1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;person:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PERSON&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:KNOWS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherP&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherP&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;membership:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HASMEMBER&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forum&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// M2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherP&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:HASCREATOR&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:CONTAINEROF&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forum&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// M3&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;otherP&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:HASCREATOR&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:POST&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;:HASTAG&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;tag:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tag&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Filter&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person.id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$personId&lt;/span&gt;
      &lt;span class=&quot;ow&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$personId&lt;/span&gt;
      &lt;span class=&quot;ow&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;membership.joinDate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$minDate&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Aggregate&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;otherP&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_cnt&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;GOpt first converts the Cypher query into GIR (Graph Intermediate Representation) through the Query Parser, as shown in Fig.9. M1, M2, and M3 form the initial Join structure, followed by a series of relational operations.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/case_gir.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.9 Initial GIR of the Query Case.&lt;/div&gt;

&lt;p&gt;Next, the GIR Optimizer applies optimizations to the GIR based on strategies defined in the DAG (Directed Acyclic Graph). In the DAG diagram, we highlight the strategies that take effect for this query, as shown in Fig.10.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/case_dag.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.10 DAG of Optimization Process in the Query Case.&lt;/div&gt;

&lt;h2 id=&quot;optimization-rules&quot;&gt;Optimization Rules&lt;/h2&gt;

&lt;p&gt;We further explain the optimization rules applicable to this query:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;FilterIntoPattern: An extended implementation based on Calcite’s FilterIntoJoin. It pushes filtering conditions further down to graph operation operators within patterns. For example, given the following Cypher query:&lt;/p&gt;

    &lt;div class=&quot;language-cypher highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;),&lt;/span&gt;
       &lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e2&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;),&lt;/span&gt;
       &lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e3&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;// There is a &amp;lt;Join&amp;gt; between the two patterns in GIR&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e4&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3.name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;China&quot;&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1.name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;After applying this rule, the optimized query is equivalent to rewriting it as:&lt;/p&gt;

    &lt;div class=&quot;language-cypher highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;),&lt;/span&gt;
       &lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e2&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;China&apos;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;}),&lt;/span&gt;
       &lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e3&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;China&apos;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;})&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;// There is a &amp;lt;Join&amp;gt; between the two patterns in GIR&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;MATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e4&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1.name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;AggJoinTrans: Pushes aggregate operations down to the Join operator. This optimization rule is inspired by &lt;a href=&quot;https://calcite.apache.org/javadocAggregate/org/apache/calcite/rel/rules/AggregateJoinTransposeRule.html&quot;&gt;relational databases&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;JoinToPattern: Removes the Join operator between patterns and merges the left and right sub-patterns into a unified pattern. Whether patterns can be merged depends on whether the semantics remain consistent after merging. Based on the semantic requirements of different query languages, we define three types of semantics within patterns:
    &lt;ul&gt;
      &lt;li&gt;Homomorphism Semantics: Allows repetition of vertices or edges within the pattern, which is adopted by Gremlin.&lt;/li&gt;
      &lt;li&gt;Edge-Distinct Semantics: Allows repetition of vertices but not edges within the pattern, which is adopted by Cypher.&lt;/li&gt;
      &lt;li&gt;Vertex-Distinct Semantics: Allows repetition of edges but not vertices.&lt;/li&gt;
      &lt;li&gt;Vertex-Edge-Distinct Semantics: Neither vertices nor edges can repeat within the pattern.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;Since the Join between two patterns inherently represents Homomorphism semantics, this rule only applies under that premise.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;PatternStrategy: As described earlier, this strategy applies a Top-Down Search Algorithm to the input pattern structure and selects the optimal PatternOrder based on cost.&lt;/li&gt;
  &lt;li&gt;ComSubPattern: For the two sub-patterns involved in a Join, extracts their common parts as the original input data. If the common part consists of only a single vertex, the Join operation can be further optimized into an Expand operation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;optimization-process-1&quot;&gt;Optimization Process&lt;/h2&gt;

&lt;p&gt;The GIR Optimizer executes specific strategies on the GIR in the order specified by Fig.10:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;FilterIntoPattern is performed first: The filtering conditions &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{person.id = $personId, otherP &amp;lt;&amp;gt; $personId, membership.joinDate &amp;gt; $minDate}&lt;/code&gt; are pushed down to the graph operators that generate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;person&lt;/code&gt; nodes, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;otherP&lt;/code&gt; nodes, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;membership&lt;/code&gt; edges.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/case_filter.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.11 The Optimization of FilterIntoPattern.&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Next, AggJoinTrans is executed: This involves splitting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{otherP, count(post) as post_cnt;}&lt;/code&gt; related group operation. Part of it is pushed down into the left branch of the Join, while the other part remains after the Join to sum up the previously computed group results to ensure semantic equivalence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/case_agg.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.12 The Optimization of AggJoinTrans.&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;JoinToPattern is then applied: The Join operation between M1 and M2 is removed, and M1 and M2 are merged into a unified pattern M4. In this example, we assume the patterns conform to Homomorphism semantics, which is a prerequisite for applying this rule.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/case_join_pat.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.13 The Optimization of JoinToPattern.&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;PatternStrategy is executed next: The following figure represents the output Optimal Pattern Order, consisting of a series of physical operators.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/case_cbo.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.14 The Optimization of PatternStrategies in M3 and M4.&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Finally, ComSubPattern is applied: This optimizes the reusable common results between patterns. As shown in Fig.14, in the left branch of the Join, M4 produces two columns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(p2, _cnt)&lt;/code&gt; after performing a Group operation, while the optimized PatternOrder of the right branch M3 starts with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Scan p2(PERSON, id &amp;lt;&amp;gt; $id)&lt;/code&gt;. Given that the common part only contains the single point p2, according to the ComSubPattern rule, the Join structure is further optimized into an Expand operation. Hence, M3 directly continues from the P2 point produced by the Group operation to execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expand p2-&amp;gt;&quot;&quot; (HASCREATOR)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/case_com.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;Tab.1 The LDCB&lt;sub&gt;100&lt;/sub&gt; DataSet.&lt;/div&gt;

&lt;h2 id=&quot;experimental-results&quot;&gt;Experimental Results&lt;/h2&gt;

&lt;p&gt;For the aforementioned case study, we conducted two main experiments: ablation tests and Pattern Orders. We used the LDBC&lt;sub&gt;100&lt;/sub&gt; dataset, as shown in Table Tab.1.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Graph&lt;/th&gt;
      &lt;th&gt;|V|&lt;/th&gt;
      &lt;th&gt;|E|&lt;/th&gt;
      &lt;th&gt;Size&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;sf100&lt;/td&gt;
      &lt;td&gt;283M&lt;/td&gt;
      &lt;td&gt;1754M&lt;/td&gt;
      &lt;td&gt;156GB&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;Tab.1 The LDCB&lt;sub&gt;100&lt;/sub&gt; DataSet.&lt;/p&gt;

&lt;p&gt;The system configuration consists of a single node with the following specifications:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;8-core Intel Xeon E5-2620 v4 CPUs at 2.1GHz&lt;/li&gt;
  &lt;li&gt;512GB memory&lt;/li&gt;
  &lt;li&gt;10Gbps network.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We used the &lt;a href=&quot;https://github.com/alibaba/GraphScope/releases/tag/v0.29.0&quot;&gt;GraphScope v0.29.0&lt;/a&gt; system, powered by the underlying &lt;a href=&quot;https://github.com/alibaba/GraphScope/tree/main/interactive_engine/executor/engine/pegasus&quot;&gt;Gaia&lt;/a&gt; engine, with 32 threads.&lt;/p&gt;

&lt;p&gt;The ablation tests primarily compare the individual optimization effects of the rules: FilterIntoPattern, AggJoinTrans, JoinToPattern, and ComSubPattern. To avoid mutual interference between these rules, we sequentially added them in the order defined in Fig.10 and compared the execution time after each rule was added. The results are shown in Table Tab.2.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Rules&lt;/th&gt;
      &lt;th&gt;Time Cost (ms)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;None&lt;/td&gt;
      &lt;td&gt;770573&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;+FilterIntoPattern&lt;/td&gt;
      &lt;td&gt;234313&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;+AggJoinTrans&lt;/td&gt;
      &lt;td&gt;214955&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;+JoinToPattern&lt;/td&gt;
      &lt;td&gt;64466&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;+ComSubPattern&lt;/td&gt;
      &lt;td&gt;7014&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div style=&quot;text-align:center;&quot;&gt;Tab.2 Time Cost of Ablation Tests in the Query Case.&lt;/div&gt;

&lt;p&gt;The Pattern Orders experiment compares the optimal order generated by PatternStrategy with two other randomly chosen orders. Figure Fig.16 illustrates the execution sequence of the three Pattern Orders and annotates the actual intermediate data volume produced at each step. Finally, we compare the execution times of the three orders in Table Tab.3.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2025-03-25-gopt/case_orders.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;Fig.16 Pattern Orders of GOpt-plan, Alt-plan1, Alt-plan2.&lt;/div&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Rules&lt;/th&gt;
      &lt;th&gt;Time Cost (ms)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;GOpt-plan&lt;/td&gt;
      &lt;td&gt;7014&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Alt-plan1&lt;/td&gt;
      &lt;td&gt;22211&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Alt-plan2&lt;/td&gt;
      &lt;td&gt;194047&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div style=&quot;text-align:center;&quot;&gt;Tab.3 Time Cost of Pattern Orders in the Query Case.&lt;/div&gt;
</description>
        <pubDate>Tue, 25 Mar 2025 00:00:00 +0000</pubDate>
        <link>https://graphscope.io/blog/tech/2025/03/25/GOpt-Optimization-Process.html</link>
        <guid isPermaLink="true">https://graphscope.io/blog/tech/2025/03/25/GOpt-Optimization-Process.html</guid>
        
        
        <category>Tech</category>
        
      </item>
    
  </channel>
</rss>
