Standalone hybrid retrieval + routing server: LanceDB, fastembed, cross-encoder reranker, FastAPI
Project description
archon-search
A standalone hybrid retrieval and routing server.
Overview
archon-search is a self-contained search service built around:
- LanceDB as the local vector store
- fastembed for dense embeddings
- A cross-encoder reranker for second-stage scoring
- A multi-collection router that picks which collections to query for a given prompt
- FastAPI for the REST control plane (with an OpenAPI 3.x contract)
- An MCP endpoint exposing the same control-plane tools to MCP clients
It runs as its own process, persists indexes and configuration under ~/.archon-search/, and exposes both an HTTP API and an MCP API over the same authentication layer.
Installation
pip install archon-search
archon-search wizard
After pip install, run archon-search wizard to complete setup. The wizard lets you choose a profile (minimal, balanced, or max), downloads the matching embedding and reranker models, and registers the server as a background service. See Documentation/UserManual/01_installation.md for the full profile comparison table, flag reference, and disk-space requirements.
Or, for a checkout-based development install:
git clone https://github.com/user538295/archon-search.git
cd archon-search
uv sync --dev
Quick start
Run the server:
archon-search
This invokes the archon_search.cli.main:main entry point declared in pyproject.toml and starts the FastAPI app on the configured host/port (default http://127.0.0.1:8765).
Once it is running:
GET /health— unauthenticated liveness probeGET /docs— interactive Swagger UIGET /openapi.json— machine-readable OpenAPI schema
Hit the search endpoint:
curl -X POST http://127.0.0.1:8765/search \
-H "Authorization: Bearer $ARCHON_SEARCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"collection": "docs", "query": "how does the router work?"}'
Authentication
All endpoints except GET /health require a Bearer token in the Authorization header.
On first start, the server auto-generates a key and writes it to ~/.archon-search/.search.env with permissions 600. To override (Docker, CI, multi-host), set the ARCHON_SEARCH_API_KEY environment variable — it takes priority over the file. To point the server at a different key file, set ARCHON_SEARCH_KEY_FILE.
Configuration
Server-side configuration lives in ~/.archon-search/archon-search.toml. Notable sections:
[database]—db_path,embedding_model,chunk_size,top_k_return, model paths, and per-collection embedder pool keys:embedder_cache_size(int, default3) controls how many embedding model instances are kept in the LRU cache;eager_load_embedders(bool, defaultfalse) pre-warms all distinct models at startup[search]— multi-collection fan-out bounds (max_fanout,fanout_timeout_seconds)[routing]—routing_shortlist_size,routing_confidence_threshold, routing strategy[collections]—pinned_collections, static collection definitions, watcher settings[telemetry]— opt-in local query logging (see below)
See examples/archon-search.toml.example in the repo for the full annotated reference.
REST API
The REST surface is formally contracted via OpenAPI. GET /openapi.json is the authoritative machine-readable schema for endpoint shapes, request/response types, and error codes; GET /docs serves the interactive explorer.
Breaking changes to the REST or MCP surface are recorded in BREAKING.md.
MCP tools
The MCP server registers 11 tools (see archon_search/server/mcp.py), sharing the REST API's auth layer:
search— hybrid vector + FTS search; returns{"results": [...], "acl_filtered": bool}search_with_context— same assearchwith adjacent-chunk contextexplain— per-stage retrieval/reranking trace plus routing decision (mirrorsPOST /explain)ingest_file— index a single file into a collectioningest_directory— recursively index a directorylist_collections— list collection namesget_collections_meta— metadata for all collectionsget_collection_meta— metadata for one collectionlist_documents— list documents in a collectiondelete_document— remove a document bydoc_idupdate_collection— change a collection's embedding model (mirrorsPATCH /collections/{name})
Telemetry (opt-in)
Query telemetry is opt-in and disabled by default (enabled = false). When enabled, every search, search_with_context, and POST /route call appends one JSONL line to a daily file under ~/.archon-search/search-logs/. No data is transmitted externally — all files stay on the local machine.
Enabling
# ~/.archon-search/archon-search.toml
[telemetry]
enabled = true
retention_days = 30 # files older than this are deleted at startup and every 24h
log_dir = "~/.archon-search/search-logs"
What is logged
Each entry is a JSON object containing: query_id (random UUID), timestamp (UTC), endpoint, latency_ms, status, and endpoint-specific fields (collection, result_count, result_doc_ids for retrieval; collections, decomposer_invoked for routing). Error entries add error_kind, a closed set: empty_query | slot_out_of_range | timeout | internal_error | validation_error | other.
What is never logged
The raw query string is never recorded. This is a structural guarantee: the factory methods that construct telemetry entries do not accept a query parameter. Exception messages are not logged either — only the coarse error_kind string enters the JSONL line.
Path-derived doc_id risk
result_doc_ids are derived from the source file path on disk (e.g. /Users/<name>/Documents/<project>/<file>.md). When telemetry is enabled, these paths appear in the log files — doc_ids may reveal filesystem paths, including username and directory structure. Operators accept this when they opt in. A hashed-doc-id mode is planned for a future release.
export_enabled is not available
[telemetry].export_enabled = true is reserved for a future release and is not implemented in v1. If set to true, the config loader logs a warning and silently coerces the value to false (see archon_search/config.py). No external transmission occurs in v1.
Telemetry read-back API
Both endpoints return {"enabled": false} when telemetry is disabled.
GET /telemetry/stats
Aggregated query statistics over an optional time window.
| Parameter | Type | Description |
|---|---|---|
since |
YYYY-MM-DD | Start date (inclusive, optional) |
until |
YYYY-MM-DD | End date (inclusive, optional) |
Response shape summary:
{
"schema_version": 1,
"enabled": true,
"total_queries": 42,
"success_rate": 0.95,
"latency_ms": {"p50": 120, "p95": 380},
"by_endpoint": {"search": 30, "route": 12},
"by_collection": {"docs": 25, "code": 17},
"error_breakdown": {"timeout": 2, "internal_error": 0}
}
success_rate is null when no queries exist in the window.
GET /telemetry/entries
Paginated raw log entries.
| Parameter | Type | Description |
|---|---|---|
since |
YYYY-MM-DD | Start date (optional) |
until |
YYYY-MM-DD | End date (optional) |
collection |
string | Filter by collection name (optional) |
endpoint |
string | Filter by endpoint (optional) |
status |
string | Filter by status (optional) |
error_kind |
string | Filter by error kind (optional) |
offset |
int | Pagination offset, default 0 |
limit |
int | Page size, 1–200, default 50 |
Response includes entries, next_offset, and total_in_window. Clients should continue calling with the returned next_offset until entries is empty (equivalently, until next_offset >= total_in_window).
Evaluation harness
tests/eval/ hosts an offline evaluation harness: a synthetic retrieval corpus, query/label fixtures, deterministic eval backends, committed thresholds, and a measured baseline. It is the sanctioned regression gate for retrieval, reranking, routing, and latency changes.
The authoritative maintenance guide — fixture schemas, threshold-lowering rationale policy, waiver workflow, and document-level metric semantics — lives at tests/eval/README.md.
The PR and release eval command is:
uv run pytest -m eval --thresholds-path tests/eval/thresholds.toml tests/eval/test_eval_suite.py
The harness uses deterministic eval backends that are corpus-aware but label-blind so retrieval and reranking metrics are stable across runs without pulling real model weights. Latency p50/p95 is captured as a regression guard only — the measured values reflect the deterministic backends and are not production SLAs.
Current measured baseline values (recall@k, MRR, nDCG@k, reranker lift, routing accuracy, latency percentiles) are recorded in tests/eval/baselines/baseline.md with the machine-readable companion in tests/eval/baselines/baseline.json.
Development
git clone https://github.com/user538295/archon-search.git
cd archon-search
uv sync --dev
uv run pytest
License
See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file archon_search-26.6.710.tar.gz.
File metadata
- Download URL: archon_search-26.6.710.tar.gz
- Upload date:
- Size: 1.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d414980b924a7f64a36675e9c5c1c153818df7295928418c8f8cc7b2e7f6873
|
|
| MD5 |
8f260de208fccc9d94fe6651612a4974
|
|
| BLAKE2b-256 |
483190cbcd639f46d04e7e886ea602241f4a21d3f04c7ab0fa19ff079d2a9ded
|
Provenance
The following attestation bundles were made for archon_search-26.6.710.tar.gz:
Publisher:
archon-search-release.yml on user538295/archon-search
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
archon_search-26.6.710.tar.gz -
Subject digest:
8d414980b924a7f64a36675e9c5c1c153818df7295928418c8f8cc7b2e7f6873 - Sigstore transparency entry: 1706194000
- Sigstore integration time:
-
Permalink:
user538295/archon-search@daa3ae37fb424f4e624e42a5c71ab7304ee2c60a -
Branch / Tag:
refs/tags/26.6.710 - Owner: https://github.com/user538295
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
archon-search-release.yml@daa3ae37fb424f4e624e42a5c71ab7304ee2c60a -
Trigger Event:
push
-
Statement type:
File details
Details for the file archon_search-26.6.710-py3-none-any.whl.
File metadata
- Download URL: archon_search-26.6.710-py3-none-any.whl
- Upload date:
- Size: 190.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
070fc7e7baf48607b94a4807d290050bab2f8cad95f1ca3817acba2402674167
|
|
| MD5 |
00caaa6cdbc20947ddeea3ffebc1aadd
|
|
| BLAKE2b-256 |
5be4555cbc69db1f7300e7fdb093b2890d5038b7590058cfde5f3eb3eafc58d1
|
Provenance
The following attestation bundles were made for archon_search-26.6.710-py3-none-any.whl:
Publisher:
archon-search-release.yml on user538295/archon-search
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
archon_search-26.6.710-py3-none-any.whl -
Subject digest:
070fc7e7baf48607b94a4807d290050bab2f8cad95f1ca3817acba2402674167 - Sigstore transparency entry: 1706194044
- Sigstore integration time:
-
Permalink:
user538295/archon-search@daa3ae37fb424f4e624e42a5c71ab7304ee2c60a -
Branch / Tag:
refs/tags/26.6.710 - Owner: https://github.com/user538295
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
archon-search-release.yml@daa3ae37fb424f4e624e42a5c71ab7304ee2c60a -
Trigger Event:
push
-
Statement type: