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

repository-intelligence-engine

v0.2.1

Published

> Turn any repository into a queryable **code knowledge graph** — then feed your AI agent *structure*, not a wall of text.

Readme

Repository Intelligence Engine (RIE)

Turn any repository into a queryable code knowledge graph — then feed your AI agent structure, not a wall of text.

CI npm license node

RIE reads a codebase and builds a semantic graph of it — files, modules, symbols, imports, calls, inheritance, packages — using a deterministic, compiler-inspired pipeline. No LLM is involved in building it. Everything else (AI context bundles, reports, MCP tools) is a plugin that reads from that graph.

Repository ──▶ RIE pipeline ──▶ Knowledge Graph ──┬──▶ AI context bundles
                                (SQLite)          ├──▶ MCP tools for agents
                                                  ├──▶ Reports & hub analysis
                                                  └──▶ Your own plugins

The graph is the product. AI is an output, not the engine.


Table of contents


Why this exists

Tools like repomix and gitingest flatten your repository into one enormous text blob and hand it to an LLM. That works until the repo is bigger than the context window — and it throws away every relationship in the code. The model gets text when what it needs is structure.

RIE builds the structure first, then answers the question "what does the agent actually need to see for this task?" by traversing the graph outward from relevant seed symbols, ranking by relevance, and pruning to a token budget.

Measured on this repository (rie benchmark . --for "incremental scanning"):

| Approach | Tokens | |---|---:| | Naive dump of all 161 parsed files | 158,148 | | RIE context bundle for the same question | 8,662 | | Reduction | 94.5% |

The bundle isn't a random 5% slice. It's the symbols that actually participate in incremental scanning, their signatures, their relationships to each other, and span-scoped excerpts of just the relevant lines.

Design properties that matter for agents:

  • Deterministic — same commit in, byte-identical graph out. Graph hashes are comparable across machines and CI runs.
  • No fabrication — if an import or call can't be resolved, RIE emits a diagnostic instead of inventing an edge. Unresolved edges are flagged resolved: false, and heuristic matches carry a confidence score.
  • Incremental by default — edit one file, RIE re-parses exactly that file. A content-addressed facts cache keeps rescans cheap enough to run from a git hook.
  • Offline — the whole pipeline, including context generation, runs with no network access.

Install

RIE ships as a set of scoped npm packages. Which one you want depends on how you plan to use it.

The CLI — rie (most people want this)

npm i -g @ri-engine/rie-cli

This is what gives you the rie command. Or run it without installing:

npx @ri-engine/rie-cli scan .

The library — build graphs from your own code

npm i @ri-engine/rie-core @ri-engine/rie-contracts @ri-engine/rie-graph-store-sqlite @ri-engine/rie-lang-typescript

@ri-engine/rie-core is the scan orchestrator. It depends only on contracts and takes the graph store and language analyzers as injected dependencies, so you install the store and languages you actually want. Add @ri-engine/rie-plugin-host for querying and @ri-engine/rie-lang-python for Python support. See Programmatic API.

Requirements

  • Node.js >= 22.13 — RIE uses the built-in node:sqlite module, which needs 22.13+ unflagged.
  • Node 24+ recommendednode:sqlite is still marked experimental below 24 and prints a warning.

Run rie doctor to check your environment:

  ✓ node-version — Node 22.22.0 (node:sqlite is experimental below 24; Node 24+ recommended)
  ✓ sqlite-fts5 — node:sqlite loads, FTS5 available
  ✓ graph-integrity — PRAGMA integrity_check: ok
  ✓ schema-version — graph schema 0.1.0
  ✓ stale-lock — no lock present

All checks passed.

Languages supported today: TypeScript (.ts .tsx .mts .cts), JavaScript (.js .jsx .mjs .cjs), Python (.py). Adding a language is adding a package that implements LanguageDescriptor — the core never changes.


Quickstart (60 seconds)

# 1. Build the graph. Writes .rie/graph.db — add .rie/ to your .gitignore.
rie scan .

# 2. See what it found.
rie graph stats .

# 3. Ask a structural question.
rie query 'callers of buildGraph'

# 4. Generate context for an AI task.
rie context --for "how does incremental scanning work" -o context.md

Step 1 on this repository prints:

rie scan: ok — 1855 nodes, 3838 edges (330 files, 0 parsed)

0 parsed means every file was served from the incremental cache. Run rie scan --force for a cold rebuild.


Using RIE for AI agent context

This is the primary use case: give your coding agent a real model of the codebase instead of a pile of files. There are three ways to wire it up, and they compose.

Option 1 — rie install (one command, done)

RIE ships a declarative installer for nine assistant platforms. It writes the instruction files, registers the MCP server, and installs agent hooks — all idempotent, all reversible.

rie install --list
  claude-code    tier 1  Claude Code
  cursor         tier 1  Cursor
  codex          tier 1  Codex
  antigravity    tier 1  Google Antigravity
  agents-md      tier 1  Universal AGENTS.md
  mcp            tier 1  MCP (any client)
  gemini-cli     tier 2  Gemini CLI
  windsurf       tier 2  Windsurf
  copilot-cli    tier 2  GitHub Copilot
# Preview exactly what would be written — nothing is touched
rie install --platform claude-code --dry-run

# Actually install (writes require explicit consent)
rie install --platform claude-code --yes

# Install every tier-1 platform
rie install --all --yes

# Detect drift in CI: RIE4001 missing / RIE4002 stale / RIE4003 tampered
rie install --check

Each platform descriptor declares its target files and an ownership mode:

| Mode | Meaning | |---|---| | rie-file | RIE owns the whole file (e.g. .claude/skills/rie/SKILL.md) | | marker-block | RIE owns a marked block inside your file (e.g. a section of CLAUDE.md) | | structured-merge | RIE merges keys into your JSON (e.g. .mcp.json, .claude/settings.json) |

rie uninstall reverses an install byte-identically — your content and any foreign settings entries come back exactly as they were. This is end-to-end tested, not aspirational.

For Claude Code specifically, installing writes a skill at .claude/skills/rie/SKILL.md, a marked block in CLAUDE.md, an MCP server entry in .mcp.json, and a PreToolUse hook in .claude/settings.json that steers the agent toward graph queries before it starts grepping.

Option 2 — MCP server (works with any MCP client)

rie serve --mcp

This starts a stdio MCP server over the persisted graph. It scans for freshness first, then watches the repo and live-refreshes on a 300 ms debounce, so the graph never goes stale while the agent is working. Use --no-watch to disable, --debounce <ms> to tune.

Register it with any MCP client:

{
  "mcpServers": {
    "rie": { "command": "rie", "args": ["serve", "--mcp"] }
  }
}

Six tools are exposed to the agent:

| Tool | What it does | |---|---| | query_graph | Run a bounded query expression (see Query language) | | get_node | Fetch one node by id, e.g. sym:src/auth.ts#AuthService:class | | get_neighbors | Edges + neighbor nodes around a node, optionally filtered by edge type | | shortest_path | BFS-shortest path between two nodes | | graph_stats | Node/edge counts by label and type, plus top hubs | | top_hubs | Highest-degree nodes — the "everything flows through these" list |

Every tool is bounded. There is no raw SQL surface, and no query can run away with your context window.

Option 3 — rie context (pipe a bundle into any prompt)

When you want a self-contained bundle to paste or pipe:

rie context --for "how does authentication work" -o context.md
# Seed from specific symbols or files instead of a natural-language question
rie context --focus AuthService --focus src/api/routes.ts

# Tune the budget and traversal depth
rie context --for "payment flow" --budget 4000 --depth 3

# Machine-readable output for your own tooling
rie context --for "payment flow" --format json

| Flag | Default | Meaning | |---|---|---| | --for <question> | — | Natural-language intent; seeds are matched from its terms | | --focus <ref> | — | Explicit seed (symbol name, qualified name, or file path). Repeatable | | --budget <n> | 8000 | Token budget for the bundle | | --depth <n> | 2 | Max expansion depth from the seeds | | --format <fmt> | markdown | markdown, xml, or json | | -o, --out <file> | stdout | Write to a file |

The bundle is structure-first: an overview, key symbols with real signatures, the relationships between them, then span-scoped source excerpts — in that order, because that's the order a model can use them in.

# RIE context: "how does incremental scanning work"

## Overview

- 54 key symbols, 39 relationships, 50 excerpts (budget: 8000 tokens)
- Expanded subgraph: 69 nodes, 102 edges

## Key symbols

- `incrementalDelta` (function) [packages/core/src/pipeline/diff.ts:90]
  `function incrementalDelta( next: GraphSnapshot, oldIds: { nodeIds: string[]; edgeIds: string[] }, unchangedFiles: ReadonlySet<string>, ): GraphDelta`
- `runScan` (function) [packages/core/src/orchestrator/scan.ts:130]
  `async function runScan(options: ScanOptions): Promise<ScanResult>`
- `FactsCache.open` (method) [packages/core/src/pipeline/cache.ts:53]
  `static async open(dir: string, versionKey: string): Promise<FactsCache>`
...

Bundles are byte-deterministic — same graph and same question produce the same bytes, which makes them cacheable and diffable.

Keeping the graph fresh

A stale graph is worse than no graph. Three mechanisms keep it current:

Git hooks — incremental rescan after every commit and checkout:

rie hook install

This adds a marker-delimited block to .git/hooks/post-commit and post-checkout. It is fail-open by contract: a hook failure never blocks your git operation. Your existing hooks survive install and uninstall untouched. Check status with rie hook status.

Automatic freshnesscontext, query, report, graph path, graph show, and serve all run an incremental scan before reading. Pass --no-scan to skip it when you know the graph is current.

File watchingrie serve --mcp watches the repository and rescans on change by default.

CI integration

rie scan . --fail-on warning   # exit code 3 if any warning-or-worse diagnostic
rie install --check            # exit non-zero if assistant integrations drifted

The graph model

Node labels

| Label | Represents | ID formula | |---|---|---| | Repository | The repo root | repo:<name> | | Directory | A directory | dir:<path> | | File | A file on disk | file:<path> | | Module | A language-resolved module | mod:<moduleId> | | Package | An npm/PyPI package or workspace member | pkg:<name>@<version> (external) · pkg:<name> (internal) | | Symbol | A declaration | sym:<moduleId>#<qualifiedName>:<kind>[:<n>] |

SymbolKind covers function, method, class, interface, type, typeAlias, enum, enumMember, variable, constant, field, property, parameter, namespace, module, constructor, getter, setter.

IDs come from a single derivation function (deriveNodeId) that every producer must call. That's what makes the graph stable across runs and safe to cache — and it structurally eliminates the "ghost node" bug class where two producers disagree on an id.

Edge types

| Category | Types | |---|---| | Structural | CONTAINS, DECLARES, MEMBER_OF | | Dependency | IMPORTS, EXPORTS, DEPENDS_ON | | Reference | CALLS, REFERENCES, INSTANTIATES, TYPED_AS | | Type hierarchy | EXTENDS, IMPLEMENTS, OVERRIDES |

Edge id formula: <TYPE>:<srcId>->:<dstId>[:<ordinal>]. The ordinal disambiguates repeated edges between the same endpoints (function overloads, repeated call sites).

Reference edges carry provenance: CALLS has a callSite span plus resolved and optional confidence; IMPORTS carries the raw specifier, an importKind (default, named, namespace, sideEffect, dynamic, typeOnly), and resolved.

What a node looks like

{
  "id": "sym:packages/core/src/orchestrator/scan.ts#runScan:function",
  "label": "Symbol",
  "kind": "function",
  "name": "runScan",
  "qname": "runScan",
  "file_id": "file:packages/core/src/orchestrator/scan.ts",
  "lang": "typescript",
  "start_line": 130,
  "end_line": 423,
  "props": {
    "visibility": "public",
    "exported": true,
    "signature": "async function runScan(options: ScanOptions): Promise<ScanResult>",
    "span": { "startLine": 130, "startCol": 8, "endLine": 423, "endCol": 2 }
  }
}

Resolution the graph actually performs

  • Relative and absolute imports, re-export chains, barrel files
  • tsconfig.json paths and baseUrl aliases, including per-directory tsconfigs
  • Bare imports → Package nodes (node builtins, workspace manifests, declared externals)
  • this.-qualified member calls, and a conservative unique-method fallback that carries a confidence score
  • Class inheritance and interface implementation across files
  • Python relative imports, inheritance, cross-file calls, and self. → receiver normalization

Edge accuracy is gated in CI at 100% precision and recall against a hand-labeled ground-truth fixture (fixtures/goldens/ts-small.expected-edges.json).


CLI reference

rie scan [path]         Scan a repository, build + persist its knowledge graph
rie context             Generate a structure-aware AI context bundle
rie query '<expr>'      Run a bounded graph query
rie report [path]       Deterministic repo summary: hubs, communities, entry points
rie graph stats [path]  Node/edge counts and top hubs
rie graph path <a> <b>  Shortest path between two nodes
rie graph show <ref>    One node in detail: fields + neighbors by edge type
rie serve --mcp [path]  Serve the graph over MCP stdio
rie plugins <sub>       List or run plugins (list | run <name>)
rie install             Install RIE into AI assistants
rie uninstall           Reverse an install (byte-identical restore)
rie hook <sub>          Git rescan hooks (install | uninstall | status)
rie config <sub>        Show or validate rie.config.json (show | validate)
rie doctor [--fix]      Check node version, sqlite, graph integrity, stale locks
rie benchmark [path]    Context-token reduction vs dumping all parsed files

Global options: -C, --cwd <dir> · --json · --no-scan · --version · --help

rie scan

Builds the graph and persists it to .rie/graph.db. Incremental by default.

| Flag | Meaning | |---|---| | --force | Cold rebuild — ignore the cache, still refresh it | | --no-cache | Neither read nor write the cache | | --stats | Print the graph hash and db path after scanning | | --json | Print the full RunReport as JSON | | --debug | Print every diagnostic verbatim, no grouping or suppression | | --fail-on <sev> | Exit 3 when diagnostics at or above <sev> exist (warning | error) |

A timestamped backup is taken before any destructive rebuild, and a single-writer lock prevents two scans from racing on the same .rie directory.

rie graph stats

Graph: 1855 nodes, 3838 edges (/path/to/repo/.rie/graph.db)

Nodes by label:
  Directory    85
  File         330
  Module       161
  Package      27
  Repository   1
  Symbol       1251

Edges by type:
  CALLS        413
  CONTAINS     576
  DECLARES     1251
  EXPORTS      294
  EXTENDS      2
  IMPLEMENTS   1
  IMPORTS      577
  INSTANTIATES 12
  MEMBER_OF    614
  REFERENCES   98

Top hubs (by degree):
    74  mod:packages/contracts/src/graph/graph-query.ts
    72  mod:packages/contracts/src/language/language.ts
    70  mod:packages/contracts/src/graph/node-types.ts

rie graph show

rie graph show buildGraph
sym:packages/core/src/pipeline/build.ts#buildGraph:function
  end_line: 349
  file_id: file:packages/core/src/pipeline/build.ts
  kind: function
  label: Symbol
  lang: typescript
  name: buildGraph
  qname: buildGraph
  start_line: 91

CALLS (in):
  sym:packages/core/src/orchestrator/scan.ts#runScan:function (function)

CALLS (out):
  sym:packages/core/src/pipeline/build.ts#ancestorDirs:function (function)
  sym:packages/core/src/pipeline/build.ts#assertUniqueIds:function (function)
  ...

References resolve loosely — you can pass a node id, a symbol name, a qualified name, or a module path.

rie graph path

rie graph path runScan buildGraph
sym:packages/core/src/orchestrator/scan.ts#runScan:function (function)
  --CALLS--> sym:packages/core/src/pipeline/build.ts#buildGraph:function (function)

rie report

A deterministic, golden-tested repository summary: overview counts, top hubs by degree, union-find module clusters, entry points, and runnable suggested queries.

rie report .                    # markdown to stdout
rie report . -o report.md       # to a file
rie report . --html -o report.html   # self-contained offline page

rie benchmark

Measures how much context RIE saves versus naively dumping every parsed file:

rie benchmark . --for "incremental scanning"
question: "incremental scanning"
naive context (161 parsed files, est.):  158,148 tokens
rie context bundle (est.):                 8,662 tokens
reduction:                                    94.5%

Query language

rie query and the MCP query_graph tool share one bounded DSL. There is deliberately no raw SQL surface — every form maps to a safe, limited traversal over graph primitives, capped at 100 results.

| Form | Example | |---|---| | callers of <symbol> [depth <n>] | rie query 'callers of buildGraph' | | callees of <symbol> [depth <n>] | rie query 'callees of buildGraph depth 2' | | importers of <module-path> | rie query 'importers of src/auth/service.ts' | | dependencies of <module-path> | rie query 'dependencies of src/app.ts' | | search <text> | rie query 'search AuthService' | | <label> where <field>=<value> [and ...] | rie query 'symbols where kind=class and lang=typescript' |

Labels: files, symbols, modules, packages, directories, repositories Filter fields: kind, name, lang, qname

Real output:

$ rie query 'callers of buildGraph'
runScan                    function     sym:packages/core/src/orchestrator/scan.ts#runScan:function

$ rie query 'symbols where kind=class'
UnknownToolError           class        sym:apps/cli/src/mcp/server.ts#UnknownToolError:class
AuthService                class        sym:fixtures/ts-small/src/auth/service.ts#AuthService:class
RieLockError               class        sym:packages/core/src/orchestrator/lock.ts#RieLockError:class
FactsCache                 class        sym:packages/core/src/pipeline/cache.ts#FactsCache:class

Add --json for full node objects.


Programmatic API

Everything the CLI does is available as a library. The core is dependency-injected: you supply the store and the language analyzers, so @ri-engine/rie-core itself stays free of native dependencies.

npm i @ri-engine/rie-core @ri-engine/rie-graph-store-sqlite \
      @ri-engine/rie-lang-typescript @ri-engine/rie-plugin-host \
      @ri-engine/rie-plugin-ai-context

Build a graph

import { runScan } from "@ri-engine/rie-core";
import { SqliteGraphStore } from "@ri-engine/rie-graph-store-sqlite";
import { defaultLanguages } from "@ri-engine/rie-lang-typescript";

const store = new SqliteGraphStore();
await store.open({ path: "./.rie/graph.db" });

const { report } = await runScan({
  path: ".",
  languages: defaultLanguages,   // add pythonLanguage from @ri-engine/rie-lang-python
  store,
  cacheDir: "./.rie/cache",      // omit to disable incremental caching
});

console.log(report.graph.nodes, report.graph.edges, report.graph.hash);
console.log("incremental:", report.incremental);

ScanOptions also accepts concurrency (default 8), force, exclude (gitignore syntax), and respectGitignore.

Query it

import { createGraphQuery, parseQuery, executeQuery } from "@ri-engine/rie-plugin-host";

const graph = createGraphQuery(store);

// The bounded DSL
const { nodes } = await executeQuery(graph, parseQuery("callers of greet"));
console.log(nodes.map((n) => n.qname));   // [ 'main' ]

// Or the primitives directly
for await (const node of graph.findNodes({ label: "Symbol", kind: "function", limit: 5 })) {
  console.log(node.id, node.props.signature);
}

for await (const { edge, node } of graph.neighbors("file:src/index.ts", { direction: "out" })) {
  console.log(edge.type, "->", node.id);
}

const sub = await graph.subgraph(["sym:src/auth.ts#login:function"], {
  edgeTypes: ["CALLS", "IMPORTS"],
  maxDepth: 2,
  budget: { maxNodes: 120, maxEdges: 300 },
  rank: "proximity",              // "bfs" | "degree" | "pathWeight" | "proximity"
});
console.log(sub.nodes.length, sub.truncated);

The full GraphQuery surface: getNode, getNodes, findNodes, neighbors, traverse, subgraph, search, callers, callees, importers, dependencies. Traversals are async iterables, so large results stream instead of materializing.

Generate a context bundle

import { runPlugins } from "@ri-engine/rie-plugin-host";
import { aiContextPlugin } from "@ri-engine/rie-plugin-ai-context";

const run = await runPlugins({
  store,
  cwd: ".",
  plugins: [aiContextPlugin],
  grants: ["readFiles"],          // required for source excerpts (ADR-010)
  pluginArgs: {
    "ai-context": { for: "authentication", budget: 4000, format: "json" },
  },
});

const bundle = JSON.parse(String(run.outputs[0].artifacts[0].content));
console.log(bundle.symbols.length, bundle.relationships.length);

Without the readFiles grant the plugin still runs — you get structure and signatures, just no source excerpts. Capabilities are off by default and must be granted explicitly.


Plugins

The graph is the stable interface. Outputs are plugins.

rie plugins list
report         ^0.3.0   [readGraph, writeOutput]             report/v1      (first-party)
ai-context     ^0.3.0   [readGraph, writeOutput, readFiles]  ai-context/v1  (first-party)

Writing one

import type { RiePlugin, GraphQuery, RunContext, Output } from "@ri-engine/rie-contracts";

export const deadCodePlugin: RiePlugin = {
  name: "dead-code",
  apiVersion: "^0.3.0",
  capabilities: ["readGraph", "writeOutput"],
  outputs: [{ schemaId: "dead-code/v1" }],

  async generate(graph: GraphQuery, ctx: RunContext): Promise<Output> {
    const orphans: string[] = [];
    for await (const sym of graph.findNodes({ label: "Symbol", kind: "function" })) {
      let referenced = false;
      for await (const _ of graph.neighbors(sym.id, { type: ["CALLS", "REFERENCES"], direction: "in" })) {
        referenced = true;
        break;
      }
      if (!referenced && sym.props?.exported !== true) orphans.push(sym.id);
    }

    return {
      pluginName: "dead-code",
      schemaId: "dead-code/v1",
      schemaVersion: "1.0.0",
      deterministic: true,
      artifacts: [{ path: "dead-code.json", content: JSON.stringify(orphans, null, 2) }],
    };
  },
};

Register it in rie.config.json:

{
  "extensions": ["./plugins/dead-code.js"],
  "plugins": { "dead-code": { "includeExported": false } }
}
rie plugins run dead-code

The plugin contract

| Capability | Grants | |---|---| | readGraph | Read-only GraphQuery access (granted by default) | | writeOutput | Emit artifacts (granted by default) | | readFiles | Repo-confined file reads — must be granted explicitly | | network | Network access — off by default | | env | Environment variables — off by default |

Lifecycle hooks: setupanalyzegenerateteardown, all optional.

Safety guarantees enforced by the host:

  • apiVersion compatibility is checked before load; incompatible plugins are refused with a clear diagnostic.
  • Failure isolation — a crashing plugin produces an RIE3xxx diagnostic and never breaks the run.
  • Path confinement — artifact writes and readFiles cannot escape the repository root.
  • Output schemas are enforced against the declared schemaId.

Configuration

Optional rie.config.json at the repo root. Every key below is read and applied today:

{
  "discovery": {
    "respectGitignore": true,
    "exclude": ["vendor/**", "**/*.generated.ts"]
  },
  "languages": { "enable": ["typescript", "javascript", "python"] },
  "plugins": { "ai-context": { "budget": 12000 } },
  "extensions": ["./plugins/my-plugin.js"],
  "install": { "platforms": ["claude-code", "cursor"], "scope": "project" }
}
rie config show       # resolved config
rie config validate   # validate without running anything
$ rie config show
source:     (defaults)
languages:  typescript, javascript, python
exclude:    (none)
install:    (none)
extensions: (none)

The file is validated against a zod schema and fails fast — a syntax error is RIE2001, a schema violation is RIE2002, and both exit 2 before any scanning happens.

Not yet wired up. The schema also accepts graph.store, graph.path, cache.enabled, cache.dir, discovery.maxFileSizeBytes, and log.level. These validate but are not consumed yet — graph and cache paths are currently fixed at .rie/graph.db and .rie/cache. Config formats other than JSON (.ts, .js, .yaml) and RIE_* environment layering are also specified but not implemented. Don't rely on them until they land; see docs/08-CLI/Configuration.md.


Ignoring files

RIE honors .rieignore and .gitignore, with full gitignore syntax including ! negation.

Default exclusions: node_modules, .git, .rie, dist, build, out, .next, .turbo, coverage, .cache, graphify-out, *.tsbuildinfo, and similar.

Re-include something the defaults dropped:

# .rieignore
!out/
docs/generated/**

Turn off .gitignore handling entirely with discovery.respectGitignore: false.


Diagnostics and exit codes

Every diagnostic carries a stable, greppable code.

| Range | Stage | |---|---| | RIE10xx | Discovery / filesystem | | RIE11xx | Classification | | RIE12xx | Language detection | | RIE13xx | Parsing | | RIE14xx | Semantic analysis / linking | | RIE15xx | Graph build / store | | RIE2xxx | Configuration | | RIE3xxx | Plugins | | RIE4xxx | Assistant install drift |

Diagnostics from unchanged files are grouped and suppressed by default. Use --debug for the full verbatim list.

| Exit code | Meaning | |---|---| | 0 | Success | | 1 | Runtime failure | | 2 | Usage error | | 3 | --fail-on diagnostics gate tripped | | 130 | Interrupted (Ctrl-C) |


Packages

All published under the @ri-engine scope at v0.2.0, Apache-2.0.

| Package | Purpose | |---|---| | @ri-engine/rie-cli | The rie command — composition root for everything below | | @ri-engine/rie-core | Scan orchestrator and pipeline. Depends only on contracts | | @ri-engine/rie-contracts | Types, zod schemas, id derivation. The shared vocabulary | | @ri-engine/rie-graph-store-sqlite | SQLite + FTS5 graph store via node:sqlite | | @ri-engine/rie-lang-typescript | TypeScript + JavaScript analyzer (tree-sitter) | | @ri-engine/rie-lang-python | Python analyzer (tree-sitter) | | @ri-engine/rie-plugin-host | Plugin runtime, GraphQuery implementation, query DSL | | @ri-engine/rie-plugin-ai-context | ai-context/v1 — the context bundle generator | | @ri-engine/rie-plugin-report | report/v1 — deterministic repository summary |

Module boundaries are enforced in CI with dependency-cruiser: core never imports a concrete store or language, and everything is wired at the CLI composition root.


How it works

discovery → classification → language detection → per-file analysis
    → cross-file linking → graph build → store persist
  1. Discovery — parallel walk honoring .rieignore and .gitignore.
  2. Classification — each file typed as source, config, doc, data, binary, generated, or vendor.
  3. Language detection — by extension, against the injected LanguageDescriptor set.
  4. Per-file analysis — tree-sitter parse producing FileFacts: declarations, imports, call sites, spans. Content-addressed and cached, so unchanged files are never re-parsed.
  5. Cross-file linking — import resolution (relative, aliased, re-export chains, bare → Package), then semantic linking for calls, instantiation, and inheritance.
  6. Graph build — nodes and edges via the canonical id formulas, with uniqueness assertions.
  7. Persist — a structural delta applied transactionally to SQLite.

Incremental scanning

The facts cache (ADR-009) is keyed on contentHash + languageId + grammarVersion. Editing one file re-parses exactly that file — structurally asserted in tests, not just measured. The store then receives a two-tier delta proportional to the change, with no content diffing.

Incremental output equals cold output is property-tested at both graph and store level, so freshness never costs correctness.

Measured on a ~50k-LOC fixture: 6.7× speedup for incremental over cold. The documented target is ≥10×; closing the remaining gap needs a per-file serialized-line cache and lazy graph materialization, both recorded as follow-ups. Cold throughput measures 56k files/min single-threaded — 5.6× the ≥10k budget, which is why worker threads were descoped with evidence rather than built.

Quality gates in CI

Determinism · golden fixtures · labeled edge accuracy (100% precision + recall) · module boundaries · install verification · license audit · 403 tests across 10 packages.


Developing RIE

git clone https://github.com/Priyanshu337/RIE--Repository-Intelligence-Engine.git
cd RIE--Repository-Intelligence-Engine
pnpm install
pnpm build
pnpm rie -- scan .

| Command | What it does | |---|---| | pnpm build | Build all packages (turbo) | | pnpm test | Run all tests (vitest) | | pnpm test:property | Property-based tests only | | pnpm typecheck | Type-check everything | | pnpm lint | Biome check | | pnpm format | Biome format --write | | pnpm boundaries | Enforce module boundaries (dependency-cruiser) | | pnpm license-check | Audit dependency licenses | | pnpm verify:install | Verify the install matrix end-to-end |

Requires Node >= 22.13 and pnpm 10.28+.

Documentation

The design handbook lives in docs/:


Roadmap

| Version | Theme | Highlights | |---|---|---| | V1 ✅ | CLI foundation | Repo scan · knowledge graph · AI context · report · MCP server · assistant installers | | V2 | Documentation & diagrams | Auto docs · architecture diagrams · dependency visualization | | V3 | Repository intelligence | Dead-code detection · impact analysis · API inventory | | V4 | Editor integration | VS Code extension | | V5 | Hosted platform | Multi-tenant, team-scale intelligence |

V1 is feature-complete — M0 through M4 delivered and tested. Two exit criteria remain open by nature: the ≥70% context win-rate versus repomix and graphify needs blind human evaluation (the harness is ready — rie context emits comparable bundles), and cross-OS npx verification needs the CI matrix to run.

See docs/11-Roadmap/ for the truthed checklist.


Contributing

Issues and pull requests welcome at the repository. Before submitting, please run pnpm test, pnpm typecheck, pnpm lint, and pnpm boundaries — CI enforces all four.

License

Apache-2.0 — see LICENSE.