This document provides instructions for developing, testing, configuring, and running ContextCortex locally.
- Python 3.11+
- Node.js 20+ & npm (for the React 19 frontend)
- Git (for shallow repository cloning)
- Vector Database: Qdrant (local/Docker or embedded) or ChromaDB (embedded/disk or remote)
- FastEmbed (included in
requirements.txtfor in-process ONNX CPU embeddings)
Linux / macOS (Bash):
git clone git@github.com:spelech/contextcortex.git
cd contextcortex
./setup.shWindows (PowerShell):
git clone git@github.com:spelech/contextcortex.git
cd contextcortex
.\setup.ps1-
Clone the repository:
git clone git@github.com:spelech/contextcortex.git cd contextcortex -
Create a virtual environment:
python3 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install Python dependencies:
pip install -r requirements.txt
-
Install Frontend dependencies & build bundle:
cd frontend npm install npm run build cd ..
-
Start Vector Database (Optional - defaults to embedded Qdrant/Chroma):
docker run -d --name qdrant -p 6333:6333 -p 6334:6334 \ -v $(pwd)/data/qdrant_storage:/qdrant/storage \ qdrant/qdrant:latest -
Set Environment Variables (Optional):
export VECTOR_STORE_PROVIDER="qdrant" # "qdrant" or "chroma" export COLLECTION_NAME="knowledge_rag_v1" export EMBEDDING_PROVIDER="local" # "local" (FastEmbed) or "api" (LiteLLM) export EMBEDDING_MODEL="BAAI/bge-small-en-v1.5" export SPARSE_MODEL="Qdrant/bm25" export EMBEDDING_NUM_THREADS=2 # CPU thread cap for ONNX (defaults to min(2, system_cpus)) export EMBEDDING_BATCH_SIZE=32 # Batch size for tokenization (defaults to 32) export GITHUB_TOKEN="ghp_your_token" # Optional: For higher rate limits & private repos
-
Run the server:
python main.py
The server starts on port
3000, initializes SQLite tables (index_cache.db), configures vector storage (Qdrant/ChromaDB), mounts/admin/static files, and binds both/sseand/mcpFastMCP transport endpoints.
# Run all backend unit and integration tests (522+ tests)
pytest -v
# Run backend tests with code coverage report (88%+ coverage baseline)
pytest -v --cov=app --cov-report=term-missingcd frontend
# Run unit and component tests via Vitest (315 tests across 32 test files)
npm test
# Run component tests with code coverage
npm run test:coverage
# Run end-to-end user journey tests via Playwright
npx playwright test# Regenerate and validate REQUIREMENTS.md against live test suite
python3 scripts/generate_requirements.py
pytest -v tests/backend/test_requirements_sync.py# Start local documentation dev server
npm run docs:dev
# Build production static documentation site
npm run docs:build
# Preview built production documentation site
npm run docs:preview| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
SQLAlchemy connection string (e.g. postgresql+psycopg://... or sqlite:///...) |
sqlite:////app/data/index_cache.db |
LOCAL_STORAGE_PATH |
Storage directory for managed local storage file uploads | /app/data/storage |
PERSISTENT_REPOS_DIR |
Storage directory for retained shallow git clones (keep_shallow) |
/app/data/repos |
AUTH_ENABLED |
Enable MCP 2026-07-28 OAuth 2.1 & API Key RBAC | false |
VECTOR_STORE_PROVIDER |
Vector database backend (pgvector, qdrant, or chroma) |
qdrant |
VECTOR_STORE_MODE |
Vector store mode (embedded or remote) |
embedded |
COLLECTION_NAME |
Vector collection name | knowledge_rag_v1 |
QDRANT_URL |
URL to the remote Qdrant vector database | http://localhost:6333 |
QDRANT_STORAGE_PATH |
Storage directory for embedded Qdrant | /app/data/qdrant_storage |
CHROMA_STORAGE_PATH |
Storage directory for embedded ChromaDB | /app/data/chroma_db |
EMBEDDING_PROVIDER |
Embedding engine (local for in-process ONNX, api for LiteLLM/OpenAI) |
local |
EMBEDDING_MODEL |
FastEmbed dense model name | BAAI/bge-small-en-v1.5 |
SPARSE_MODEL |
FastEmbed sparse BM25 model name | Qdrant/bm25 |
GITHUB_TOKEN |
Optional GitHub Personal Access Token for rate limits & private repos | None |
VAULT_PATH |
Default path to the markdown documentation directory | /docs |
CACHE_DB_PATH |
Path to persistent SQLite cache database | /app/data/index_cache.db |
CHUNK_SIZE |
Maximum character length per chunk | 1500 |
CHUNK_OVERLAP |
Character overlap between consecutive chunks | 200 |
contextcortex/
├── main.py # FastAPI entry point, lifespan manager & FastMCP route mounting
├── app/ # Modular architecture (all files < 450 LOC)
│ ├── api/ # FastAPI REST routers
│ │ ├── routers/ # Dedicated subrouters (repositories, settings, navigator, auth, storage, ingestion)
│ │ ├── routes.py # Main router aggregator and health checks
│ │ └── webhooks.py # Multi-provider webhook endpoint and HMAC validation
│ ├── mcp/ # FastMCP 2.0 dual-transport server
│ │ ├── handlers/ # Modular tool handlers (search, symbol, repo, route, architecture, storage)
│ │ ├── mcp_server.py # FastMCP server lifecycle & session registry
│ │ └── tools.py # Tool registry and handler dispatcher
│ ├── models/ # Pydantic schema validation models
│ │ └── schemas.py # Request/response schemas for APIs and MCP
│ └── services/ # Modular business logic services
│ ├── auth/ # RBAC engine, JWT validator, API key lifecycle, models
│ ├── chunking/ # Tree-sitter loaders, token chunkers, AST/route extractors
│ ├── database/ # Relational schema, engine pool, credential vault, ADRs, sync configs
│ ├── indexing/ # Git/local syncers, file processor, state notifications
│ ├── topology/ # Graph topology builder, node details, BFS helpers
│ ├── vector_store/ # pgvector, Qdrant, and ChromaDB pluggable vector store implementations
│ ├── navigator.py # High-performance codebase tree, outline & impact intelligence
│ ├── omni_search.py # Unified fuzzy command palette search for files, repos, and symbols
│ ├── file_reader.py # Safe full-file source and markdown content resolution from disk
│ ├── local_storage.py# Safe path resolution, disk file persistence, and tree inspection
│ ├── git_manager.py # Shallow git clone (ephemeral & persistent), token masking, permalinks
│ ├── embeddings.py # FastEmbed dense (384d) & sparse BM25 multi-vector engine
│ ├── search.py # Hybrid search & Reciprocal Rank Fusion (RRF) reranker
│ ├── poller.py # Background scheduled repo SHA poller daemon
│ ├── adr.py # MADR / Nygard format ADR ingestion and lifecycle
│ ├── architecture.py# Codebase entry point, language distribution synthesis
│ └── logger.py # In-memory 500-event ring buffer diagnostic logger
├── tests/ # Backend pytest test suite (522+ tests, 88%+ coverage)
│ ├── backend/ # Unit and integration test modules
│ ├── test_navigator_router.py # REST navigator endpoints tests
│ ├── test_navigator_service.py # Tree, outline, and impact service tests
│ ├── test_local_storage_service.py # Path security and local disk storage tests
│ ├── test_local_storage_indexing.py# Real-time incremental vector indexing tests
│ ├── test_mcp_storage_tools.py # manage_local_file and what_is_ingested tests
│ ├── test_storage_api_routes.py # REST storage and ingestion endpoint tests
│ ├── test_auth_service.py # Authentication and API key service tests
│ ├── test_poller.py # Background poller tests
│ └── test_webhooks.py # Multi-provider webhook tests
├── frontend/ # Web Admin Dashboard (React 19, TypeScript, Vite)
│ ├── src/ # React components and modular sub-components
│ │ ├── components/ # Sub-component trees (git/, settings/, topology/, navigator/)
│ │ │ └── navigator/ # NavigatorToolbar, NavigatorTree, NavigatorOutline, NavigatorInspector
│ │ ├── CodeNavigator.tsx # 3-Pane Codebase Navigator main orchestrator
│ │ ├── LocalStorageManager.tsx # Managed storage file explorer and upload modal
│ │ ├── IngestionCatalogViewer.tsx # Unified multi-source ingestion explorer
│ │ ├── styles/ # Modular CSS stylesheets (base.css, components.css, navigator.css)
│ │ └── tests/ # Vitest component unit tests
│ ├── e2e/ # Playwright E2E test specs (26 user journeys)
│ └── dist/ # Compiled production distribution assets
├── requirements.txt # Python dependencies
├── Dockerfile # Container definition with Python 3.11 & Git
├── ARCHITECTURE.md # Deep architectural design specification
├── DEVELOPER_DOCS.md # Local developer setup and test guide
└── docs/
├── REQUIREMENTS.md # Pointer to root Software Requirements Specification
└── TEST_COVERAGE.md # Full test coverage report and metrics breakdown
Connect any MCP client supporting Server-Sent Events (SSE) or Streamable HTTP:
- SSE Stream Endpoint:
http://localhost:3000/sse - Message Exchange Endpoint:
http://localhost:3000/messages/
Example configuration (claude_desktop_config.json / Cursor / Antigravity):
{
"mcpServers": {
"contextcortex-sse": {
"url": "http://localhost:3000/sse",
"headers": {
"Authorization": "Bearer cc_live_your_api_key_here"
}
}
}
}- Streamable HTTP Endpoint:
http://localhost:3000/mcp
Example configuration:
{
"mcpServers": {
"contextcortex-http": {
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer cc_live_your_api_key_here"
}
}
}
}search_code(query="JWT authentication handler", repo="backend-api")[Role:viewer]search_docs(query="caddy reverse proxy configuration")[Role:viewer]find_symbol(name="extract_symbols_and_chunks", exact=true)[Role:viewer]trace_path(target="authenticate_user", repo="backend-api")[Role:viewer]find_routes(repo="backend-api")[Role:viewer]find_api_callers(target="/api/v1/auth/login")[Role:viewer]get_file_outline(filepath="app/services/search.py")[Role:viewer]list_repositories()[Role:viewer]sync_repository(repo="backend-api")[Role:editor]index_status()[Role:viewer]get_architecture(repo="backend-api")[Role:viewer]manage_adr(action="list", repo="backend-api")[Role:editor]manage_local_file(action="upload", file_path="notes/spec.md", content="# Spec")[Role:editorfor mutations,viewerfor read]what_is_ingested(source_type="all", detail_level="summary")[Role:viewer]
knowledge://catalog/summary
search_infrastructure_docs(topic="docker-compose network topology")find_implementation_symbol(symbol="execute_hybrid_search")
| Resource / Operation | HTTP Endpoint | MCP Tool | Required Role |
|---|---|---|---|
| List / Search API Keys | GET /admin/api/auth/keys |
- | Role.ADMIN |
| Create / Revoke API Keys | POST/DELETE /admin/api/auth/keys |
- | Role.ADMIN |
| Upload Local Storage File | POST /admin/api/storage/upload |
manage_local_file (upload) |
Role.EDITOR |
| Replace Local Storage File | PUT /admin/api/storage/file |
manage_local_file (replace) |
Role.EDITOR |
| Delete Local Storage File | DELETE /admin/api/storage/file |
manage_local_file (delete) |
Role.EDITOR |
| Read Local Storage File | GET /admin/api/storage/file |
manage_local_file (read) |
Role.VIEWER |
| Browse Storage Directory Tree | GET /admin/api/storage/tree |
- | Role.VIEWER |
| Query Ingestion Catalog | GET /admin/api/ingestion/catalog |
what_is_ingested |
Role.VIEWER |
| Repository Navigator Tree | GET /admin/api/navigator/tree |
- | Role.VIEWER |
| File Symbol Outline | GET /admin/api/navigator/file-outline |
- | Role.VIEWER |
| Symbol Impact Intelligence | GET /admin/api/navigator/symbol-impact |
- | Role.VIEWER |
| Sync Git Repository | POST /admin/api/repositories/{id}/sync |
sync_repository |
Role.EDITOR |
| Manage ADRs | - | manage_adr (create/update) |
Role.EDITOR |
| Code & Document Searches | POST /admin/api/search |
search_code, search_docs |
Role.VIEWER |
The frontend architecture implements a modular 3-pane layout under frontend/src/components/navigator/:
CodeNavigator.tsx: Primary container handling repository selection state, file selection state, symbol selection state, and density modes (Compact,Balanced,Spacious).NavigatorToolbar.tsx: Top bar with repository dropdown selector, total file/symbol metric badges, layout density toggles, and reindexing status.NavigatorTree.tsx: Left pane rendering hierarchical directory/file tree with symbol and route count badges, debounced search filtering, expand/collapse all controls, and keyboard selection.NavigatorOutline.tsx: Middle pane rendering file-scoped AST symbols, category chips (All,Functions,Classes,Routes), signature badges, and line number indicators.NavigatorInspector.tsx: Right pane rendering symbol details, 4-metric summary grid (callers, callees, imports, scope), API route mapping cards, signature code blocks, docstrings, interactive relationship click-through cards, and copy permalink actions.
- Query Parameters:
repo(optional, string, defaults to__all__). - Response (
200 OK):{ "repo": "__all__", "total_files": 42, "total_symbols": 380, "tree": [ { "id": "dir:app", "name": "app", "is_dir": true, "path": "app", "symbol_count": 210, "route_count": 18, "children": [ { "id": "file:app/api/routes.py", "name": "routes.py", "is_dir": false, "path": "app/api/routes.py", "language": "python", "symbol_count": 12, "route_count": 4 } ] } ] }
- Query Parameters:
filepath(required, string),repo(optional, string). - Response (
200 OK):{ "repo": "contextcortex-core", "filepath": "app/api/routers/chat.py", "language": "python", "symbols": [ { "id": 101, "name": "chat_completion_endpoint", "full_symbol": "app.api.routers.chat.chat_completion_endpoint", "kind": "function", "start_line": 45, "end_line": 85, "signature": "async def chat_completion_endpoint(request: ChatCompletionRequest) -> ChatCompletionResponse:", "route": { "http_method": "POST", "path_pattern": "/v1/chat/completions", "framework": "FastAPI" } } ] }
- Query Parameters:
symbol_id(optional, integer) orname+filepath(strings). - Response (
200 OK):{ "symbol": { "id": 101, "name": "chat_completion_endpoint", "full_symbol": "app.api.routers.chat.chat_completion_endpoint", "kind": "function", "filepath": "app/api/routers/chat.py", "start_line": 45, "end_line": 85, "signature": "async def chat_completion_endpoint(request: ChatCompletionRequest) -> ChatCompletionResponse:", "docstring": "Processes OpenAI-compatible chat completion requests.", "language": "python", "repo": "contextcortex-core" }, "route": { "http_method": "POST", "path_pattern": "/v1/chat/completions", "framework": "FastAPI" }, "callers": [ { "id": 501, "source_symbol_id": 301, "source_filepath": "tests/e2e/test_chat.py", "source_symbol": "test_chat_completions_e2e", "target_symbol": "chat_completion_endpoint", "relationship_type": "CALLS", "line_number": 28 } ], "callees": [], "imports": [] }
- Multipart Form:
file(binary),path(relative target path), optionalrepo(default"local_storage"), optionalcategory. - JSON Payload:
{ "path": "rfcs/caching-v2.md", "content": "# RFC: Caching Architecture v2\n\nDesign notes...", "repo": "local_storage", "category": "rfcs" } - Response (
200 OK):{ "status": "success", "rel_path": "rfcs/caching-v2.md", "repo": "local_storage", "category": "rfcs", "size_bytes": 1240, "chunks_indexed": 3 }
- JSON Payload:
{ "path": "rfcs/caching-v2.md", "content": "# Updated RFC: Caching Architecture v2\n\nRevised design...", "repo": "local_storage", "category": "rfcs" } - Response (
200 OK):{ "status": "success", "rel_path": "rfcs/caching-v2.md", "repo": "local_storage", "size_bytes": 1410, "chunks_indexed": 4 }
- Query Parameters:
source_type(all|git|monitored_path|local_storage),repo_name,path_prefix,file_extension,detail_level(summary|detailed). - Response (
200 OK):{ "source_type": "all", "detail_level": "summary", "git_repositories": [ { "id": 1, "name": "contextcortex", "url": "https://github.com/spelech/contextcortex", "branch": "main", "commit_sha": "a7c8950...", "provider": "github", "status": "synced", "file_count": 42 } ], "monitored_paths": [], "local_storage": { "root_path": "/app/data/storage", "file_count": 5, "tree": { "root": "/app/data/storage", "current_folder": "", "directories": [{"name": "rfcs", "rel_path": "rfcs", "abs_path": "/app/data/storage/rfcs"}], "files": [{"name": "spec.md", "rel_path": "rfcs/spec.md", "abs_path": "/app/data/storage/rfcs/spec.md", "size_bytes": 1024, "mtime": 1724800000.0}] } }, "files": [] }