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.
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_retrieveto 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_continuefor 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.
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.
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.
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.
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.
<!-- 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.
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.
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.
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_continueChecks 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_readReads 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_retrieveScores 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_editLogs 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_decisionLocks 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_invalidateHard-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_scanScans 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_rgA 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
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