A powerful, multi-pass codebase indexing and graph-resolution engine designed to build a high-fidelity Retrieval-Augmented Generation (RAG) system for large, multi-repository microservices architectures.
rag-cli is the core engine behind our RAG infrastructure. It doesn't just index text; it understands code structure, extracts symbols (functions, classes, contracts), and builds a global dependency graph that bridges the gaps between disparate services.
The CLI implements a sophisticated three-pass synchronization workflow to ensure global context awareness:
- Pass 1: Global Symbol Discovery
Scans all registered services to build a global map of exports and symbols. This allows the system to know where every function and class is defined before it starts chunking. - Pass 2: Implementation & Embedding
Performs semantic chunking (using Babel/TypeScript-ESTree), generates vector embeddings via Ollama, and stores metadata in ArangoDB and vectors in Qdrant. - Pass 3: Global Bridge Resolution
Analyzes the indexed symbols and local graphs to "stitch" together inter-service dependencies, creating a unified knowledge graph across the entire organization.
- Semantic AST Chunking: Deep parsing using
@babel/parserandtypescript-estreeto ensure code chunks are syntactically meaningful. - Hyper-Graph Metadata: Stores code chunks as nodes in an ArangoDB graph, allowing for relationship-aware retrieval (e.g., "Find the implementation of the API endpoint called here").
- Priority Scanning: Intelligent file discovery that prioritizes core business logic and API contracts over boilerplate.
- Plugin Augmentation: A modular system where multiple plugins can "augment" a single chunk with extra metadata (e.g., a file can be both a
typescript-domainsymbol and anapi-contract). - Scalable Parallelism: Concurrent processing of multiple services with configurable batch sizes to prevent memory exhaustion during heavy AST analysis.
- Incremental & Smart Sync: Only re-indexes changed files, prunes stale nodes, and rebuilds graph edges dynamically.
- Node.js: v22 or higher (ESM support).
- ArangoDB: For metadata, symbol storage, and graph relationships.
- Qdrant: For vector storage and semantic search.
- An LLM + embedding provider: local (Ollama, LM Studio) or frontier (OpenAI, Anthropic β chat only, no embeddings) β see Provider configuration below.
- Python Reranker: (Optional) For high-precision result ranking.
git clone https://github.com/your-repo/rag-cli.git
cd rag-cli
npm install
npm link # To use the 'rag-cli' command globallyThe CLI is driven by a rag-registry.json file (managed in the sibling rag-config repo). You can validate your configuration using:
rag-cli validate --config ../rag-config/rag-registry.json{
"version": "2.0.0",
"config": {
"qdrant_url": "http://localhost:6333",
"default_branch": "QA",
"reranker_url": "http://localhost:8001",
"llm": {
"provider": "lmstudio",
"model": "qwen3.6-35b-a3b",
"base_url": "http://localhost:1234/v1",
"api_key_env": null
},
"embedding": {
"provider": "lmstudio",
"model": "text-embedding-nomic-embed-text-v1.5",
"dimensions": 768,
"base_url": "http://localhost:1234/v1",
"api_key_env": null
}
},
"services": [
{
"name": "payment-service",
"path": "/path/to/payment-service",
"type": "backend",
"qdrant_namespace": "qa__payment_service",
"rag": {
"include": ["src/**/*.ts"],
"chunking": {
"strategy": "function",
"plugins": ["babel", "typescript"]
}
}
}
]
}config.llm and config.embedding independently select a provider β you can, for example, run embeddings locally on LM Studio and generation on Anthropic. Supported providers:
| Provider | llm |
embedding |
Notes |
|---|---|---|---|
ollama |
β | β | Native Ollama API (/api/chat, /api/embed). |
lmstudio |
β | β | LM Studio's local OpenAI-compatible server. |
openai |
β | β | Requires api_key_env naming an OPENAI_API_KEY-style env var. |
anthropic |
β | β | Chat only β Anthropic has no embeddings API. |
Secrets: api_key_env names an environment variable β never put a literal key in rag-registry.json (it's committed to git and CI-checked for this). Set the real key via your shell or a local .env file (copy .env.example).
Switching providers: edit config.llm/config.embedding in rag-registry.json, then run:
rag-cli doctor -c ../rag-config/rag-registry.json -s <service>to confirm connectivity, auth, and that the embedding model's output dimension matches config.embedding.dimensions (a mismatch here silently corrupts Qdrant collections).
For a one-off override without editing the registry, use --llm-provider/--llm-model/--embedding-provider/--embedding-model on ask, search, embed, and embed-all (this overrides provider/model only β base_url/api_key_env still come from the registry).
schemas/registry.schema.json in this repo is a synced copy of the canonical schema in the sibling rag-config repo. After changing it there, run:
npm run sync-schema # copy the canonical schema in
npm run check-schema-sync # verify the two copies match (run before PRs)rag-cli supports multiple specialized plugins that can be combined per service:
| Plugin | Scope | Extraction Logic |
|---|---|---|
babel |
Core | AST-based function, method, and class extraction. |
api-contract |
API | HTTP Routes, Methods (GET/POST), and Path patterns. |
service-client |
Integration | Outbound HTTP/Event calls to other services. |
dto-contract |
Data | Schema definitions for requests and responses. |
entity-definition |
Storage | Database entities, decorators, and primary keys. |
entity-usage |
Logic | Tracking where database entities are queried or mutated. |
infra |
DevOps | Dockerfiles, K8s manifests, and Terraform resources. |
text |
Docs | Markdown and plain text files with recursive splitting. |
The system maintains three primary collections with specialized persistent indices for performance:
Stores the actual code snippets and their semantic metadata.
- Indices:
chunk_id(Unique),[service, symbol_name],[repo, service, chunk_type].
Stores global symbol definitions found during Pass 1.
- Indices:
[service, name](Unique),[service, file_path].
Stores the relationships between chunks.
- Relation Types:
CALLS: Function/Method invocation.DEFINES: Symbol definition relationship.SERVICE_HTTP_CALLS_SERVICE: Cross-service API bridge.SHARES_EVENT_CONTRACT: Cross-service message bridge.
- Indices:
[service, _from, _to, relation_type],[source_service, target_service, relation_type].
The master command for knowledge synchronization.
--config <path>: (Required) Path to your registry file.--discovery-only: Run only the symbol extraction pass.--skip-discovery: Jump straight to chunking and embedding.--only <names>: Comma-separated list of services to process.--concurrency <n>: Parallel service limit (Default: 2).--full-clear: Destructive wipe of all global RAG data before starting.
Checks your registry against the JSON schema to prevent runtime crashes.
Terminally interactive retrieval.
search: Returns raw ranked chunks with metadata.ask: Sends context to an LLM to generate a natural language answer.
Checks connectivity and auth for the configured LLM, embedding, Qdrant, and reranker providers β run this after switching machines or providers, before embed/ask/search.
--config <path>: (Required) Path to your registry file.--service <name>: Service to check Qdrant collection reachability for.
The chunk command is the brain of the static analysis pipeline. It transforms raw source code into semantic, namespaced knowledge nodes.
When a file is processed, the orchestrator runs a multi-stage pipeline:
- Primary Plugin: A language-aware plugin (like
babel) generates base chunks by traversing the AST. - Augmenter Plugins: Specialized plugins (like
api-contractordto-contract) analyze the same file to add high-value metadata or secondary nodes. - Fallback Mechanism: If a syntax error occurs or a plugin returns nothing, the system falls back to the
textplugin to ensure the content is still searchable.
Every chunk is assigned a globally unique chunk_id using the pattern:
repo-slug::service-name::local-symbol-name
This allows the global knowledge graph to resolve dependencies across repository boundaries without collisions.
The search and ask commands are powered by an Adaptive Retrieval Controller. Unlike simple semantic search, this engine understands the codebase topography and walks the dependency graph to find the most relevant context.
The engine uses a multi-pass strategy to ensure "Chain Coverage". It assesses whether the retrieved chunks provide a complete "story" (e.g., Entrypoint β Logic β Persistence). If a gap is detected (e.g., missing data access logic), it adapts the retrieval plan and runs another pass with specialized filters.
After the initial vector search, the engine uses ArangoDB to:
- Walk the Call Graph: Find functions called by the search results.
- Bridge Services: Resolve outbound HTTP/Event calls into the actual implementation in another service.
- Context Enrichment: Automatically pull in parent class definitions and module wiring to provide full context to the LLM.
To ensure high precision, retrieved candidates are sent to a dedicated reranker service. This secondary ranking phase uses a cross-encoder model to score the relevance of each code chunk against the query, significantly reducing "hallucinations" in the ask command.
The knowledge graph is the "glue" that allows rag-cli to understand complex, multi-service architectures. It tracks not just what code says, but how it connects across your entire organization.
Pass 1 of the pipeline builds the Global Symbol Map. This is a lightweight index of all exported functions, classes, and types across all repositories. It provides the "address book" for the entire codebase, ensuring that when Service A calls Service B, the target is already known.
Once services are indexed, Pass 3 "stitches" the individual graphs together. It analyzes api-contract and service-client chunks to create cross-repo bridges:
- HTTP Bridges: Matches outbound calls to their corresponding route implementations.
- Event Bridges: Links message publishers to their subscribers via shared event patterns.
dep-graph <symbol>: Performs deep AQL traversals to visualize the "chain of command" for any specific symbol, even across repository boundaries.graph-health: Identifies dangling edges, unresolved contracts, and disconnected "islands" in the knowledge graph to ensure structural integrity.
Run the entire 3-pass pipeline for all services:
rag-cli sync-all --config ./rag-registry.jsonSync only a subset of services:
rag-cli sync-all --config ./rag-registry.json --only payment-service,auth-servicePopulate the global symbol map without embedding (useful for graph pre-calculation):
rag-cli sync-all --config ./rag-registry.json --discovery-onlyTest the indexed knowledge directly from the terminal:
rag-cli search "How does the multi-hop transfer validation work?"
rag-cli ask "Explain the FX rate expiration logic in the transfer service."bin/: CLI entry point.commands/: Implementation of all CLI commands.schemas/: JSON schemas for configuration validation.utils/: Core logic for ArangoDB, Qdrant, scanning, chunking, and graph resolution.utils/chunker/: Chunker plugins (Babel, Text, etc.).
- Adding a Plugin: Create a new file in
utils/chunker/plugins/. Implement thevisitorpattern to extract custom metadata. - Improving Resolution: Update
utils/graph-store.jsto add new canonicalization logic for protocol-specific bridges (e.g., gRPC, GraphQL). - Local Testing: Use the
rag-cli validatecommand to ensure your changes to the registry schema are correct.