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

arcscope

v0.2.0

Published

Fully-local, architecture-aware code-navigation MCP server. tree-sitter breadth + a repo-declared architecture vocabulary answered live.

Readme

arcscope

A fully-local MCP server that gives an AI coding agent precise views of an unfamiliar codebase — fast symbol navigation, a compiler-exact call graph and flow surface, and a repo-declared architecture vocabulary answered live against current code — so it stops re-deriving structure with grep, and stops missing the this.service.foo() calls grep can't see.

Status: 0.1.0. Three tiers — tree-sitter breadth, an agent-authored knowledge layer, and a compiler-exact TypeScript precise tier — work end-to-end. TS / JS / TSX.

npm i -D arcscope
npx arcscope init        # index once, write MCP config, update .gitignore
# reload Cursor (Settings → MCP) or restart Claude Code

init writes the same offline node … serve entry to .cursor/mcp.json (Cursor) and .mcp.json (Claude Code). When arcscope is installed under node_modules, the path is project-relative so you can commit .cursor/mcp.json for the team.

Everything runs on your machine: no network at query time or at server spawn, no telemetry, no embeddings. Breadth comes from tree-sitter (WASM grammars bundled offline); precision comes from the TypeScript compiler running locally. Every result carries a precision tier so the agent never mistakes a heuristic for a compiler-accurate answer.

How it's being used

npx arcscope stats

One local command — no network, no telemetry — that shows both halves:

  • How much — reads .arcscope/usage.jsonl (one line per tool call, written as the server runs): totals, a breakdown by tool, and the most-queried symbols/concepts/entry points, plus your committed concepts and their drift baselines.

  • Is it useful (vs grep) — the server only sees its own calls, so stats also reads the newest Claude Code session transcript for this repo, replays every search/navigation call in order (arcscope ✅ vs grep 🔎 vs ToolSearch 🔍), and reports arcscope's share of arcscope + grep. No transcript yet → it says so and shows the usage half only.

    Reads Claude Code transcripts only (~/.claude/projects); Cursor sessions aren't included. The share is a whole-session volume ratio — a quick "is the agent reaching for it?" gut check, not a formal adoption gate.

Tools

| tool | answers | | --- | --- | | find_def | where a symbol is defined, with its signature | | find_refs | who references it — compiler-exact for methods when a tsconfig governs the file (member access obj.method() resolved); import-resolved otherwise | | dep_graph | the file/module dependency graph: hubs, a file's neighborhood, or circular dependencies | | call_graph | the method-resolved outgoing call graph from a function — follows this.x.foo() through the type checker | | flow | the complete surface of a flow before you change it: the call closure + a structural edge-case checklist | | arch_list | the repo's named architecture concepts (committed + agent-asserted) | | arch_query | resolve one concept to its live code locations, with drift + conformance | | arch_assert | record a concept — or a reviewed flow — so a later session inherits it, re-verified live | | arch_candidates | find a concept's likely missing members by structural (AST-shape) similarity |

The precise tier — compiler-exact, still local

tree-sitter can't tell you who calls this.documentService.clone() — resolving a method call needs the receiver's type. arcscope's precise tier runs the TypeScript compiler + language service locally (no network) to answer that exactly:

  • find_refs on a method finds its member-access call sites (obj.method()), resolved through the type checker — the call sites grep and import-resolution miss.
  • call_graph traces the outgoing closure from an entry point with method dispatch resolved to the concrete implementation (DI-injected services, inheritance).
  • flow maps the complete surface of a flow before you touch it: every function it transitively calls, annotated with each function's edge cases (branches, error handling, async). So you catch every case a change must handle.
flow cloneUser
# Flow surface from `cloneUser` (apps/.../clone-user.service.ts:44) — 38 functions, precision tier: typescript:
# cloneUser  apps/.../clone-user.service.ts:44  (+5 lib)  {2 branch}
# ├─ loadRecord  apps/.../record.repository.ts:183  (+2 lib)  {2 branch, 3 await}
# │  └─ …
# └─ performClone  apps/.../clone-user.service.ts:62  (+3 lib)  {1 err, 1 await}
#    └─ cloneRecord  libs/.../record-clone.ts:32  (+1 lib)
#       └─ cloneItem  libs/.../record-clone.ts:104
#          └─ reindexAfterClone  libs/.../reindex.ts:41
# … (38 functions; tree abbreviated)
# Edge-case surface: 6 decision points (if/switch/ternary) · 1 error-handling site (try/throw) · 7 async boundaries (await).
# Each {…} tag marks where behaviour forks, fails, or awaits — verify your change handles each before you write it.

The architecture vocabulary — the differentiator

Where other tools keep project knowledge as static prose that silently rots, arcscope binds each named concept to an executable locator recomputed on every query. The knowledge is agent-authored, not hand-edited: as the agent works out a concept, it records it with arch_assert into a committed .arcscope/assertions.yaml — a binding of locators, never a frozen list — so a later session inherits it. One concept looks like:

concepts:
  repository-tokens:
    title: Repository-token pattern (I{Name}Repository)
    locators:
      - { kind: symbol, query: "interface I*Repository", in: "libs/data-access/**" }
      - { kind: symbol, query: "const *_REPOSITORY = InjectionToken", in: "libs/**/tokens/**" }
      - { kind: path,   glob: "apps/**/firestore-*.repository.ts" }

arch_query repository-tokens resolves this against the current tree and flags drift when the resolved set diverges from its accepted baseline. Locators come in three kinds — symbol (a tree-sitter query), path (a glob), and import (every file importing a module specifier) — and resolve through arcscope's own engine; a committed assertion can never run a shell command.

Three things keep an agent-written assertion honest:

  • a must invariant — a rule every member must satisfy, re-checked live (conformance); a violation surfaces on every query, not when it ships.
  • arch_candidates — finds the members a binding missed, by AST-shape similarity (name-independent, so it catches a hand-copied re-implementation that shares no name or import). The "fixed it twice" antidote.
  • a flow conceptarch_assert a reviewed flow by its entry point; arch_query recomputes the whole flow live (precise tier) and drifts when a function enters or leaves it.

Nothing is stored as a bare fact: every assertion is re-verified against live code on read, so it can't silently rot.

Drift in practice

The first arch_query records a baseline; later queries compare against it:

arch_query repository-tokens
# Concept `repository-tokens` — Repository-token pattern (7 locations, fresh (baseline captured)):
#  … later, someone adds apps/audit/firestore-audit.repository.ts …
arch_query repository-tokens
# Concept `repository-tokens` — Repository-token pattern (8 locations, DRIFTED):
#   ⚠ DRIFT vs baseline: 1 added, 0 removed, 0 changed.
#     + apps/audit/firestore-audit.repository.ts
arch_query repository-tokens reaccept:true     # accept the new shape → fresh again

How it works

One local Node process speaking MCP over stdio, in tiers:

  • Engine (tree-sitter) — web-tree-sitter parses each file (lazy WASM grammars) into symbols + import edges. The always-on breadth substrate.
  • Graph — a derived view over those import edges (dependency graph, cycles), grouped by directory + import-clustering — never a build tool's project model (nx.json, BUILD files).
  • Knowledge — the live, agent-authored architecture vocabulary above.
  • Precise tier (TypeScript) — a local ts.Program + language service, built lazily per tsconfig and cached, powering the call graph, flow surface, and compiler-exact method references.

Precision tiers & limits

Two tiers, labeled on every result:

  • tree-sitter — fast, broad (multi-language breadth), structural. The always-on substrate; complete for imported-symbol references.
  • typescript — compiler-exact, via the local TypeScript compiler + language service. Resolves method dispatch, DI, inheritance, overloads.

arcscope never presents a tree-sitter heuristic as compiler-exact. Honest residual limits (the precise tier counts these at the boundary, never hides them):

  • any-typed / higher-order callbacks and runtime-wired providers (InjectionToken, useFactory) may resolve to the declared member rather than the concrete impl.
  • the precise tier is per-tsconfig — a single flow rarely spans module systems, but cross-project closures aren't unioned. It builds a TS program on first use (seconds), cached after.
  • TS / JS / TSX only; module grouping is general-first (directory + import clustering), never a build tool's project model.