Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ jobs:
python -m pip install -e . --no-deps
python -m pip install pytest pytest-asyncio pydantic pydantic-settings click PyYAML fastapi structlog ruff mypy mcp httpx

- name: Run Milestone 0-5 tests
run: PYTHONPATH=src python -m pytest tests/test_m0_baseline.py tests/test_m1_services.py tests/test_m2_registry.py tests/test_citations.py tests/test_m3_citations.py tests/test_api_routes.py tests/test_mcp_handlers.py tests/test_mcp_tools.py tests/test_ui_handlers.py tests/test_m4_hybrid_retrieval.py tests/test_m5_code_graph.py
- name: Run Milestone 0-6 tests
run: PYTHONPATH=src python -m pytest tests/test_m0_baseline.py tests/test_m1_services.py tests/test_m2_registry.py tests/test_citations.py tests/test_m3_citations.py tests/test_api_routes.py tests/test_mcp_handlers.py tests/test_mcp_tools.py tests/test_ui_handlers.py tests/test_m4_hybrid_retrieval.py tests/test_m5_code_graph.py tests/test_m6_interfaces_docs.py

- name: Run Milestone 0-5 lint baseline
run: ruff check src/coderag/generation src/coderag/indexing/vectorstore.py src/coderag/models src/coderag/retrieval src/coderag/graph src/coderag/services src/coderag/config.py src/coderag/api/schemas.py src/coderag/api/routes.py src/coderag/mcp/handlers.py src/coderag/mcp/tools.py src/coderag/cli.py src/coderag/ui/grounding.py src/coderag/ui/repository_metadata.py src/coderag/ui/handlers.py tests/test_m0_baseline.py tests/test_m1_services.py tests/test_m2_registry.py tests/test_citations.py tests/test_m3_citations.py tests/test_api_routes.py tests/test_mcp_handlers.py tests/test_mcp_tools.py tests/test_ui_handlers.py tests/test_m4_hybrid_retrieval.py tests/test_m5_code_graph.py scripts/evalfly_smoke.py
- name: Run Milestone 0-6 lint baseline
run: ruff check src/coderag/generation src/coderag/indexing/vectorstore.py src/coderag/models src/coderag/retrieval src/coderag/graph src/coderag/services src/coderag/config.py src/coderag/api/schemas.py src/coderag/api/routes.py src/coderag/mcp/handlers.py src/coderag/mcp/tools.py src/coderag/cli.py src/coderag/ui/grounding.py src/coderag/ui/repository_metadata.py src/coderag/ui/handlers.py tests/test_m0_baseline.py tests/test_m1_services.py tests/test_m2_registry.py tests/test_citations.py tests/test_m3_citations.py tests/test_api_routes.py tests/test_mcp_handlers.py tests/test_mcp_tools.py tests/test_ui_handlers.py tests/test_m4_hybrid_retrieval.py tests/test_m5_code_graph.py tests/test_m6_interfaces_docs.py scripts/evalfly_smoke.py

- name: Run Milestone 0-5 type baseline
run: PYTHONPATH=src mypy src/coderag/generation src/coderag/indexing/vectorstore.py src/coderag/models src/coderag/retrieval src/coderag/graph src/coderag/services src/coderag/config.py src/coderag/api/schemas.py src/coderag/api/routes.py src/coderag/mcp/handlers.py src/coderag/ui/grounding.py src/coderag/ui/repository_metadata.py src/coderag/ui/handlers.py tests/test_m0_baseline.py tests/test_m1_services.py tests/test_m2_registry.py tests/test_citations.py tests/test_m3_citations.py tests/test_api_routes.py tests/test_mcp_handlers.py tests/test_ui_handlers.py tests/test_m4_hybrid_retrieval.py tests/test_m5_code_graph.py scripts/evalfly_smoke.py
- name: Run Milestone 0-6 type baseline
run: PYTHONPATH=src mypy src/coderag/generation src/coderag/indexing/vectorstore.py src/coderag/models src/coderag/retrieval src/coderag/graph src/coderag/services src/coderag/config.py src/coderag/api/schemas.py src/coderag/api/routes.py src/coderag/mcp/handlers.py src/coderag/ui/grounding.py src/coderag/ui/repository_metadata.py src/coderag/ui/handlers.py tests/test_m0_baseline.py tests/test_m1_services.py tests/test_m2_registry.py tests/test_citations.py tests/test_m3_citations.py tests/test_api_routes.py tests/test_mcp_handlers.py tests/test_ui_handlers.py tests/test_m4_hybrid_retrieval.py tests/test_m5_code_graph.py tests/test_m6_interfaces_docs.py scripts/evalfly_smoke.py

- name: Compile changed runtime modules
run: python -m py_compile src/coderag/__init__.py src/coderag/config.py src/coderag/main.py src/coderag/cli.py src/coderag/indexing/embeddings.py src/coderag/indexing/vectorstore.py src/coderag/generation/*.py src/coderag/models/*.py src/coderag/retrieval/*.py src/coderag/graph/*.py src/coderag/services/*.py src/coderag/api/schemas.py src/coderag/api/routes.py src/coderag/mcp/handlers.py src/coderag/mcp/tools.py src/coderag/ui/grounding.py src/coderag/ui/repository_metadata.py src/coderag/ui/handlers.py tests/test_m0_baseline.py tests/test_m1_services.py tests/test_m2_registry.py tests/test_citations.py tests/test_m3_citations.py tests/test_api_routes.py tests/test_ui_handlers.py tests/test_m4_hybrid_retrieval.py tests/test_m5_code_graph.py scripts/evalfly_smoke.py
run: python -m py_compile src/coderag/__init__.py src/coderag/config.py src/coderag/main.py src/coderag/cli.py src/coderag/indexing/embeddings.py src/coderag/indexing/vectorstore.py src/coderag/generation/*.py src/coderag/models/*.py src/coderag/retrieval/*.py src/coderag/graph/*.py src/coderag/services/*.py src/coderag/api/schemas.py src/coderag/api/routes.py src/coderag/mcp/handlers.py src/coderag/mcp/tools.py src/coderag/ui/grounding.py src/coderag/ui/repository_metadata.py src/coderag/ui/handlers.py tests/test_m0_baseline.py tests/test_m1_services.py tests/test_m2_registry.py tests/test_citations.py tests/test_m3_citations.py tests/test_api_routes.py tests/test_ui_handlers.py tests/test_m4_hybrid_retrieval.py tests/test_m5_code_graph.py tests/test_m6_interfaces_docs.py scripts/evalfly_smoke.py

- name: Build package
run: python -m build
Expand Down
20 changes: 20 additions & 0 deletions .pi/.specsafe-state.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,26 @@
"turns": 0
}
}
},
{
"sliceId": "CRAG-20260630-M6-PRODUCTION-INTERFACES",
"workspaceId": "CodeRAG",
"sessionId": "omp-session",
"beganAt": "2026-06-30T21:35:47.487Z",
"endedAt": "2026-06-30T21:40:17.045Z",
"outcome": "PASS",
"costSummary": {
"externalMemoryCalls": 0,
"externalMemoryCost": 0,
"subagentTokens": {
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"cost": 0,
"turns": 0
}
}
}
]
}
75 changes: 54 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# CodeRAG - Code Q&A with Verifiable Citations
# CodeRAG - Verified Codebase Context Engine

[![PyPI version](https://badge.fury.io/py/code-rag-me.svg)](https://pypi.org/project/code-rag-me/)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

RAG-based Q&A system for code repositories that provides grounded answers with verifiable citations.
CodeRAG is a verified codebase context engine for agents and developers. It indexes repositories, retrieves grounded code context, verifies citations against retrieved chunks, and exposes the results through CLI, REST, MCP, and a local web UI. It is not an autonomous coding agent and does not edit repositories.

## 🚀 Quick Start

Expand Down Expand Up @@ -34,26 +34,32 @@ Now you can use CodeRAG directly in Claude Desktop!

## ✨ Features

- **Grounded Responses**: Every answer includes citations to source code `[file:start-end]`
- **Cloud or Local LLM**: Use Groq (free), OpenAI, Anthropic, or run locally with GPU
- **GitHub Integration**: Index any public GitHub repository
- **MCP Support**: Integrate directly with Claude Desktop
- **Semantic Chunking**: Tree-sitter for Python, text fallback for other languages
- **Web Interface**: Gradio UI for easy interaction
- **REST API**: Programmatic access for integration
- **CLI**: Full command-line interface
- **Verified citations**: Answers include citations like `[file:start-end]` and expose verification status.
- **Hybrid retrieval and context packs**: Combine semantic and lexical retrieval without requiring generation.
- **Code graph intelligence**: Python and TypeScript/JavaScript symbols, references, and blast-radius evidence are indexed when supported.
- **Cloud or local LLM**: Use Groq, OpenAI, Anthropic, OpenRouter, Together, or explicitly configured local models.
- **GitHub indexing**: Index public GitHub repositories with durable SQLite registry/job state.
- **MCP support**: Expose indexing, retrieval, context, and graph tools to MCP clients.
- **REST API and CLI**: Programmatic and terminal access to the same core capabilities.
- **Local web interface**: Gradio UI for local exploration.

## 📋 CLI Commands

```bash
coderag setup # Configure LLM provider and API key
coderag serve # Start web server
coderag mcp-install # Configure Claude Desktop for MCP
coderag mcp-run # Run MCP server (used by Claude Desktop)
coderag index <url> # Index a GitHub repository
coderag query <repo> "?" # Ask a question about code
coderag repos # List indexed repositories
coderag doctor # Diagnose setup issues
coderag setup # Configure LLM provider and API key
coderag serve # Start local web/API/MCP server
coderag mcp-install # Configure Claude Desktop for MCP
coderag mcp-run # Run MCP server over stdio
coderag index <url> # Index a GitHub repository
coderag update <repo> # Incrementally update an indexed repository
coderag query <repo> "?" # Ask a question with citations
coderag search-hybrid <repo> "query" # Retrieve hybrid code context without generation
coderag context-pack <repo> "query" # Build an agent-ready context pack
coderag find-symbol <repo> <symbol> # Find indexed graph symbols
coderag find-references <repo> <sym> # Find indexed symbol references
coderag blast-radius <repo> <symbol> # Show graph-backed impacted files/tests
coderag repos # List indexed repositories
coderag doctor # Diagnose setup issues
```

## 🔧 Installation
Expand Down Expand Up @@ -229,8 +235,17 @@ This will prompt you to:
# Index a repository
coderag index https://github.com/owner/repo

# Ask questions
coderag query abc12345 "How does authentication work?"
# Ask questions with citation verification metadata
coderag query abc12345 "How does authentication work?" --format json

# Retrieve context without calling an LLM
coderag search-hybrid abc12345 "authentication flow" --format json
coderag context-pack abc12345 "authentication flow"

# Inspect graph evidence
coderag find-symbol abc12345 AuthService --format json
coderag find-references abc12345 validate_token --format json
coderag blast-radius abc12345 validate_token --format json

# List repositories
coderag repos
Expand All @@ -244,10 +259,20 @@ curl -X POST http://localhost:8000/api/v1/repos/index \
-H "Content-Type: application/json" \
-d '{"url": "https://github.com/owner/repo"}'

# Query
# Query with citation verification
curl -X POST http://localhost:8000/api/v1/query \
-H "Content-Type: application/json" \
-d '{"question": "How does X work?", "repo_id": "abc12345"}'

# Hybrid retrieval without generation
curl -X POST http://localhost:8000/api/v1/search-hybrid \
-H "Content-Type: application/json" \
-d '{"query": "authentication flow", "repo_id": "abc12345", "top_k": 5}'

# Graph-backed blast radius
curl -X POST http://localhost:8000/api/v1/graph/blast-radius \
-H "Content-Type: application/json" \
-d '{"symbol": "validate_token", "repo_id": "abc12345"}'
```

### Claude Desktop (MCP)
Expand Down Expand Up @@ -290,6 +315,14 @@ SERVER_PORT=8000

Configuration is stored in `~/.config/coderag/config.json` after running `coderag setup`.

## Production readiness

Current release-candidate work is evidence-gated. The supported default is local loopback (`127.0.0.1`) with user-configured model credentials. Binding to public interfaces requires explicit host, trusted CORS origins, authentication, and network controls outside CodeRAG's defaults.

- Cloud LLM providers send prompt context to the selected provider. Use local/private profiles only when configured and verified for your environment.
- Unsupported graph languages degrade explicitly to text/chunk retrieval; they do not report fake graph confidence.
- CodeRAG verifies citations against retrieved chunks, but it does not prove repository correctness, execute arbitrary project tests, or make autonomous code changes.

## 🏗️ Architecture

```
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Milestone 6 Contract: Production Interfaces and Docs

## Scope

Stabilize the user-facing CodeRAG contracts across REST, MCP, CLI, and README without claiming production readiness beyond verified evidence.

## Acceptance Criteria

- M6-AC1: REST/MCP/CLI expose the same documented capability set where implementation exists: index, update, list, query, search, hybrid search, context packs, symbol lookup, reference lookup, and blast radius.
- M6-AC2: Representative REST, MCP, and CLI output shapes are covered by deterministic snapshot/contract tests.
- M6-AC3: User-facing docs position CodeRAG as a verified codebase context engine, not an autonomous coding agent.
- M6-AC4: Docs state current privacy and readiness limits: loopback default, explicit deployment hardening required, cloud LLMs require user-configured keys, and unsupported graph languages degrade explicitly.
- M6-AC5: CI and EvalFly smoke gates include the M6 interface/doc contract checks.

## Non-goals

- No autonomous editing behavior.
- No blanket production-ready claim.
- No broad redesign of Gradio UI.
- No expansion of unsupported language graph confidence.
96 changes: 96 additions & 0 deletions evals/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,102 @@
}
]
}
},
{
"schema_version": "evalfly.case.v1",
"case_id": "m6-production-interfaces-contract-exists",
"title": "Milestone 6 production interfaces contract exists",
"suite": "smoke",
"risk_tier": "critical",
"task_type": "delivery_governance",
"source": {
"kind": "acceptance_criteria",
"criteria": "M6-AC1 M6-AC2 M6-AC3 M6-AC4"
},
"privacy": {
"classification": "public",
"sanitized": true
},
"expected": {
"success_criteria": [
"The Milestone 6 interface and documentation contract is committed."
]
},
"judge": {
"type": "deterministic",
"assertions": [
{
"type": "file_exists",
"path": "docs/superpowers/plans/2026-06-30-m6-production-interfaces-contract.md"
}
]
}
},
{
"schema_version": "evalfly.case.v1",
"case_id": "m6-hybrid-search-interface-exists",
"title": "Hybrid search interface exists across adapters",
"suite": "smoke",
"risk_tier": "critical",
"task_type": "adapter_contract",
"source": {
"kind": "acceptance_criteria",
"criteria": "M6-AC1 M6-AC2"
},
"privacy": {
"classification": "public",
"sanitized": true
},
"expected": {
"success_criteria": [
"REST and CLI expose hybrid retrieval without generation."
]
},
"judge": {
"type": "deterministic",
"assertions": [
{
"type": "file_contains",
"path": "src/coderag/api/routes.py",
"text": "@router.post(\"/search-hybrid\""
},
{
"type": "file_contains",
"path": "src/coderag/cli.py",
"text": "@cli.command(\"search-hybrid\")"
}
]
}
},
{
"schema_version": "evalfly.case.v1",
"case_id": "m6-targeted-tests-exist",
"title": "Milestone 6 targeted interface tests exist",
"suite": "smoke",
"risk_tier": "critical",
"task_type": "test_coverage",
"source": {
"kind": "acceptance_criteria",
"criteria": "M6-AC2 M6-AC3 M6-AC4"
},
"privacy": {
"classification": "public",
"sanitized": true
},
"expected": {
"success_criteria": [
"Targeted interface and README contract tests are committed."
]
},
"judge": {
"type": "deterministic",
"assertions": [
{
"type": "file_exists",
"path": "tests/test_m6_interfaces_docs.py"
}
]
}
}
]
}
40 changes: 40 additions & 0 deletions src/coderag/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
GraphQueryRequest,
GraphReferenceResponse,
GraphSymbolResponse,
HybridSearchRequest,
HybridSearchResponse,
HybridSearchResultResponse,
IndexRepositoryRequest,
IndexRepositoryResponse,
ListRepositoriesResponse,
Expand Down Expand Up @@ -218,6 +221,43 @@ async def context_pack(request: ContextPackRequest) -> ContextPackResponse:
)


@router.post("/search-hybrid", response_model=HybridSearchResponse)
async def search_hybrid(request: HybridSearchRequest) -> HybridSearchResponse:
"""Run hybrid retrieval without LLM generation."""
repo = get_repo_or_404(request.repo_id)
try:
results = retrieval_service.search_hybrid(
repo.id,
request.query,
top_k=request.top_k,
max_tokens=request.max_tokens,
max_chunks_per_file=request.max_chunks_per_file,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return HybridSearchResponse(
results=[
HybridSearchResultResponse(
chunk_id=chunk.chunk_id,
file_path=chunk.file_path,
start_line=chunk.start_line,
end_line=chunk.end_line,
citation=chunk.citation,
chunk_type=chunk.chunk_type,
name=chunk.name,
content=chunk.content,
relevance_score=chunk.relevance_score,
score_breakdown=chunk.score_breakdown,
retrieval_sources=chunk.retrieval_sources,
token_estimate=chunk.token_estimate,
ranking_reason=chunk.ranking_reason,
)
for chunk in results
],
count=len(results),
)


@router.post("/graph/find-symbol", response_model=FindSymbolResponse)
def find_symbol(request: GraphQueryRequest) -> FindSymbolResponse:
"""Find graph symbols by name."""
Expand Down
35 changes: 35 additions & 0 deletions src/coderag/api/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,41 @@ class ContextPackResponse(BaseModel):
capabilities: dict[str, object]



class HybridSearchRequest(BaseModel):
"""Request to run hybrid retrieval without generation."""

repo_id: str = Field(..., description="Repository ID to search")
query: str = Field(..., description="Search query")
top_k: int = Field(10, ge=1, le=20, description="Maximum results to include")
max_tokens: int = Field(4000, ge=1, description="Maximum token estimate")
max_chunks_per_file: int = Field(3, ge=1, description="Maximum results per file")


class HybridSearchResultResponse(BaseModel):
"""A hybrid retrieval result."""

chunk_id: str
file_path: str
start_line: int
end_line: int
citation: str
chunk_type: str
name: str | None = None
content: str
relevance_score: float = 0.0
score_breakdown: dict[str, float] = Field(default_factory=dict)
retrieval_sources: list[str] = Field(default_factory=list)
token_estimate: int = 0
ranking_reason: str | None = None


class HybridSearchResponse(BaseModel):
"""Hybrid retrieval response."""

results: list[HybridSearchResultResponse]
count: int

class GraphQueryRequest(BaseModel):
"""Request for graph symbol queries."""

Expand Down
Loading
Loading