HomeDocumentation

Documentation

How Dual-Graph works

A local MCP server that builds a persistent map of your codebase and a memory of your session β€” so your AI stops re-reading files it already knows about.

100% LocalNo CloudClaude CodeCodex CLIZero Config

The Problem

Why your AI keeps re-reading the same files

Every time you start a new conversation with Claude Code or Codex CLI, the AI has no memory of your project. It has to rediscover everything β€” which files exist, how they connect, what you changed last session. That rediscovery costs tokens on every single turn.

Even within a single session, most AI assistants will re-read the same files multiple times β€” once to understand the structure, again to make an edit, again to verify the result. Each re-read burns your context window and costs real money.

Dual-Graph solves this by keeping two persistent graphs on your machine: one that maps what your code does, and one that remembers what happened in your session. Together, they let your AI go straight to the right files β€” without starting from scratch.

Architecture

Two graphs, one purpose

When you run dgc . or dg ., Dual-Graph scans your project and writes two JSON files into a .dual-graph/ folder at your project root. Neither file ever leaves your machine.

Info Graph

info_graph.json

A static snapshot of your codebase structure. Built once when you first run Dual-Graph on a project, and updated whenever you re-scan.

  • β†’Every file as a node with its path and a content summary
  • β†’Every function and class as a symbol node with line ranges
  • β†’Import and dependency edges between files
  • β†’Used by graph_retrieve to rank files per query

Action Graph

chat_action_graph.json

A live session journal. Written to on every tool call and consulted at the start of every new turn to skip files already known.

  • β†’Every file that was read, with the query that triggered it
  • β†’Every edit, with which file and symbol was changed
  • β†’Locked decisions that persist across sessions
  • β†’Used by graph_continue for memory-first routing

The symbol index

Alongside the two graphs, Dual-Graph maintains a flat symbol_index.json β€” a lookup table mapping every file::symbol ID to its start line, end line, and a content hash. This lets graph_read extract just the lines of a function without loading the entire file.

When you write src/auth.ts::handleLogin in a tool call, Dual-Graph resolves that to a precise line range, reads only those lines, and records the access β€” saving significant token cost compared to reading the full file.

The retrieval cache

Retrieval results are cached on disk with a 15-minute TTL. If you ask the same question twice in the same session, the second call is instant. The cache is automatically invalidated whenever a file in the result set is modified on disk β€” so you never get stale results.

Session Flow

A session, turn by turn

Here is exactly what happens from the moment you run dgc . to the moment your AI gives you a response on turn three.

1
Scan & builddgc .

Dual-Graph scans every file in your project, builds the info graph and symbol index, and writes them to .dual-graph/. The MCP server then starts on a free local port and registers itself with Claude Code automatically.

2
Turn 1 β€” cold startgraph_continue(query)

On the very first turn, the action graph is empty so graph_continue returns confidence=low. Claude reads the recommended files normally, and Dual-Graph records every read and every decision into the action graph.

3
Turn 2 β€” memory firstgraph_continue(query) β†’ memory hit

On the second turn, graph_continue finds the files touched in turn 1 in the action graph. It returns them as recommended_files with confidence=high β€” meaning Claude goes directly to those files without re-scanning. The re-read cost drops to zero.

4
Turn N β€” fully warmCompounding savings

By turn N, the action graph has a rich history of reads, edits, and decisions. graph_continue routes with high confidence on almost every query. Each turn is cheaper and faster than the last. Savings compound across the session.

The turn read budget

Each turn has a hard cap of 18,000 characters of file content that the AI is allowed to read. This prevents runaway context consumption even when confidence is low. The budget resets at the start of each new query.

The reuse gate

Before reading a new file, Dual-Graph checks whether a previously-read file (from the action graph) already overlaps with the current query. If it does, Claude is instructed to check the cached content first before requesting a new read β€” enforcing a β€œread less, reuse more” behavior at the protocol level.

Configuration

The CLAUDE.md policy

Dual-Graph works by injecting a concise policy block into your project's CLAUDE.md file. This policy is what tells Claude how to use the MCP tools β€” without any manual configuration on your part. You never touch it directly.

CLAUDE.md (injected block)auto-managed
<!-- dgc-policy-vN -->
# Dual-Graph Context Policy

## MANDATORY: Always follow this order

1. Call graph_continue first β€” before any file exploration.
2. If needs_project=true: call graph_scan with the project root.
3. If skip=true: project is small, explore normally.
4. Read recommended_files using graph_read.

## Confidence caps (hard limits)
- high   β†’ Stop. Do NOT grep or explore further.
- medium β†’ fallback_rg at most N times, graph_read at most M files.
- low    β†’ fallback_rg at most N times, graph_read at most M files.

The policy is versioned (the vN comment at the top). When you update Dual-Graph, the installer replaces the old block with the new version automatically. Your own notes in CLAUDE.md are never touched.

Confidence levels

Every call to graph_continue returns one of three confidence levels. They are hard limits β€” not suggestions.

high

Stop. Do not grep or explore further.

The action graph already contains strong matches for the current query β€” previously-read or edited files cover the answer.

medium

Up to max_supplementary_greps greps and max_supplementary_files reads.

The action graph has partial matches. The recommended files are likely sufficient, but Claude may do limited supplementary work.

low

Up to max_supplementary_greps greps and max_supplementary_files reads.

No strong action history for this query. Claude reads the files the info graph recommended, within the defined caps.

Reference

MCP tools reference

These are the tools Dual-Graph exposes to Claude via the local MCP server. Claude calls them according to the injected CLAUDE.md policy β€” you never invoke them directly unless you want to.

graph_continue

Checks action memory for previously-read and edited files, then routes the AI directly to them. Returns a confidence level and a list of recommended files so Claude never starts a turn blind.

First call on every turn β€” mandatory.

graph_read

Reads a file from the project root and records it in the action graph. Supports file::symbol notation to read only the lines of a specific function or class β€” not the whole file.

After graph_continue returns recommended files.

graph_retrieve

Scores every file in the info graph against the current query and returns the top N ranked files and their import edges. Results are cached and invalidated automatically when files change on disk.

When confidence is medium or low and more context is needed.

graph_register_edit

Logs the edit into the action graph and flushes the retrieval cache for that file so future turns route to the new version. Uses file::symbol notation when the change targets a specific function.

Immediately after writing or editing a file.

graph_confirm_decision

Locks the decision into the action graph so it persists across sessions. Future sessions will see it as context β€” preventing Claude from re-deciding things that were already settled.

After making an important architecture or design decision.

graph_invalidate

Hard-removes a wrong assumption from action memory so it stops being surfaced in future turns. Useful when the graph has been routing to the wrong files due to stale context.

When a prior assumption turns out to be wrong.

graph_scan

Scans the project root, builds both the info graph and the symbol index from scratch, and writes them to .dual-graph/. Normally triggered by the dgc / dg CLI commands before the session starts.

Automatically on first use if no graph exists yet.

fallback_rg

A policy-capped grep substitute. The CLAUDE.md policy sets a hard maximum on how many times this can be called per turn β€” preventing the AI from falling back to brute-force file scanning.

Only when graph_continue returns confidence=low and you need a specific symbol.

Privacy

All data stays local

Every file Dual-Graph produces lives inside a .dual-graph/ folder at your project root, plus a shared ~/.dual-graph/ directory for the Python virtual environment and install files.

No outbound network calls

The MCP server runs on localhost. Your source code is never sent to any external service β€” not even to Anthropic or OpenAI.

No account or API key required

Dual-Graph itself needs no account, no license key, and no configuration. It is currently free to use.

What is stored on disk

.dual-graph/ (per project)
info_graph.json          ← static code structure (files, symbols, edges)
chat_action_graph.json   ← live session journal (reads, edits, decisions)
symbol_index.json        ← flat file::symbol β†’ line-range lookup
retrieval_cache.json     ← cross-turn retrieval cache (15 min TTL)
mcp_tool_calls.jsonl     ← tool call log for debugging
context-store.json       ← key decisions and tasks logged by Claude
None of these files contain your source code content β€” only metadata, file paths, line ranges, and hashes. The graphs record structure, not content.