The API is rooted at /api/v1. OpenAPI and interactive docs are enabled in development and
disabled by the production Compose configuration. Every response includes X-Request-ID.
Errors use one envelope:
{"error":{"code":"http_404","message":"Repository not found","request_id":"..."}}Validation errors add a structured details list. 429 includes Retry-After and 413 indicates
a configured request/repository resource bound.
GET /api/v1/health/live checks only that the process can serve requests.
GET /api/v1/health/ready (also aliased by /health) checks PostgreSQL and Qdrant. A ready response is:
{"status":"ok","database":"ok","vector_database":"ok"}POST /api/v1/repositories validates and records one canonical public GitHub URL:
{"github_url":"https://github.com/pypa/sampleproject"}URLs must use HTTPS, use the exact github.com host, identify one owner/repository, and contain no credentials, query, or fragment. Invalid input returns 422; a duplicate owner/repository returns 409.
GET /api/v1/repositories/{repository_id} returns current repository status (submitted, ingesting, ready, or failed) and any ingestion error.
POST /api/v1/repositories/{repository_id}/ingestion-jobs returns 202 with a durable job. Poll
GET /api/v1/repositories/{repository_id}/ingestion-jobs/{job_id} until succeeded or failed.
The successful job includes snapshot_id; the failure includes a bounded diagnostic. Posting while
the repository already has a queued/running job returns that active job. A full configured global
queue returns 503 with Retry-After.
POST /api/v1/repositories/{repository_id}/ingestions remains as a deprecated synchronous
compatibility endpoint. Snapshot responses contain:
- branch and full commit SHA;
- ingestion status and error;
- parsed, malformed, and skipped file counts;
- reused, newly processed, and removed file counts;
- symbol/import counts and total accepted bytes.
The same completed commit is returned idempotently. Acquisition failures return 422; configured resource-limit failures return 413. Unexpected failures return 500 after repository/snapshot failure status is persisted.
GET /api/v1/repositories/{repository_id}/snapshots lists snapshot history newest first.
All collection endpoints accept bounded limit and offset parameters.
GET /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/filesGET /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/files/{file_id}GET /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/symbolsGET /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/imports
The file-detail endpoint includes source content. Symbol queries optionally accept exact kind (module, class, function, or method) and name filters. Every symbol/import includes its source-file path and available line range.
POST /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/retrieval-index builds the
snapshot's vector and lexical index. It accepts optional refresh=true; otherwise a compatible
ready index is reused. GET on the same path reports its lifecycle and unit count.
POST /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/search accepts:
{"query":"where is authentication checked?","mode":"hybrid","limit":10,"symbol_kind":"function"}mode is lexical, semantic, or hybrid; optional filters are filepath, filepath_prefix,
symbol_kind, and language. Evidence contains snapshot identity, code/path/line range, symbol
metadata, available score components, and a GitHub link pinned to its commit. An unindexed
snapshot returns 409.
Ingestion builds deterministic graph relationships automatically. Existing snapshots can be backfilled or rebuilt idempotently with:
POST /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/graphGET /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/graph
The summary reports module, symbol, and import counts plus resolved, unresolved, and ambiguous import totals. Controlled lookup endpoints are:
GET .../graph/modules/{module_id}/symbolsGET .../graph/modules/{module_id}/importsGET .../graph/modules/{module_id}/importersGET .../graph/symbols/{symbol_id}/containment
Module IDs are source-file IDs. Import results always include resolution status, requested module, candidate paths, a human-readable reason, source line range, and an optional resolved target. Importers contain only uniquely resolved internal module relationships. All IDs are validated against the repository snapshot in the route.
POST /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/investigations runs one bounded
investigation against a ready snapshot:
{"question":"How is the greeting implemented and which module contains it?"}The response contains the validated plan, grounded answer, commit-pinned citations, observable tool
trace, number of investigation rounds, and termination reason (completed, max_steps, or
no_more_tools). A failed tool is represented in the trace while other calls continue. Invalid
model output or an exhausted configured provider path returns 502; a non-ready snapshot returns
409. Successful investigation responses include model_runs with provider, model, duration,
success/fallback state, and optional token usage.
The intended default provider is Gemini (REPOLENS_LLM_PROVIDER and REPOLENS_LLM_MODEL), with
Groq as one configured fallback. OpenRouter and Ollama are optional selections. Provider calls and
credentials remain server-side. Retrieval must already be indexed for search_code; otherwise that
tool fails transparently and the model may continue with symbol, source, graph, or metadata tools.
POST /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/queries classifies clear query shapes with deterministic rules before using existing controlled capabilities:
{"question":"What commit was indexed?"}The response includes routing (category, strategy, confidence, fallback_applied, router, and rationale), answer, citations, and tool trace. Simple metadata, symbol, and retrieval queries may avoid the investigation model. Dependency, security, ambiguous, and unmatched questions use the bounded cloud investigator.
GET /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/dependenciesreturns manifest-derived inventory and provenance.version_resolved=falsemeans the declaration was not one exact pin and therefore was not queried as an installed version.POST /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/vulnerability-scanqueries OSV for exact versions. Add?refresh=trueto bypass successful cached checks.GET /api/v1/repositories/{repository_id}/snapshots/{snapshot_id}/vulnerabilitiesreturns persisted OSV findings with package version, OSV ID, aliases, severity, affected data, references, source URL, and query time.
OSV failures are recorded per dependency and do not erase older findings. A returned vulnerability is a public-source package/version match, not a claim that the application is reachable or exploitable.
GET /api/v1/evaluations/results returns bounded, read-only summaries of valid JSON reports in the
configured evaluation results directory. Summaries contain dataset identity/hash, embedding and
retrieval configurations, Recall@K, citation metadata correctness, routing/symbol/tool accuracy,
latency, comparisons, unsupported experiments, and the explicitly separate model-assisted section.
Malformed or oversized report files are skipped and logged.