corelore
v0.4.0
Published
Your team's lore, with receipts — point Corelore at any folder of markdown and agents get accurate, cited, freshness-aware answers over MCP. Local-first, zero config.
Maintainers
Readme
Corelore
Your team's lore, with receipts. Point Corelore at any folder of markdown and your AI agents get accurate, cited, freshness-aware answers over MCP — then keep them accurate with golden-question tests in CI.
Zero config. Zero new files in your folder. Local-first: after a one-time model download, nothing you index or ask ever leaves your machine.
npx corelore serve ./docs # MCP server on stdio, ready for any agent
# or, for Claude Code, one line:
claude mcp add corelore -- npx corelore serve /absolute/path/to/your/docsFirst run downloads two ONNX models (~130MB embedding + ~23MB reranker — announced, one-time, cached). After that Corelore runs fully offline; set
CORELORE_OFFLINE=1to enforce it.
Why this exists
Ask a typical quickstart-RAG stack "Which table should I use for order data?" over a realistic internal KB and it confidently returns the deprecated legacy table first. Corelore returns the canonical table first — and still shows the legacy one, flagged:
$ corelore ask ./benchmark/corpus "Which table should I use for order data?"
#1 tables/orders.md > Overview
[status: active | date: 2026-06-20 (29d old)]
This is the canonical source for order data. It replaced the legacy pipeline…
#4 tables/orders_legacy.md > Overview ⚠ DEPRECATED
[status: deprecated]
⚠ DEPRECATED — do not use for new work; kept for historical referenceDeprecated and stale content is flagged in-band (machine-readable deprecated: true + human ⚠) and rank-penalized — never silently served, never silently hidden.
The four commands
| | |
|---|---|
| corelore serve <dir> | Zero-config MCP server (stdio). Tools: search_knowledge (cited retrieval), get_concept (one doc in full), list_map (table of contents). Add --watch to auto-reindex as files change (long-running servers stay current). |
| corelore ask <dir> "<q>" | Same engine from the terminal. |
| corelore status <dir> | Knowledge hygiene: stale docs (>180d), broken links (incl. [[wikilinks]]), orphans, deprecated-but-still-linked. --strict exits 1 for CI. |
| corelore eval <dir> | Golden-question tests (below). |
Test your knowledge like you test your code
# evals/core.yaml
- q: Which table should I use for order data?
cites: [tables/orders.md]corelore eval ./docs # ✓/✗ per question, exit 1 on any failure
corelore eval ./docs --update-baseline # commit evals/baseline.json
# in CI: a PR that edits docs and breaks an answer fails with "⚠ N newly failing since baseline"Deterministic by design — a question passes iff every doc in cites appears in the production top-k. No LLM judge, no flaky scores, no API key.
Don't want to hand-write 25 questions? corelore eval init ./docs drafts them from your docs with an LLM, and corelore eval approve walks you through them one keypress at a time — nothing becomes a live eval without your yes. The default provider is NVIDIA NIM, which runs on free trial credits that eventually run out; for a durably-free, fully-local path (nothing leaves your machine) use --llm ollama. Any OpenAI-compatible endpoint works via --llm-base-url. Want to check answer quality, not just retrieval? corelore eval ./docs --grounded adds an opt-in LLM-judged Grounded Accuracy score (report-only unless you set --grounded-gate). Full guide, including the public-claim floor and judge-audit protocol: EVALS.md.
Knowledge CI: drop this into a workflow to fail PRs that break an answer —
- uses: corelore/[email protected]
with:
path: ./docs
baseline: docs/evals/baseline.jsonFrontmatter conventions (all optional)
Plain markdown works with zero frontmatter. Add these fields when you want the extra behavior:
| Field | What Corelore does with it |
|---|---|
| status: deprecated | Flags every chunk in-band + rank-penalizes the doc — the headline feature |
| verified_at: 2026-06-01 | Shown as date/age on citations; drives staleness (>180d) in status |
| review_after: 2026-09-01 | Past date ⇒ flagged stale in status (wins over verified_at) |
| owner: data-team | Shown on citations — who to ask |
| title, type, description | Woven into each chunk's retrieval context (measurably better ranking) |
No fields at all? Staleness falls back to file mtime; docs are served normally. Obsidian [[wikilinks]] resolve case-insensitively by title or filename.
When NOT to use Corelore
Honesty section. If your docs are a small folder inside the repo your agent already works in, Claude Code's own file search is often good enough — try that first. Corelore earns its keep when: the corpus is big enough that agentic grep gets slow and spotty; the knowledge lives outside the working repo (a vault, a wiki-export, another repo); multiple agents/tools need one consistent knowledge source; you need guarantees (deprecation flags every time, not most times) and numbers (eval in CI) instead of vibes. Also: input is markdown folders only — no Confluence/Notion connectors (export to markdown first).
How it works & the benchmark
Heading-scoped chunks with frontmatter breadcrumbs → hybrid retrieval (in-house BM25 + local bge-small-en-v1.5 embeddings via transformers.js) → reciprocal-rank fusion → cross-encoder rerank (--no-rerank to disable). Index cache in ~/.cache/corelore/<corpus-hash>/, all models in ~/.cache/corelore/models (override with --model-dir). Indexing is incremental: editing a doc re-embeds only the chunks that changed (a content-addressed embedding cache reuses the rest), so re-indexing after an edit is near-instant even on large corpora. First-time and full indexing use length-aware batching (chunks are grouped by length so padded compute isn't wasted on mixed-length docs) — measured ~1.3–1.8× faster with byte-identical results.
Reproducible 30-doc / 36-question benchmark ships in-repo (npm run bench; integrity rules in benchmark/BENCHMARK.md):
| pipeline | fail% | recall | lookup | multihop | warm p50* | |---|---|---|---|---|---| | naive dense RAG (reference impl) | 22.2 | 87.0% | 4.2 | 55.6 | — | | Corelore default | 8.3 | 96.3% | 0.0 | 22.2 | 130–180ms |
* Apple-silicon laptop, models cached. Reference implementation: pip install rank_bm25 fastembed numpy && python3 benchmark/reference/corelore_proto.py experiment benchmark/corpus benchmark/evals.json.
Troubleshooting
- First
search_knowledgecall is slow (~30s): that's the one-time model download + cold index;initializeresponds instantly and everything after is fast. Pre-warm withcorelore ask <dir> "test"if you prefer. - Corporate proxy / air-gapped: model downloads don't honor
HTTPS_PROXYyet. Pre-seed from a machine with access: copy~/.cache/corelore/models, then run withCORELORE_OFFLINE=1. - "cannot read " — the path isn't a directory of markdown; Corelore indexes
*.mdrecursively (symlinks are skipped, with a warning). - Serving untrusted content? Read SECURITY.md first — prompt injection is inherent to serving text to agents; trust the structured fields, not the prose.
Why there is no corelore export
Your folder already is the format. Corelore writes nothing into it (except the explicit eval baseline) and keeps no proprietary state — delete ~/.cache/corelore/ and you lose nothing but a rebuildable index. Lock-in is architecturally impossible.
Privacy, license, requirements
Telemetry is opt-in, content-free, and off by default — locally auditable, uploader disabled; see TELEMETRY.md. Node ≥ 20. Apache-2.0.
