npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

codetree-claude

v1.6.1

Published

MCP server & CLI: codebase index + cache for Claude Code, Cursor, OpenAI Codex, Google Antigravity/Gemini. Model Context Protocol tools (codetree_read, codetree_search, …), hooks on Claude, rules on other IDEs. Token savings, SQLite index, symbol search,

Readme

CodeTree

Persistent codebase index + Model Context Protocol (MCP) server for AI coding assistants. Cuts redundant Read / Grep / Glob token usage by routing AI tool calls through a cached SQLite index with symbol-aware APIs.

npm VS Code License Node

CodeTree works with Anthropic Claude Code, Cursor, OpenAI Codex, Google Antigravity / Gemini, and any MCP-compatible editor or CLI. A single codetree init wires the same MCP server into every tool's config format.


Table of Contents

  1. Why CodeTree
  2. Features
  3. Quick Start
  4. Supported AI Tools
  5. Architecture
  6. Component Design
  7. Data Flow Diagrams
  8. MCP Tools Reference
  9. CLI Commands
  10. Configuration
  11. Repository Layout
  12. How codetree init Wires Each IDE
  13. Reliability & Cross-Platform Notes
  14. Development
  15. Testing
  16. Contributing
  17. License

Why CodeTree

Teams using AI coding assistants spend a large fraction of their context window / tokens on re-reading the same files. Every chat re-runs Glob, Grep, and Read, and the model sees the same source again and again.

CodeTree solves this by maintaining a local, persistent SQLite index of your repo and serving requests through MCP tools that return:

  • Cached file content (mtime-validated, never silently stale)
  • Compact diffs when the file is mostly unchanged
  • Symbol outlines instead of full bodies
  • Symbol-aware search that bypasses raw text grep
  • Token-efficient project tree instead of Glob "**/*"

For Claude Code, CodeTree additionally installs PreToolUse hooks that intercept native Read/Grep/Glob calls and redirect them to the cache. For Cursor / Codex / Antigravity, the model is steered to the same MCP tools via project rules and AGENTS.md / GEMINI.md.


Features

  • Persistent SQLite index — survives restarts; cold start uses cached postings
  • In-memory LRU + compressed SQLite content cache — two-tier read path
  • Symbol extraction for JS/TS/JSX/TSX, Python, Java/Kotlin/C#, Go, Rust, Ruby
  • Token-postings index for fast multi-token content scans (avoids full-corpus grep)
  • mtime-validated reads — branch switches, external edits, merges all reflected
  • File watcher (chokidar) + safety-net rescan every 10 min for missed events
  • Singleton IPC server — deterministic per-project port; duplicates exit cleanly
  • Hooks for Claude CodePreToolUse, PostToolUse, SessionStart, Pre/PostCompact
  • Multi-IDE setup — one codetree init configures Claude, Cursor, Codex, Antigravity
  • VS Code extension — sidebar with token savings, indexed files, symbols, dashboard
  • Cross-platform — Windows \r\n safe, forward-slash paths in MCP configs
  • Per-tool telemetry — read/search/glob hits, misses, tokens saved, scan-cache hit rate

Quick Start

Option 1 — npm global

npm install -g codetree-claude
cd your-project
codetree init

Option 2 — per-project dev dependency

npm install --save-dev codetree-claude
npx codetree init

Option 3 — VS Code extension

Install "CodeTree — Cache for Claude Code" from the VS Code Marketplace. The extension activates CodeTree in the editor and shows the live dashboard.

After codetree init, reload your editor (Cursor / VS Code: Cmd/Ctrl+Shift+P → Developer: Reload Window). The MCP server starts automatically per project on the next AI session.


Supported AI Tools (multi-IDE)

| Product | What CodeTree configures | How tokens are saved | |---------|--------------------------|----------------------| | Claude Code (Anthropic) | Root .mcp.json, .claude/settings.json hooks, CLAUDE.md, .claude/rules/codetree.md | Hooks redirect native Read/Grep/Glob/Edit/Write to codetree_* when the cache can serve | | Cursor | .cursor/mcp.json, .cursor/rules/codetree.mdc | MCP tools + alwaysApply rules steer the agent | | OpenAI Codex | .codex/config.toml [mcp_servers.codetree], AGENTS.md | MCP tools + agent instructions (merge-safe TOML) | | Google Antigravity / Gemini | .antigravity/mcp.json, AGENTS.md, GEMINI.md | MCP + portable docs | | VS Code | Marketplace extension "CodeTree — Cache for Claude Code" | Sidebar dashboard + auto-mirroring MCP into .cursor/mcp.json | | Any MCP host | Same node …/dist/server/mcp-server.js entry | Register the MCP server manually if your tool uses a custom config path |

Note: Token-saving hooks (PreToolUse interception) are a Claude Code feature. Cursor / Codex / Antigravity rely on MCP + project rules — the model is steered to call codetree_read, codetree_search, etc., instead of native tools. The indexer, cache, and MCP tool surface are identical for all hosts.


Architecture

CodeTree is composed of six layered subsystems, each with a single responsibility. The whole stack is one Node process per project, started on demand by the MCP host.

┌──────────────────────────────────────────────────────────────────────┐
│  AI client                                                           │
│  (Claude Code / Cursor / Codex / Antigravity / any MCP host)         │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │  Steering layer                                                 │ │
│  │  - Claude Code: PreToolUse hooks + .claude/rules               │ │
│  │  - Cursor:      .cursor/rules/codetree.mdc (alwaysApply)       │ │
│  │  - Codex:       AGENTS.md + .codex/config.toml                 │ │
│  │  - Antigravity: AGENTS.md + GEMINI.md + .antigravity/mcp.json  │ │
│  └────────────────────────────┬───────────────────────────────────┘ │
└───────────────────────────────┼──────────────────────────────────────┘
                                │ MCP / stdio
┌───────────────────────────────▼──────────────────────────────────────┐
│  MCP Server  (src/server/mcp-server.ts)                              │
│  - Registers 10 tools, dispatches CallToolRequest                    │
│  - Routes telemetry through HTTP IPC                                 │
└──────────┬──────────────────────────────────┬────────────────────────┘
           │                                  │
┌──────────▼──────────────┐        ┌──────────▼────────────────────────┐
│  Tool Handlers          │        │  IPC Server (singleton, HTTP)     │
│  src/server/tools/*.ts  │        │  src/server/ipc.ts                │
│  - codetree_read        │        │  - Deterministic per-project port │
│  - codetree_search      │        │  - /check, /check-search,         │
│  - codetree_structure   │        │    /check-glob   (hook decisions) │
│  - codetree_outline     │        │  - /stats, /status, /mcp-call     │
│  - codetree_probe       │        │  - Owner / shared mode coordination│
│  - codetree_find_refs   │        └──────────┬────────────────────────┘
│  - codetree_summary     │                   │
│  - codetree_memory      │                   │ same process
│  - codetree_edit        │                   │
│  - codetree_write       │                   │
└──────────┬──────────────┘                   │
           │                                  │
┌──────────▼──────────────────────────────────▼────────────────────────┐
│  Indexer  (src/indexer/indexer.ts)                                   │
│  - fullScan / indexFile / safetyNetRescan                            │
│  - In-memory token postings  (Map<token, Set<relPath>>)              │
│  - readCached / readForScan  (mtime revalidation, disk fallback)     │
│  - looksBinary heuristic, file size cap                              │
│  - Uses ExtractorRegistry to pull symbols + dependencies             │
└──────────┬──────────────────────┬────────────────┬───────────────────┘
           │                      │                │
┌──────────▼──────────┐  ┌────────▼──────────┐  ┌──▼──────────────────┐
│  Storage            │  │  ContentCache LRU │  │  FileWatcher         │
│  src/storage/       │  │  (in-memory)      │  │  src/indexer/        │
│  database.ts        │  │  cache.ts         │  │  watcher.ts          │
│  - sql.js (WASM)    │  │  - hash-keyed     │  │  - chokidar          │
│  - files,           │  │  - mtime/size/    │  │  - debounce 300ms    │
│    symbols,         │  │    hash metadata  │  │  - .git/HEAD watcher │
│    dependencies,    │  │                   │  │    → branch switch   │
│    content_cache,   │  │                   │  │    cache invalidation│
│    token_postings,  │  │                   │  │  - error handler     │
│    trigrams,        │  │                   │  │    (EMFILE/ENOSPC)   │
│    previous_content │  │                   │  │                      │
│  - persistToDisk    │  │                   │  │                      │
└─────────────────────┘  └───────────────────┘  └──────────────────────┘

Layer Responsibilities

| Layer | File(s) | Responsibility | |-------|---------|----------------| | Steering | templates/, setup/install.ts | Idempotent install of MCP configs + rules into each IDE | | MCP Server | src/server/mcp-server.ts | Stdio transport, tool registration, lifecycle management | | Tool Handlers | src/server/tools/*.ts | One file per MCP tool; pure functions of (config, indexer, db) | | IPC Server | src/server/ipc.ts | HTTP server on deterministic port; serves hook decisions + telemetry | | Indexer | src/indexer/indexer.ts | The orchestrator — read / scan / extract / postings / token cache | | Storage | src/storage/database.ts, cache.ts | SQLite (sql.js WASM) + in-memory LRU | | Watcher | src/indexer/watcher.ts | chokidar + branch-switch detection + safety-net rescan | | Hooks (Claude only) | src/hook/*.ts | Bundled standalone scripts invoked by Claude Code per tool call | | CLI | src/cli.ts | init, status, stats, reindex, doctor, help |


Component Design

Indexer

The Indexer class (src/indexer/indexer.ts) is the heart of CodeTree.

  • fullScan() — incremental scan of the project tree. Each file goes through indexFile(), which short-circuits on (size, mtime) match (the cheap path) and only re-extracts on real change.
  • indexFile() — reads file, runs looksBinary heuristic (>5% unprintable bytes ⇒ skip), computes content hash, extracts symbols + dependencies via the language-specific extractor, writes to SQLite, populates LRU + content-cache, and updates the token-postings index.
  • readCached(relPath) — two-tier read: in-memory LRU first (with periodic mtime revalidation), then SQLite content cache (with mtime check against disk). On mismatch, re-indexes and serves fresh.
  • readForScan(relPath) — used by content-search loops. Like readCached but never returns null for files that exist: falls back to direct readFileSync and re-seats both caches. Counts hits/misses for scan telemetry.
  • safetyNetRescan() — cheap incremental sweep (mostly statSync + short-circuit) run every 10 min as backup against missed chokidar events on Windows / OneDrive / network drives.
  • Token postings (Map<lowercase-token, Set<relPath>>) — drives codetree_search content search, codetree_find_refs, and codetree_probe. Persisted to SQLite for instant cold start. Tokens are extracted with /[A-Za-z_][A-Za-z0-9_]{2,}/ (≥3 chars, capped per-file at 4000).

Storage

src/storage/database.ts — SQLite via sql.js (WASM, no native build). Tables:

| Table | Purpose | |-------|---------| | files | path, hash, size, mtime, language, line count, indexed-at | | symbols | name, kind, line span, signature, exported flag — keyed by file path | | dependencies | source path → target import specifier (resolved is null in current pass) | | content_cache | zlib-deflated file content; capped by cache.contentCacheMaxMB | | token_postings | per-file token list (for postings cold start) | | trigrams | content trigrams (for fuzzy content search) | | previous_content | older deflated content for diff-based reads (24h TTL, capped at 200 rows) |

src/storage/cache.ts — small in-memory LRU keyed by relPath. Stores raw text plus hash/mtime/size metadata. Hit/miss counters exposed on /stats.

IPC Server

src/server/ipc.ts (~1000 lines, single class IpcServer) exposes an HTTP API on a deterministic per-project port. Two responsibilities:

  1. Hook decisions/check, /check-search, /check-glob answer Claude Code hooks in <50 ms.
  2. Telemetry/stats, /status, /clear-cache, /mcp-call. Per-tool counters: readHits, searchHits, globHits, mcpCalls, tokensSaved, scanCacheHits, scanHitRate.

The IPC server is a singleton per project: it picks a deterministic port from the project root path. If another instance is already bound, it retries with backoff (200/400/800/1200 ms). On failure the duplicate process exits cleanly so two instances never race on the same SQLite write lock.

Hooks (Claude Code only)

Bundled into dist/hook/*.js (esbuild standalone scripts) and invoked by Claude Code via .claude/settings.json:

| Hook | When it fires | What it does | |------|---------------|--------------| | pre-tool-use | Before every Read/Grep/Glob | Asks IPC /check*; on cache hit, exits 2 with redirect message → Claude calls codetree_* instead | | post-tool-use | After every tool call | Updates session memory | | session-start | New chat session | Injects compact project summary (capped at 2 KB) | | pre-compact | Before context compaction | Saves current insights for recall | | post-compact | After compaction | Restores compact session context |

All hooks must complete in <50 ms and fail open (any error ⇒ exit 0, native tool runs).


Data Flow Diagrams

Flow 1 — AI agent reads a file (Claude Code)

Agent: Read("src/api/auth.ts")
  │
  ▼
Claude Code  ──── PreToolUse hook ────► pre-tool-use.js
                                          │
                                          ▼
                                        IpcServer  /check?path=…
                                          │
                          ┌───────────────┴───────────────┐
                          │                               │
                       cached                          not cached
                          │                               │
                          ▼                               ▼
              exit 2 + stderr message            exit 0 (allow)
              "Use codetree_read …"                  │
                          │                          │
                          ▼                          ▼
              Agent calls codetree_read       Native Read runs
                          │                          │
                          ▼                          ▼
              Indexer.readCached → LRU/SQLite   Disk read
                          │
                          ▼
              JSON: { content, hash, lineCount,
                      symbols, language,
                      unchanged_since_last_read? }

Flow 2 — AI agent reads a file (Cursor / Codex / Antigravity)

Agent (steered by .cursor/rules/codetree.mdc or AGENTS.md)
  │
  ▼ (decides to call codetree_read directly)
MCP Server  ──► CallToolRequest("codetree_read", {file_path, session_id?})
  │
  ▼
Tool handler (src/server/tools/codetree-read.ts)
  │
  ├── session+hash short-circuit?  → unchanged_since_last_read: true (no body)
  ├── expected_hash match?         → unchanged: true (no body)
  ├── outline_only or auto-fallback → symbols + metadata only (no body)
  └── focus_symbol set?            → return only symbol body + context
  │
  ▼
Indexer.readCached(relPath)
  │
  ├── LRU hit?  → mtime revalidate periodically → return content
  ├── SQLite content_cache hit? → mtime check vs disk → re-index if stale
  └── miss → null  (handler falls back to direct disk read for non-scan paths)
  │
  ▼
Response → MCP Server → JSON over stdio → Agent
  │
  └── (in parallel) IPC /mcp-call?tool=codetree_read&tokens=N updates telemetry

Flow 3 — Indexer lifecycle (server startup)

MCP host spawns:  node dist/server/mcp-server.js
  │
  ▼
loadConfig()  ──►  Database.init() (sql.js loads .codetree/index.db)
  │
  ▼
ContentCache(memoryLimitMB)  ──►  Indexer.init() (load token postings from SQLite)
  │
  ▼
IpcServer.start()  ──►  bind deterministic port
  │
  ├── port owned by another live codetree → retry (200/400/800/1200ms) → exit if duplicate
  ├── port acquired           → owner mode
  └── port already ours       → shared mode (skip scan + watcher)
  │
  ▼ (owner mode only)
indexer.fullScan()  ──►  walk project, indexFile() per file (incremental)
  │
  ▼
FileWatcher.start()  ──►  chokidar + .git/HEAD watcher + safetyNetRescan timer
  │
  ▼
Server.connect(StdioServerTransport())  ──►  ready for AI host requests

Flow 4 — File change → index update

Editor saves file  →  chokidar 'change' event  →  debounce 300ms
                                                       │
                                                       ▼
                                              Indexer.indexFile(absPath)
                                                       │
                              ┌────────────────────────┴────────────────────────┐
                              │                                                 │
                        size+mtime same                              size or mtime changed
                              │                                                 │
                              ▼                                                 ▼
                  short-circuit: skip extract                          read file → looksBinary?
                  (reseat content_cache if evicted)                            │
                                                          ┌────────────────────┴────────────────────┐
                                                          │                                         │
                                                       binary                                    text
                                                          │                                         │
                                                          ▼                                         ▼
                                                  delete from index                       hash → ExtractorRegistry
                                                                                                    │
                                                                                                    ▼
                                                                                  upsert files / symbols / deps
                                                                                  save trigrams + token postings
                                                                                  save previous content (for diffs)
                                                                                  update LRU + content_cache

Flow 5 — codetree init setup

codetree init
  │
  ▼
findGitRepos(cwd)  ──►  for each repo:
                          1.  createDefaultConfig            → .codetreerc.json
                          2.  updateGitignore                → adds .codetree/
                          3.  installHook                    → .claude/settings.json
                          4.  installMcpServer               → .mcp.json (Claude)
                          5.  installClaudeMd                → CLAUDE.md
                          6.  installClaudeRules             → .claude/rules/codetree.md
                          7.  installCursorMcp               → .cursor/mcp.json
                          8.  installCursorRules             → .cursor/rules/codetree.mdc
                          9.  installAntigravityMcp          → .antigravity/mcp.json
                         10.  installCodexMcp                → .codex/config.toml
                         11.  installAgentsMd                → AGENTS.md (block)
                         12.  installGeminiMd                → GEMINI.md

All install steps are idempotent — re-running codetree init only refreshes generated blocks.


MCP Tools Reference

All ten tools are available on every MCP host (Claude Code, Cursor, Codex, Antigravity, …).

| Tool | Replaces / complements | What it does | |------|------------------------|--------------| | codetree_read | Read | Cached read; supports outline_only, expected_hash (returns diff or "unchanged"), session_id short-circuit, focus_symbol narrowing, offset/limit pagination. Mtime-validated. | | codetree_outline | Read (lite) | File metadata + exported symbols + imports. No body. Cheapest browse primitive. | | codetree_probe | Grep (lite) | Returns only { file_path, line_numbers[] } per match. No snippets. Use for "does X mention Y?" triage. | | codetree_search | Grep | Symbol-name search + optional content search via token postings. Pagination via next_cursor. file_pattern narrows before scanning. | | codetree_find_refs | — | Cross-file references for a symbol; uses postings to narrow candidates. | | codetree_structure | Glob | Project file tree. format='text' ≈ 40% fewer tokens than JSON. path/depth/pattern narrow. Auto-collapses huge repos. | | codetree_summary | — | Whole-project overview: language breakdown, top files by symbol count, total estimated tokens. Use at session start. | | codetree_memory | — | Save / recall insights across sessions. get_context is aggressively trimmed. | | codetree_edit | Edit | Edit without prior Read. \r\n-safe on Windows. Updates index in place. | | codetree_write | Write | Write file without prior Read. Creates parent dirs. Updates index. |

Token-saving knobs (selected)

| Tool | Knob | Default | Effect | |------|------|---------|--------| | codetree_read | outline_only | false | Symbols + metadata only | | codetree_read | exported_symbols_only | true | Drop private symbols | | codetree_read | expected_hash | — | Unchanged ⇒ no body; changed ⇒ compact diff | | codetree_read | session_id | — | "Already-read this session" short-circuit | | codetree_read | focus_symbol | — | Return only the named function / class body + context | | codetree_search | file_pattern | — | Narrow candidate pool before the scan cap | | codetree_structure | format='text' | 'json' | Compact indented tree |


CLI Commands

codetree init       # Configure CodeTree + Claude + Cursor + Antigravity + Codex in every git repo under cwd
codetree status     # Per-project: running? indexed file count? ready?
codetree stats      # Aggregated cache hit rates + estimated tokens / cost saved
codetree reindex    # Drop .codetree/index.db (rebuilds on next session)
codetree doctor     # Verify MCP paths, hook scripts, IPC port (run after Node/npm changes)
codetree help       # Show help

codetree init discovers all .git directories under the current working directory and configures each one independently.


Configuration

Edit .codetreerc.json in your project root (a default is created by codetree init):

{
  "projectRoot": ".",
  "ignore": [".git", "node_modules", "dist", "build", "coverage", ".next", "__pycache__", ".cache", ".turbo", ".vercel", ".output"],
  "ignoreBinary": true,
  "maxFileSize": 1048576,
  "cache": {
    "memoryLimitMB": 256,
    "dbPath": ".codetree/index.db",
    "contentCacheMaxMB": 512
  },
  "ipc": { "port": 0, "host": "127.0.0.1" },
  "watch": { "enabled": true, "debounceMs": 300, "usePolling": false },
  "symbols": {
    "enabled": true,
    "languages": ["javascript", "typescript", "python", "java", "go", "rust", "ruby", "csharp"]
  },
  "telemetry": { "enabled": true, "statsFile": ".codetree/stats.json" },
  "tokenSave": {
    "read": {
      "includeSymbolsByDefault": true,
      "maxSymbols": 40,
      "exportedSymbolsOnlyByDefault": true,
      "unchangedShortCircuit": true,
      "outlineFallbackBytes": 81920
    },
    "search":       { "defaultLimit": 20, "snippetMaxChars": 120 },
    "structure":    { "compactText": false },
    "sessionStart": { "maxBytes": 2048 }
  }
}

The schema is enforced via zod in src/config.ts — invalid values fall back to defaults rather than crashing the server.


Repository Layout

codetree/
├── src/
│   ├── cli.ts                       # `codetree` CLI entry point
│   ├── config.ts                    # zod schema + project-root discovery
│   ├── doctor.ts                    # `codetree doctor` checks
│   ├── diff.ts                      # compact diff format for codetree_read
│   ├── index.ts                     # programmatic API exports
│   ├── utils.ts                     # findGitRepos, findIpcPort, formatNumber
│   │
│   ├── server/
│   │   ├── mcp-server.ts            # MCP stdio entry; lifecycle + shutdown
│   │   ├── ipc.ts                   # HTTP IPC server (singleton per project)
│   │   └── tools/
│   │       ├── codetree-read.ts
│   │       ├── codetree-outline.ts
│   │       ├── codetree-probe.ts
│   │       ├── codetree-search.ts
│   │       ├── codetree-find-refs.ts
│   │       ├── codetree-structure.ts
│   │       ├── codetree-summary.ts
│   │       ├── codetree-memory.ts
│   │       ├── codetree-edit.ts
│   │       └── codetree-write.ts
│   │
│   ├── indexer/
│   │   ├── indexer.ts               # the orchestrator
│   │   ├── watcher.ts               # chokidar + .git/HEAD + safety-net rescan
│   │   ├── hasher.ts                # xxhash content + quick (size,mtime) hash
│   │   ├── ignore.ts                # gitignore-compatible ignore filter
│   │   ├── extractor-registry.ts    # routes file → language extractor
│   │   └── extractors/              # JS/TS, Python, Java, Go, Rust, Ruby, C#, generic
│   │
│   ├── storage/
│   │   ├── database.ts              # sql.js wrapper + schema + migrations
│   │   ├── cache.ts                 # in-memory LRU
│   │   └── disk-manager.ts          # disk-budget management
│   │
│   ├── hook/
│   │   ├── pre-tool-use.ts          # bundled standalone (esbuild)
│   │   ├── post-tool-use.ts
│   │   ├── session-start.ts
│   │   ├── pre-compact.ts
│   │   ├── post-compact.ts
│   │   └── hook-client.ts           # tiny HTTP client → IPC server
│   │
│   └── setup/
│       ├── install.ts               # all install* functions used by `codetree init`
│       └── template-load.ts         # reads templates/ and copies into project
│
├── templates/                       # bundled with npm package; copied by init
│   ├── claude-md-codetree.snippet.md
│   ├── claude-rules-codetree.md
│   ├── cursor-codetree.mdc
│   ├── agents-codetree.snippet.md
│   ├── gemini-codetree.snippet.md
│   └── README.md
│
├── vscode-extension/                # standalone published extension
│   ├── src/
│   │   ├── extension.ts             # activation, commands, MCP mirror
│   │   ├── dashboard.ts             # webview dashboard (live token savings)
│   │   └── tree-views.ts            # sidebar trees (stats / files / symbols)
│   ├── media/                       # icons
│   └── package.json                 # publisher: rishuni30
│
├── scripts/
│   ├── bundle-hook.js               # esbuild bundle for hook/*.ts
│   └── postinstall.js
│
├── docs/
│   ├── INSTALL_PATH_AND_IGNORE_ISSUES.md
│   └── INTEGRATION_CURSOR_ANTIGRAVITY_CODEX.md
│
├── test/
│   ├── diff.test.ts
│   ├── extractors.test.ts
│   ├── utils.test.ts
│   └── integration.mjs              # end-to-end against a live server
│
├── dist/                            # build output (gitignored — but shipped on npm)
├── .codetree/                       # local index DB + stats (gitignored)
├── .codetreerc.json                 # project config
├── .codetreerc.default.json         # template default
├── .mcp.json                        # Claude Code MCP entry for THIS repo
├── .gitignore                       # node_modules/, dist/, .codetree/, *.tsbuildinfo
├── package.json                     # name: codetree-claude
├── tsconfig.json
├── CHANGELOG.md
├── LICENSE                          # MIT
└── README.md                        # this file

How codetree init Wires Each IDE

| IDE | MCP config | Rules / instructions | |-----|------------|----------------------| | Claude Code | Root .mcp.json | CLAUDE.md + .claude/rules/codetree.md + hooks in .claude/settings.json | | Cursor | .cursor/mcp.json | .cursor/rules/codetree.mdc (alwaysApply) | | OpenAI Codex | .codex/config.toml ([mcp_servers.codetree]) | AGENTS.md (also: trust the project in Codex if required) | | Google Antigravity | .antigravity/mcp.json | AGENTS.md (full table) + GEMINI.md (Gemini pointer) |

All written files are safe to commit (the team setup) except .codetree/ itself which is gitignored. Re-running codetree init only refreshes the CodeTree-managed blocks.


Reliability & Cross-Platform Notes

Never stale

  • External edits — periodic mtime revalidation on read; immediate re-index on mismatch
  • Branch switches.git/HEAD watcher invalidates relevant cache
  • Missed watcher events — safety-net rescan every 10 min (1 min after startup)

Cross-platform

  • Windows \r\ncodetree_edit normalizes for matching, preserves style on write
  • Paths — forward slashes in MCP JSON for portability across OSs
  • ShutdownSIGINT/SIGTERM/SIGHUP + transport.onclose + stdin.end/stdin.close (Windows doesn't reliably deliver SIGTERM to Node child processes)

Safe at scale

  • Large filesoutlineFallbackBytes (default 80 KB) auto-degrades to outline mode rather than truncating mid-byte; per-call slice capped at 5000 lines
  • Large repos — structure view paginates via next_cursor; auto-collapses on huge trees
  • Hooks (Claude) — redirect only when CodeTree can serve; otherwise native tools run
  • Graceful degradation — non-critical failures wrapped so core reads do not break
  • Single owner — duplicate processes detect via deterministic IPC port and exit cleanly to avoid SQLite write-lock contention

Telemetry

Per-tool counters available on IPC /stats:

readHits / readMisses          searchHits / searchMisses          globHits / globMisses
readTokensSaved                 searchTokensSaved                   globTokensSaved
sessionTokensSaved              mcpTokensSaved                      mcpCalls
scanCacheHits / scanCacheMisses scanHitRate                         scanDiskReadBytes
hitRate (= cacheHits / (cacheHits + cacheMisses))                   avgTokensPerHit

A persistently low scanHitRate on a large repo is a clear signal that cache.contentCacheMaxMB is too small.


Development

Prerequisites

  • Node.js ≥ 20
  • npm (or pnpm / yarn — npm is what CI uses)

Setup

git clone <your-repo-url> codetree
cd codetree
npm install
npm run build

npm run build runs tsc and then scripts/bundle-hook.js (esbuild) to produce standalone bundles for dist/hook/*.js.

Useful scripts

| Script | What it does | |--------|--------------| | npm run build | Full build: TypeScript compile + hook bundling | | npm run build:hook | Re-bundle hook scripts only | | npm run dev | tsc --watch | | npm run lint | tsc --noEmit (no separate ESLint dependency) | | npm test | Vitest run | | npm run test:watch | Vitest watch mode | | npm start | Run the MCP server directly (node dist/server/mcp-server.js) |

Local install for testing

npm pack
npm install -g ./codetree-claude-*.tgz
cd /path/to/test-project
codetree init
codetree doctor

Testing

Unit tests (Vitest)

npm test

Covers:

  • test/diff.test.ts — diff formatter
  • test/extractors.test.ts — symbol + import extraction per language
  • test/utils.test.ts — utility helpers

Integration tests

node test/integration.mjs

Spins up a real MCP server against a test fixture and asserts:

  • /stats shape and arithmetic invariants (cacheHits == readHits + searchHits + globHits)
  • Phantom-hit regression (a /check against a path with no DB record correctly counts as a miss)
  • /check-search and /check-glob token-saving credits
  • Cold-cache disk fallback for multi-word queries
  • scanStats reachability
  • File-pattern narrowing on probe and content search

Contributing

  1. Fork and create a feature branch off main.
  2. Install dependencies (npm install) and build (npm run build).
  3. Add tests under test/ for any behavior change.
  4. Run npm run lint && npm test && node test/integration.mjs.
  5. Update CHANGELOG.md under a new ## [x.y.z] - YYYY-MM-DD entry.
  6. Open a PR with a clear description of the user-visible change and a reference to the symptom you observed (CHANGELOG entries on this project lead with the symptom — see CHANGELOG.md for examples).

Coding conventions

  • TypeScript strict mode; no any casts in committed code
  • Forward-slash paths in any string written to disk
  • Tool handlers are pure functions of (config, indexer, db) — easy to unit-test
  • Failures in non-critical paths are wrapped (try { … } catch { /* non-critical */ }) so a corrupted index row never breaks the whole server

License

MIT © CodeTree contributors


Acknowledgements

Built on top of: