┌─────────────────────────────────────────────────────────────┐
│ │
│ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗ │
│ ██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝ │
│ ███████╗██║ ██║ ██║██████╔╝█████╗ │
│ ╚════██║██║ ██║ ██║██╔═══╝ ██╔══╝ │
│ ███████║╚██████╗╚██████╔╝██║ ███████╗ │
│ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ │
│ │
│ Code intelligence for LLM coding agents. │
│ Know before you touch. │
│ │
└─────────────────────────────────────────────────────────────┘
Table of contents
- What it does
- Supported languages
- Installation
- Quick start
- Commands
- Watch mode
- Workspaces
- How it works
- Configuration
- Agent integration
- Building from source
- Benchmark methodology
- Roadmap
- License
What it does
Scope builds a local code intelligence index for any codebase and exposes it through a CLI designed for LLM coding agents. Before an agent edits a function, it can run scope sketch PaymentService and get back the class structure, method signatures, caller counts, and dependency surface in approximately 180 tokens -- without reading the 6,000-token source file.
The index is built from tree-sitter AST parsing (fast, error-tolerant, no compiler required), stored in a SQLite dependency graph with FTS5 full-text search, and queried through commands that return structured, agent-readable output. Everything lives in a .scope/ directory in your project root. No server process, no Docker, no API key required.
Scope integrates with Claude Code, Cursor, Aider, and any other agent that can run a shell command. Install the code-navigation skill and agents use scope automatically.
$ scope sketch PaymentService
PaymentService class src/payments/service.ts:12-89
─────────────────────────────────────────────────────────────────────────────────────
deps: StripeClient, UserRepository, Logger, PaymentConfig
extends: BaseService
implements: IPaymentService
methods:
async processPayment (amount: Decimal, userId: string) → Promise<PaymentResult> [11 callers]
refundPayment (txId: string, reason?: string) → Promise<bool> [3 callers]
private validateCard (card: CardDetails) → ValidationResult [internal]
getTransaction (id: string) → Transaction | null [2 callers]
fields:
private readonly client : StripeClient
private repo : UserRepository
private logger : Logger
// ~180 tokens · source file is 6,200 tokens
Supported languages
Production-ready
All six languages have full support: tree-sitter grammar integration, symbol extraction, edge detection (calls, imports, extends, implements), and enriched metadata. C# includes partial class merging; Python includes decorator and docstring extraction; Rust includes visibility modifiers; Go includes receiver metadata; Java includes annotations and access modifiers. TypeScript, C#, Java, and Rust also extract enum variants as a dedicated variant symbol kind with parent linking.
Planned
Language support means: tree-sitter grammar integrated, symbol extraction tested, and edge detection (calls, imports, extends, implements) working correctly for that language's idioms.
Installation
curl (Linux and macOS)
|
cargo
After installation, verify with:
# scope 0.9.0
Windows PowerShell note: The binary is named
scope-- no conflicts with PowerShell aliases.
Quick start
1. Initialise
Run once from your project root. Detects languages and writes a default .scope/config.toml.
Initialised .scope/ for project: api
Detected languages: TypeScript
Run 'scope index' to build the index.
2. Build the index
First run indexes the full codebase. Subsequent runs are incremental -- only changed files are re-indexed.
Indexing 847 files...
TypeScript 612 files 4,821 symbols
C# 235 files 1,943 symbols
Built in 12.4s. Index size: 8.2MB
3. Explore the codebase
Start with the high-level overview, then drill down.
4. Keep the index fresh
Line numbers in Scope output reflect the last scope index run. If you've edited files since then, re-index before querying:
scope index --watch monitors your project for file changes and re-indexes automatically with a 300ms debounce. Run it in a terminal tab during development -- agents never see stale line numbers.
5. Install the agent skill
Follow the agent integration steps to install the skill and CLAUDE.md snippet. Agents will use scope automatically.
Commands
| Command | Signature | Description | When to use |
|---|---|---|---|
scope init |
[--json] |
Initialise Scope for a project. Creates .scope/ with default config, auto-detects languages. |
Once per project, before first scope index. |
scope index |
[--full] [--watch] [--json] |
Build or refresh the code index. Incremental by default, --full forces rebuild, --watch auto re-indexes on file changes. |
Once on setup, then --watch during development or manual scope index after edits. |
scope map |
[--limit N] [--json] |
Full repository overview: entry points, core symbols ranked by caller count, architecture summary. ~500-1000 tokens. | First thing in a new codebase. Replaces 5-17 sketch calls for orientation. |
scope entrypoints |
[--json] |
Lists API controllers, workers, and event handlers grouped by type. Symbols with zero incoming call edges. | Understanding the request flow starting points. |
scope sketch |
<symbol> [--json] |
Compressed structural overview: methods with caller counts, dependencies, type signatures, modifiers. ~200 tokens vs ~4,000 for full source. | Before reading source or editing any non-trivial symbol. |
scope refs |
<symbol> [--kind calls|imports|extends] [--limit N] [--json] |
All references grouped by kind: call sites, imports, type annotations. Includes source line snippets. | Before changing a function signature or deleting a symbol. |
scope callers |
<symbol> [--depth N] [--context N] [--json] |
Direct callers (depth 1) or transitive callers (depth 2+). Depth 1 shows snippets; depth 2+ groups by level with test file separation. | Before any refactor that changes a public API surface. |
scope deps |
<symbol> [--depth 1-3] [--json] |
What does this symbol depend on? Direct imports, calls, extended classes. Transitive with --depth. |
Understanding prerequisites before implementing something new. |
scope rdeps |
<symbol> [--depth 1-3] [--json] |
What depends on this symbol? Reverse dependency traversal. | Before deleting or renaming a symbol. |
scope impact |
<symbol> [--depth 1-5] [--json] |
Deprecated -- delegates to scope callers --depth N. Blast radius analysis. |
Use scope callers --depth N instead. |
scope trace |
<symbol> [--limit N] [--json] |
Trace call paths from entry points to a symbol. Shows how API endpoints and workers reach a function. | Understanding how a bug is triggered or what code paths exercise a function. |
scope flow |
<start> <end> [--depth N] [--limit N] [--json] |
Find call paths between any two symbols. Unlike trace (entry points to target), this traces forward from start to end through the call graph. |
Understanding how two arbitrary symbols are connected. |
scope find |
"<query>" [--kind function|class] [--limit N] [--json] |
Full-text search with BM25 ranking, importance-boosted results. CamelCase and snake_case aware. | Navigating an unfamiliar codebase or finding code by intent. |
scope similar |
<symbol> [--kind function|class] [--json] |
Stub -- find structurally similar symbols. Not yet implemented. | Future: discovering existing implementations. |
scope source |
<symbol> [--json] |
Stub -- fetch full source of a symbol. Not yet implemented. | Future: reading implementation after scope sketch. |
scope status |
[--json] |
Index health: symbol count, file count, last indexed time, stale files. | Checking whether the index is stale before making range-based edits. |
scope workspace init |
[--name NAME] |
Discover projects with .scope/ in subdirectories and create scope-workspace.toml. |
Once per workspace, after running scope init in each project. |
scope workspace list |
[--json] |
Show all workspace members with index status, symbol counts, and freshness. | Checking workspace health before cross-project queries. |
scope workspace index |
[--full] [--watch] [--json] |
Index all workspace members. With --watch, starts a file watcher per member. |
Initial setup, batch refresh, or continuous watching of all projects. |
Global flags
| Flag | Description |
|---|---|
--workspace |
Query across all workspace members. Requires scope-workspace.toml. Works with: status, map, refs, find, entrypoints. |
--project <name> |
Target a specific workspace member by name. Overrides CWD-based project detection. |
--verbose |
Enable debug output to stderr. |
--json |
Output structured JSON instead of human-readable text. Supported on all commands. |
All commands support --json for structured output. Line numbers reflect the state of the index at last run -- use scope status to check freshness before range-based edits.
Watch mode
scope index --watch monitors your project for file changes and automatically re-indexes when source files are modified. It's designed to run in a background terminal tab during development so the index is always fresh.
Initial index: 0.8s. 4,821 symbols, 12,456 edges.
Watching for changes... (Ctrl+C to stop)
Re-indexed 2 files (34ms) — 2 symbols updated
Re-indexed 1 file (12ms) — 0 symbols updated
How it works
- Uses the
notifycrate for cross-platform file system events (inotify on Linux, FSEvents on macOS, ReadDirectoryChangesW on Windows) - Debounces rapid changes with a 300ms window -- saving 5 files in quick succession triggers one re-index, not five
- Respects
.gitignoreandconfig.index.ignorepatterns --node_modules/,dist/, etc. are never watched - Only reacts to files with supported extensions (
.ts,.tsx,.cs, etc.) - A lock file (
.scope/.watch.lock) prevents multiple watchers on the same project
NDJSON output
For programmatic consumers, --watch --json emits newline-delimited JSON to stdout:
Concurrent access
Watch mode writes to graph.db on each re-index. Other scope commands (sketch, refs, map, etc.) can read concurrently thanks to SQLite WAL mode and a 5-second busy timeout. You don't need to stop the watcher to query.
Workspaces
Workspaces let you query across multiple Scope projects as a single unit. This is useful for monorepos, multi-repo setups, and polyglot projects where different parts of the codebase live in separate directories.
The model
Each project keeps its own independent .scope/ index. A scope-workspace.toml manifest at the workspace root ties them together. When you pass --workspace to a command, Scope opens all member databases and fans out the query, merging results with project labels.
~/repos/
scope-workspace.toml ← workspace manifest
api-gateway/
.scope/ ← Go index
src/
user-service/
.scope/ ← Rust index
src/
web-app/
.scope/ ← TypeScript index
src/
Key properties:
- Workspace is opt-in -- single-project behavior is unchanged without
--workspace - Each project index is independent -- you can build, refresh, and query them separately
- Cross-project queries merge results from all members with project-name labels
- No cross-project edge detection -- Scope doesn't know that your TypeScript frontend calls your Go backend. Each project's call graph is self-contained.
Setup
# 1. Initialise and index each project individually
&& &&
&& &&
&& &&
# 2. Create the workspace manifest from the parent directory
Found 3 projects:
api-gateway (go)
user-service (rust)
web-app (typescript)
Wrote scope-workspace.toml
Alternatively, index all members at once after creating the manifest:
Manifest format
scope-workspace.toml is a simple TOML file:
[]
= "my-platform"
[[]]
= "api-gateway"
[[]]
= "user-service"
[[]]
= "web-app"
= "frontend" # optional -- defaults to directory name
You can edit this file manually to add or remove members, rename projects, or reorder entries.
Querying across projects
Add --workspace to any supported command:
# Overview of the entire workspace
# Find who calls PaymentService across all projects
# Search for authentication code everywhere
# List all entry points across all projects
# Check health of all member indexes
Results are tagged with project names so you can tell which project each symbol belongs to:
PaymentService (api-gateway) class src/payments/service.go:12-89
PaymentService (web-app) class src/types/payment.ts:5-22
Targeting a specific member
Use --project <name> to query a specific workspace member without cd-ing into it:
Watch mode with workspaces
Watch all workspace members with a single command:
[api-gateway] Watcher started (PID 12345)
[user-service] Watcher started (PID 12346)
[web-app] Watcher started (PID 12347)
Watching 3 members (Ctrl+C to stop all)...
This spawns one scope index --watch process per member. Each watcher is independent — a file change in web-app/ only re-indexes that project. Press Ctrl+C to stop all watchers.
You can also watch individual projects manually:
&&
Limitations
- No cross-project edges. Scope doesn't detect that
web-appcallsapi-gatewayvia HTTP. Each project's dependency graph is self-contained. Cross-project references are a planned future feature. - Commands that need source access (
sketch,deps,trace,callers) work on one project at a time. Use--project <name>to target a member, orcdinto the project directory. - Nested projects are detected. If project A contains project B's directory, the file walker skips B's files to avoid double-indexing. Each project only indexes its own source tree.
How it works
Your codebase
|
v
+-----------------------------+
| tree-sitter parser | Fast, incremental, error-tolerant AST parsing.
| (TypeScript, C#, ...) | No compiler required. Extracts symbols, types,
+--------------+--------------+ modifiers, docstrings, line ranges.
|
+-------+--------+
v v
+----------+ +--------------+
| SQLite | | SQLite FTS5 | Two complementary indexes:
| graph | | search | SQLite for structural relationships (who calls
| | | | what, inheritance chains, import graphs).
| symbols | | BM25-ranked | FTS5 for full-text search by intent -- finds
| + edges | | symbol text | symbols by what they do, not what they're named.
+----------+ +--------------+ Both embedded on disk -- no server.
| |
+-------+--------+
v
+-----------------------------+
| scope query engine | Combines structural traversal and text search.
| | Returns labelled, token-efficient output designed
+-----------------------------+ for LLM consumption, not human readability.
Parsing -- tree-sitter produces a concrete syntax tree for every file. Scope extracts symbols (functions, classes, methods, interfaces, enums, enum variants, types) with their signatures, type annotations, access modifiers, async status, and docstrings. For C#, partial classes are merged across files before indexing.
Structural graph -- symbols are nodes in a SQLite database. Edges represent relationships: calls, imports, extends, implements, instantiates, references_type. Impact analysis uses recursive common table expressions to traverse this graph to arbitrary depth.
Full-text search -- symbol names (with CamelCase splitting), signatures, docstrings, caller/callee names, and file path components are indexed in an FTS5 virtual table with porter stemming. Symbols with more callers rank higher via importance-tier boosting. scope find "payment" matches processPayment, PaymentService, and any symbol with "payment" in its docstring. Scores are normalized to 0.00-1.00 and sorted by BM25 relevance.
Incremental indexing -- each file's SHA-256 hash is stored alongside its symbols. On re-index, only files whose hash has changed are re-parsed. A single changed file re-indexes in under one second.
Configuration
Scope reads .scope/config.toml in the project root. This file is created by scope init and is safe to commit to version control.
[]
= "api"
= ["typescript", "csharp"]
[]
# Patterns to exclude from indexing (respects .gitignore by default)
= [
"node_modules",
"dist",
"build",
".git",
"migrations/",
]
# Include test files in refs and impact output
= true
# Vendor code patterns (auto-configured by scope init)
# Files matching these patterns are de-ranked in find and refs results
= ["node_modules/", "vendor/", "third_party/"]
[]
# "local" uses SQLite FTS5 -- no API key, works offline
= "local"
[]
# Truncate long reference lists (use --limit to override per command)
= 20
# Maximum depth for impact traversal (use --depth to override)
= 3
Agent integration
Scope ships two files that teach LLM agents how to use it:
| File | Purpose | Where it goes |
|---|---|---|
skills/code-navigation/SKILL.md |
The skill — decision trees, command reference, optimal workflows from 54 benchmarks, anti-patterns, the 3-command rule. This is where all the detail lives. | .claude/skills/code-navigation/SKILL.md |
docs/CLAUDE.md.snippet |
The pointer — 7 lines that tell agents scope exists and that subagents must be given the skill. Keeps CLAUDE.md clean. | Append to your project's CLAUDE.md |
Setup
# 1. Copy the skill file
# 2. Append the snippet to CLAUDE.md
# 3. Allow scope commands (prevents permission prompts in subagents)
# Add to .claude/settings.local.json:
# { "permissions": { "allow": ["Bash(scope:*)"] } }
How it works
- Main session reads
CLAUDE.mdat startup, sees scope is available, and auto-discovers the skill via.claude/skills/. The skill's description triggers on any code navigation task. - Subagents don't auto-discover skills. The CLAUDE.md snippet instructs the main session: "when dispatching subagents that need code navigation, tell them to read
.claude/skills/code-navigation/SKILL.md." The subagent reads the file and follows the scope workflows. Bash(scope:*)permission ensures scope commands execute without prompts — critical for subagents which can't approve permissions interactively.
What the CLAUDE.md snippet contains
This project has Scope CLI installed (.scope/ index).
Run `scope status` to check availability. Run `scope map` for a repo overview.
When dispatching subagents that need to navigate, search, or understand code,
include the `code-navigation` skill or instruct them to read
`.claude/skills/code-navigation/SKILL.md` before starting.
That's it. No command lists, no workflows — all of that lives in the skill file.
What the skill file teaches agents
- Check
scope statusbefore navigating - Use
scope sketchinstead of reading full files (~200 tokens vs ~4,000) - Use
scope callers/scope refsinstead of grep for finding references - Use
scope mapfor repo orientation instead of reading 10+ files - Follow task-specific workflows (discovery, bug fix, refactor, new feature)
- The 3-command rule: if you've run 3 scope commands without editing, start editing
See skills/README.md for more details. The snippet also works with Cursor, Aider, and any agent that reads project instructions.
Building from source
Prerequisites: Rust 1.75 or later (rustup update stable)
# Binary at target/release/scope
Run the test suite:
Benchmark methodology
Scope ships with a benchmark harness (scope-benchmark v0.6.1) in benchmarks/runner/ that measures whether it actually reduces token consumption. The harness runs real coding tasks using a 3-arm experiment design, comparing three conditions:
- without-scope -- agent works without Scope CLI (tools disallowed)
- with-scope -- agent has Scope CLI available
- with-scope-preloaded -- agent has Scope CLI available AND
scope mapoutput baked into CLAUDE.md
Three metrics are measured simultaneously:
- Input token consumption across conditions
- Task correctness (compilation + tests + caller coverage)
- Navigation efficiency (file reads per task)
12 tasks across 6 categories (discovery, bug fix, refactoring, new feature, focused exploration, cross-cutting changes), for both TypeScript and C# fixtures with known dependency graphs. Each task runs 3 reps per condition for statistical reliability.
# Build the benchmark runner
# Validate a single task across all 3 conditions before committing to a full run
# Full 3-arm comparison -- all tasks, 3 reps each
# Manual workflow: prepare work directories, then run tasks manually
# Import results from manual runs
# Generate a report from existing results
Prerequisites: Claude Code CLI installed, ANTHROPIC_API_KEY set, scope on PATH, .NET SDK (for C# fixtures), Node.js (for TypeScript fixtures).
Results are committed per release in benchmarks/results/vX.Y.Z/. See benchmarks/README.md for full documentation.
Roadmap
v0.1.0 -- v0.9.0 (current)
- TypeScript and C# symbol extraction with edge detection
- SQLite dependency graph with recursive impact traversal
- Full-text search with FTS5, BM25 ranking, and importance-tier boosting
- 16 commands:
init,index,sketch,refs,callers,deps,rdeps,impact,find,trace,flow,entrypoints,map,status,similar(stub),source(stub) -
scope index --watch-- auto re-index on file changes with notify crate - Multi-project workspaces --
scope workspace init/list/index,--workspaceflag on 5 commands,--project <name>targeting, workspace-level--watch -
WorkspaceGraphfederated query facade with symbol ID namespacing -
LanguagePlugintrait for pluggable language support (parser refactor) - Python language support -- decorator metadata, docstring extraction, access inference
- Rust language support -- structs, enums, traits, visibility modifiers, dogfooding
- Enriched output with method modifiers, CamelCase/snake_case-aware FTS5
-
--jsonoutput on all commands - Benchmark harness with 12 tasks, 3-arm experiment, correctness verification
- Go language support -- receiver metadata, export inference, struct embedding
- Java language support -- annotations, access modifiers, extends/implements, records
-
scope flow-- find call paths between any two arbitrary symbols - Enum variant extraction --
variantsymbol kind with parent linking (TS, C#, Java, Rust) - Match/switch arm edge detection for enum variant refs (Rust, Java, C#)
-
this/self/base/superedge capture for TypeScript, C#, and Java - Rust impl block association -- struct sketches now show methods and trait implementations
- Sketch enrichments -- Java annotations, Python decorators, Go receiver types on methods
- Generic name de-ranking and vendor code de-ranking in search results
- Query context specificity boost for mixed specific/generic searches
Next
-
scope similar,scope sourcecommands (currently stubs) - Vector embeddings via local ONNX model (replacing FTS5 for
scope find) - Cross-project edge detection via
scope link - MCP adapter (thin wrapper over the same binary)
Later
- Kotlin and Ruby language support
- Hosted team index sync
- CI/CD integration for impact analysis on PRs
License
MIT -- see LICENSE for the full text.