Skip to main content

urag

Universal Repository Agent Graph

Structure-aware retrieval and impact analysis for software repositories. urag indexes code symbols, documentation, call sites, and source locations into a portable SQLite database. It then returns small, cited result packets that are useful to developers and AI agents without loading whole files into context.

urag is a retrieval layer, not an LLM. It finds the relevant repository context; the developer or agent uses that context to answer the question.

See urag in action for a complete indexing and agent response walkthrough.

Why urag

Traditional text search is good at finding strings. Generic RAG is good at finding similar text. Repository questions often need both, plus structural information such as:

  • Where is a function, class, interface, or type defined?
  • How does a feature work across modules?
  • What calls this function?
  • What is the downstream impact of changing a symbol?
  • Which exact source lines support the result?

urag addresses these questions with:

  • Tree-sitter parsing for symbol-aware indexing.
  • FTS5 lexical search for exact names and identifiers.
  • sqlite-vec embeddings for conceptual search.
  • Reciprocal Rank Fusion for the default hybrid search.
  • A static call graph for direct and multi-hop caller queries.
  • Import-alias resolution for selected languages.
  • Lazy source retrieval, so search results stay compact.
  • Incremental indexing and a file watcher for active repositories.
  • A CLI and a stdio MCP server for agent harnesses.

How It Works

repository files
       |
       v
file discovery and incremental checks
       |
       v
tree-sitter extractors
       |
       +--> symbols, signatures, summaries, spans
       +--> call edges and import aliases
       |
       v
SQLite project index
       |
       +--> FTS5 lexical index
       +--> sqlite-vec dense index
       +--> files, units, calls, and aliases
       |
       v
ranked result packets
       |
       v
exact source span fetched only when needed

Each indexed unit has three practical layers:

Layer Contents Purpose
Retrieval key Name, qualified name, signature, summary, concepts, relationships Search and embedding input
Relationships File, line, byte span, parent, calls, aliases Navigation and impact analysis
Evidence Exact source lines on disk Final context, loaded on demand

The index is stored per project in .urag/index.db. SQLite uses WAL mode, and new embeddings are written in batches of 64 units.

Installation

Requirements:

  • Python 3.12 or newer.
  • git is optional, but is used for commit provenance and changed-file detection when available.
  • The default local embedding model downloads on first use and is cached locally. No API key is required for the default provider.

From Source

git clone https://github.com/Abas-Tim/urag.git
cd urag
uv sync
uv run urag --version

To install the command globally with uv:

uv tool install .
urag --version

The repository also contains bootstrap installers for macOS, Linux, and Windows under bootstrap/.

Quick Start

Run these commands from a repository you want to index:

urag init --root /path/to/project --full
urag search "how does authentication work" --root /path/to/project
urag search "TokenValidator.validate" --mode lexical --top-k 3 --root /path/to/project
urag callers index_all --depth 3 --root /path/to/project
urag get UNIT_ID --root /path/to/project

urag init creates .urag/, the project configuration, and the database. Use --full for the initial index. Later updates are incremental:

urag index --root /path/to/project
urag watch --root /path/to/project

watch debounces filesystem events and re-indexes changed files. It can also run a periodic full rescan with --rescan 30.

CLI

Command Description
urag init Create project configuration and an empty index; add .urag/ to .gitignore
urag init --full Create the project index and index all eligible files
urag index Incrementally index new, changed, and deleted files
urag watch Keep the index updated while files change
urag search QUERY Search symbols and documentation
urag callers NAME Find direct callers of a symbol
urag callers NAME --depth 3 Find callers through multiple call-graph hops
urag get UNIT_ID Fetch the exact source span for a search result
urag status Show file, unit, embedding, language, and database statistics
urag doctor Check index and embedding health
urag classify QUERY Show the query class and selected context budget
urag eval Compare retrieval systems on a question set
urag mcp Run the MCP server over stdio

Search supports three modes:

Mode Best for
lexical Exact names, identifiers, paths, and configuration keys
dense Conceptual or natural-language questions
hybrid The default; combines lexical and dense results with RRF

Use --json for machine-readable output, --language to filter results, and --evidence to include trimmed source spans. The get command returns the full current span for a unit id.

Adaptive Retrieval

Queries are routed with a deterministic, zero-model-cost classifier. The classifier selects a default result count and evidence budget based on the question shape:

Class Typical query Default results Evidence budget
symbol TokenValidator.validate 3 800 tokens
local how does token validation work 5 2,000 tokens
debugging why does this crash across modules 8 4,000 tokens
impact what calls parse_token 10 6,000 tokens

Exact symbol queries are routed to lexical search. Impact queries are routed to the call graph when a target symbol can be identified. --top-k and query_class can override the defaults where supported.

The configured retrieval.max_evidence_tokens is a global ceiling and can reduce the class budget; the generated default is 1,500 tokens.

Call Graph And Impact Analysis

During indexing, urag scans supported source files for call expressions and stores:

  • The enclosing caller unit.
  • The last callee segment, such as validate.
  • The full written callee chain, such as self.validate or os.path.exists.
  • The call-site line number.

This powers direct and multi-hop queries:

urag callers validate
urag callers validate --depth 3
urag search "what breaks if parse_token changes"

Multi-hop traversal uses breadth-first search, records the shortest hop for each result, and terminates safely on cycles. Import aliases are resolved for Python, TypeScript, Go, Rust, and C# when the index contains the relevant bindings:

urag callers os.path.exists
urag callers core.http.fetch

The graph is static and intentionally approximate. Dynamic dispatch, reflection, generated code, and some instance-method chains are not resolved. The graph should be treated as impact evidence, not as a runtime dependency model.

Supported Languages

Language Extensions Extracted information
Python .py, .pyi Functions, classes, methods, imports, calls, aliases
TypeScript .ts, .tsx, .mts, .cts Functions, classes, interfaces, types, enums, imports, calls, aliases
JavaScript .js, .jsx, .mjs, .cjs Functions, classes, methods, imports, calls, aliases
Go .go Functions, methods, structs, interfaces, imports, calls, aliases
Rust .rs Functions, methods, structs, traits, enums, imports, calls, aliases
Java .java Methods, constructors, classes, interfaces, enums, imports, calls
C .c, .h Functions, structs, unions, typedefs, includes, calls
C++ .cpp, .cc, .cxx, .hpp, .hh Functions, methods, classes, structs, namespaces, includes, calls
C# .cs Classes, interfaces, structs, records, enums, methods, usings, calls, aliases
Markdown .md, .markdown, .mdx Heading-based document chunks and hierarchy

Files are filtered by .gitignore, built-in exclusions, configured languages, and a default maximum size of 1 MB. These settings are configurable in .urag/urag.toml.

Embeddings And Configuration

The default provider is a local ONNX model through FastEmbed:

[embedding]
provider = "local"
model = "BAAI/bge-small-en-v1.5"
dimension = 384

The model is downloaded on first use and cached in %LOCALAPPDATA%/urag on Windows or ~/.cache/urag on other systems. An OpenAI-compatible HTTP embedding endpoint is also supported:

[embedding]
provider = "http"
dimension = 384
http_url = "http://localhost:11434/v1"
http_model = "nomic-embed-text"
http_api_key = ""

Keep API keys in the local .urag/urag.toml only and do not commit them. Projects that already have an index can use provider = "none" for lexical-only retrieval; dense retrieval and embedding new units require an embedding provider.

Git Freshness

For Git repositories, indexed files record the commit used at indexing time. Search and get results include the short commit and a stale flag when the file differs from that indexed revision. Non-Git projects use file metadata checks instead.

Freshness detection is best-effort. Run urag index after a branch switch, pull, or other large repository change before relying on old evidence. Static analysis also cannot see runtime-generated relationships.

MCP Server

Run urag as a stdio MCP server for an agent harness:

urag mcp --root /path/to/project

Example generic MCP configuration:

{
  "mcpServers": {
    "urag": {
      "command": "urag",
      "args": ["mcp", "--root", "/path/to/project"]
    }
  }
}

The server exposes these tools:

  • search: Search symbols and documentation with compact result packets.
  • fetch_unit: Fetch exact source lines for a result id.
  • callers: Query direct or multi-hop callers.
  • index_now: Incrementally re-index changed files.
  • status: Return index statistics and configuration.
  • init_project: Create and populate an index for a project.

The intended agent workflow is to search with top_k=3-5, fetch exact spans only for the most relevant one to three units, and call index_now after changes.

Agent Skill

The repository includes skills/urag/SKILL.md, a small instruction file for agent harnesses. It teaches the search-first, fetch-evidence-on-demand workflow and is included in built packages.

For harnesses that use local skill directories, install it with the harness's normal skill installation mechanism. For example:

cp -r skills/urag ~/.config/opencode/skills/urag
cp -r skills/urag ~/.claude/skills/urag

Measuring Retrieval

The evaluation harness compares urag with non-structural baselines on the same questions:

urag eval --root . --autogen 10 --top-k 5
urag eval --root . --questions questions.jsonl
urag eval --root . --transitive 25 --alias 25 \
  --systems urag-callers,urag-transitive,urag-hybrid
uv run python benchmarks/run_bench.py --self

It measures fractional unit recall@k, file recall@k, precision, MRR, approximate tokens per retrieval, and p50/p95 latency. Definition and call questions can be generated with provable gold data from the index. Custom conceptual questions can be supplied as JSONL:

{"query": "where is TokenValidator defined", "gold_file": "src/auth.py"}

Checked-In Benchmark Snapshot

The following values come from the reports in benchmarks/reports/, using top_k=5. They are reference measurements from one environment, not performance guarantees.

Dataset System Questions Unit recall Precision MRR p50 Mean compact tokens
Synthetic fixture urag-callers 22 1.000 1.000 1.000 0.14 ms 5.0
Synthetic fixture urag-transitive 22 1.000 1.000 1.000 0.11 ms 6.4
urag repository urag-callers 47 1.000 1.000 1.000 0.48 ms 41.4
urag repository urag-transitive 47 1.000 1.000 1.000 10.38 ms 78.2
urag repository urag-hybrid 57 0.316 0.077 0.252 4.38 ms 134.7

The checked-in reports predate the current index-lifecycle and retrieval-quality changes; rerun the benchmark before comparing new results. The transitive system reached indirect_recall=1.000 on the synthetic fixture and 0.440 on the checked-in urag repository report. In the current evaluation harness, unit recall is fractional across the gold units for a question. Graph systems also run on graph-eligible questions, while the hybrid row includes the full generated question set, so the rows are directional rather than a universal ranking.

The efficiency gain urag is designed to provide comes from returning compact metadata first and loading source spans only when requested. Actual latency, token count, and retrieval quality depend on repository size, embedding provider, query type, and index state.

Development

uv sync
uv run pytest -q
uv run urag --version

CI runs the test suite and CLI smoke check on Python 3.12 and 3.13. The test suite covers extractors, call extraction, multi-hop traversal, alias resolution, evaluation metrics, and benchmark fixtures.

License

MIT. See LICENSE.

Metadata

Release files for urag-cli 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for urag-cli 0.1.2
File Size Uploaded Provenance
urag_cli-0.1.2.tar.gz 62.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for urag-cli 0.1.2
File Interpreter ABI Platform
urag_cli-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 126.0 kB

Release files / urag_cli-0.1.2.tar.gz

Download URL urag_cli-0.1.2.tar.gz
Size 62.1 kB
Tags Source
SHA-256 checksum
How to use checksums
32d6fc44782c9be0254dcec13361d89b0d4d19630a68fa006c9da8c6e02e2ab6
BLAKE2b-256 checksum
How to use checksums
ab36bf3ead013bc365c90330d80eea81554ac329fddbaf4f1a2106d45ec34160
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / urag_cli-0.1.2-py3-none-any.whl

Download URL urag_cli-0.1.2-py3-none-any.whl
Size 63.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f59b7d920271d9372cdc74783e9489b44e347cd4b16c822ae836958596a7c146
BLAKE2b-256 checksum
How to use checksums
6fd174dc3dd71e3aeb925de86de71dc7da66554e6a7439363cbffa9d92c62c7f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for urag-cli 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page