Changelog¶
Notable changes to sci-rag-kit. The format follows Keep a Changelog; versions follow Semantic Versioning once past 1.0.
[Unreleased]¶
Added¶
sci-rag draft questions: an assisted first pass atdomain/eval_seed_questions.jsonl, grounded in the documents you already have. It prefers the ingested corpus and falls back to readingdata/raw/through the same parsers, so it works beforemake setup. Every quoted evidence phrase is verified in Python against a passage belonging to a document the question names; rows that fail are dropped and reported by id and reason, with one repair round. A run proposeseval_seed_questions.jsonl.proposed;--applyappends to the seed file and never displaces a question a human wrote.- Two lanes on every drafter.
--print-promptwrites the fully rendered, corpus-grounded prompt to stdout for pasting into any assistant, and--from-filereads the reply back through identical validation, so the drafters work with no API key and no provider account. domain/prompts/seed_questions.md: the prompt behind that draft, with$DOMAIN_NAME,$ENTITY_TYPES,$QUERY_CLASSES,$PASSAGES,$COUNT, and$REJECTEDslots.- The
draftedtag on seed questions, and the honesty plumbing behind it.sci-rag eval retrievalandsci-rag eval answersnow warn in the generated Markdown when any question behind the numbers is still model-drafted, and both report payloads carry"ground_truth": {"drafted": N, "reviewed": M}. Removing the tag is the expert sign-off; nothing in the kit removes it for you. docs/llm-assisted-setup.md: the three lanes, the copy-paste path, the review discipline, and the honesty rules for drafted ground truth.sci-rag draft manifest: reads title, authors, year, DOI, journal, and a source bucket off each document's opening pages, through the same parsers ingestion uses, and proposesdata/corpus.jsonl.proposed. Source buckets are chosen across the whole batch rather than one per file.license_classis never guessed: every drafted row is writtenunknown, the command reports how many documents need a rights decision, and a license sentence is kept inlicense_sourceas evidence only, and only when it appears verbatim in the document.sci-rag draft ontology:--from-corpusredrafts the ontology from real passages,--refineasks only for additions and removals with a reason for each, and--coldis the wizard's description-only draft on its own. The tunedretrieval:andcompression:blocks are carried over untouched, and a refinement that would leave no entity type is rejected. Writesdomain/domain.yaml.proposedwith a summary diff;--applywrites in place.domain/prompts/manifest_metadata.mdanddomain/prompts/ontology_from_corpus.md.sci-rag draft prompts: rewordsentity_extraction.mdoranswer.mdfor your field while keeping the job identical. The rewrite is re-rendered against dummy values and rejected if a required$SLOTwent missing, if one was invented, or if the template will not render.judge_grounding.md,judge_correctness.md,snippet_compression.md, andontology_draft.mdare refused by name, each with a reason. New promptdomain/prompts/prompt_localization.md.- Domain-coherence rows in
sci-rag doctor: ontology size, unique names and SCREAMING_SNAKE relations; seed questions that cite nothing and seed sets with nounanswerableprobe; how many questions are still taggeddrafted; whether every reference title resolves to an ingested document; and manifest paths that no longer exist plus a count of rows with unknown rights. - One new
sci-rag initquestion,draft_domain_files, asked only when the project has credentials. It decides whether the next-steps block leads with the drafters or with the hand-written route.
Changed¶
docs/bring-your-own-domain.mdsteps 2, 3, 4 and 6 are now Generate it / Write it yourself tab pairs. The generated route goes first; the full schema for every file stays underneath, unchanged.- The next-steps blocks in
scripts/init_domain.pyandsci-rag initnamesci-rag draft ...instead of telling you to go hand-write four files. AGENTS.mdtells a coding agent pointed at a generated project to runsci-rag draft ... --print-promptrather than authoring domain YAML from scratch.- The rendered-geometry guard ignores zero-height wrappers. Two inactive tab panels in a row sit at the same point, which it read as a zero-pixel gap between blocks a reader can never see at the same time.
[0.3.0] - 2026-08-28¶
The "Campaigns" release: the kit gets the parts that make it better for science than a general-purpose RAG framework, plus an interactive project factory so starting one is two commands instead of a seven-step tutorial.
Two features ship switched off, on purpose. Contextual compression cut
median prompt tokens by 70% but every judged dimension moved down, so its
paired gate did not hold (#90). Entity resolution finds nothing to merge on
the demo corpus, so its ablation cannot be measured here. Both are in
docs/benchmarks.md with the numbers.
Added¶
sci-rag init: an interactive setup wizard that specializes a checkout for your own domain. Asks about the project, credentials and models, ontology, corpus source, PDF parser, reranker, license, and stack, then writesdomain/domain.yaml,.env,pyproject.toml, theMakefile,README.md, and the corpus scaffold.--defaultsand--answers-filemake generation reproducible;--dry-runpreviews it. The ontology can be drafted by the configured model and is validated againstDomainConfigbefore anything is written, so a malformed draft is rejected rather than saved as unusable YAML.domain/prompts/ontology_draft.md: the prompt behind that draft.- Multi-provider generation.
SCI_RAG_LLM_MODELand friends now accept aprovider:modelspec selectinggoogle,anthropic(Claude on Vertex AI or the direct API), oropenai-compatible(Vertex Model Garden partner models such as Grok, Llama, Mistral, and DeepSeek; also OpenAI and self-hosted vLLM/Ollama). Newanthropicandopenaiextras; the SDKs are imported lazily so a Google-only install carries neither. See ADR 0006 for why the adapters are hand-written and why embeddings stay Google-only. SCI_RAG_JUDGE_MODEL, so the evaluation judge can run on a different provider than the generator. Answer eval reports now record which model answered and which graded, making cross-provider judging auditable.-
sci-rag doctorreports the resolved spec per role and checks credentials for each generation provider in use. -
Environment manager choice in the wizard: pixi, conda, and venv+pip alongside uv. One
RunnerProfilerenders all five uv-wired surfaces (task commands, CI, Dockerfile, dev container, docs), writes whatever manifest that manager needs ([tool.pixi]tables orpixi.toml,environment.yml,requirements.txtplusrequirements-dev.txt), and is the only place a manager-specific string lives. -
generated-projects.yml: a CI matrix that generates a project per manager and runs that project's own lint, typecheck, and offline demo. uv runs on every pull request; all four run nightly, on release tags, and on any pull request that changes what a generated project looks like. -
sci-rag-new: the project factory as its own entry point. Runs from a parent directory with nothing cloned, fetches the template at the tag matching its own installed version, then applies the wizard's answers.--template-pathgenerates from a local checkout with no network, and--refoverrides the tag. The LLM ontology draft is offered here and insci-rag init, with accept, reject, and redraft. -
.github/workflows/release.yml: tag-driven publishing to TestPyPI and then PyPI over Trusted Publishing, gated on theciworkflow having passed for the tagged commit and on the tag matching the packaged version. The one-time maintainer setup is indocs/VERSIONING.md. -
The documentation homepage leads with
pipx install sci-rag-kitandsci-rag-new, and shows the session in a player. The transcript below it is generated by driving the real wizard (make cast), so it cannot drift from the questions;make docsfails when it is stale. The asciinema player is vendored underdocs/assets/vendor/, not loaded from a CDN, which keeps the docs build hermetic and the offline link check honest. -
docs/adr/0007-interactive-project-generator.md: why the generator is a post-fetch applier rather than a template renderer, and how that implements the escape hatch ADR 0004 left open instead of overturning it. -
A Docker-free database for pixi and conda projects. Those two managers read conda-forge, which ships the PostgreSQL server and pgvector as ordinary packages, so their generated manifests declare
postgresql >=16,<19andpgvector, and theirmake setupstarts that server instead of a container.scripts/local_postgres.pydrivesinitdbandpg_ctlagainst a project-local.pgdata/, producing a database the unmodified.env.examplealready points at. uv and venv+pip keep Docker: PyPI ships no server, and a manager that cannot take the path does not advertise it. .github/workflows/docker-free-postgres.yml: the integration and server suites against a conda-forge server on linux-64 and osx-arm64, failing if the suite skips rather than runs. Withci.ymlon PostgreSQL 16 and this on 18, both ends of the supported range are tested.docs/adr/0008-supported-postgresql-versions.md: why the project supports a range instead of moving everyone to one major.
Changed¶
-
Supported PostgreSQL versions are now stated and tested: 16 through 18. Nothing moves. Compose and the CI service stay on the
pgvector/pgvector:pg16image, and no existing database needs a migration. The schema uses no pgvector feature newer than 0.5 and no version-specific SQL, so the 16 in this repository was three container image tags rather than a requirement. -
Generated projects no longer carry the kit's own onboarding. The pipx instructions, the recorded session, the vendored player, and the renderer that keeps it current are all removed, along with their entries in
mkdocs.ymland theMakefile, so a generated project's documentation still builds. docs/bring-your-own-domain.mdopens with what the wizard asked and where each answer landed, then keeps the by-hand walkthrough for people who want to know what it chose for them.docs/tour.md,docs/deploy-gcp.md,README.md, anddocs/benchmarks.mdsay which pieces the wizard can decline, instead of describing directories a generated project may not have..envnow reaches the process environment. pydantic-settings reads it intoSettingsbut never exported it, so Typer'senvvar=lookups and theOPENALEX_API_KEYread insci-rag campaign discovercould not see values placed there. A real environment variable still wins over the file.-
scripts/init_domain.pyis now a thin shim oversci_rag.scaffold, so it and the wizard cannot disagree about what a seed-question reset looks like. Its command line, dry-run behavior, and output are unchanged. -
A bare model id still resolves to
SCI_RAG_LLM_PROVIDER(defaultgoogle), so existing configurations keep working unchanged. GoogleLLMmoved fromsci_rag.llm.clienttosci_rag.llm.google, matching the layout ofsci_rag.embed.sci_rag.llmre-exports it as before.- Retry policy is shared across providers in
retry_async(), and status-code detection no longer matches a code embedded in a longer number.
Fixed¶
sci-rag doctorno longer reports FAIL for a project that runs offline on purpose. A project with the local-hash embedder, no credentials anywhere, and the shipped generation defaults now sees warnings that name the unavailable features, and exits 0. Reaching for a model still fails: a Google embedder without credentials, or a deliberately named generation model such asanthropic:claude-opus-5with no key behind it, reports FAIL as before. The generated-project matrix gates ondoctoragain.sci-rag doctorprints its table when the configured embedder cannot be built. It looked up the embedder to report embedding-version drift, so a Google embedder without credentials aborted the whole command with a traceback, hiding the credentials row that explained the cause.sci-rag doctor --probeno longer warns on a healthy setup. Its generation probe capped output at 10 tokens, which reasoning models spend on thought before writing anything, so a working provider looked like it returned nothing.- The Vertex Model Garden endpoint is now derived correctly for the
globallocation, which is served by an unprefixed host. Grok is offered only globally, so the previous URL made it unreachable. - The OpenAI-compatible adapter closes its response stream, returning the connection to the pool when a consumer stops early.
sci-rag initno longer rewrites the commented examples in.env.examplewith the answers it collected. Only the first assignment of a key is the setting; substituting the later illustrative ones turned worked examples into confidently wrong advice and emitted the same key several times.
[0.3.0a1] - 2026-08-28¶
A packaging pre-release. No behavior of its own: it exists to establish
Trusted Publishing to TestPyPI and PyPI and to reserve the sci-rag-kit
name on both, using a version number that can be burned without cost if
the publishing path turns out to be wrong.
The changes it carries are the ones listed under Unreleased above. The real 0.3.0, with the Wave 2 benchmark refresh, is #49.
[0.2.0] - 2026-08-27¶
The "Credibility" release: the gaps between what the methodology document promised and what the code did are closed, and the launch package (roadmap, governance, comparison, benchmarks) is in place.
Added¶
- Post-fusion reranker stage:
Rerankerprotocol with an LLM adapter (default, zero new dependencies) and a local cross-encoder adapter behind the newrerankextra; per-requestinclude_rerankoverrides on the retriever and/v1/query; honestrerankstage traces with fused-order fallback on any failure. Off by default pending ablation evidence. - Eval statistics: bootstrap 95% confidence intervals on every reported mean (question-level resampling, stdlib only, deterministic), small-sample warnings below 10 questions, paired bootstrap comparisons, and nDCG@10 alongside hit@k/MRR.
sci-rag eval diff: per-question rank moves (improved, regressed, appeared, disappeared) and paired metric deltas with significance between any two eval runs; answers-mode dimension diffs.sci-rag eval calibrate: Cohen's kappa per judge dimension against human labels, agreement matrices, calibration sections appended to answers reports; ships a non-expert seed label set for the demo corpus (domain/eval_calibration_labels.jsonl).sci-rag embed reindex: find and re-embed rows stamped by retired embedder versions, batch-committed and idempotent; refuses cross-dimension reindexes; community summaries now carry embedding version stamps (migration 0002).sci-rag corpus delete+sci-rag graph gc: transactional document deletion that scrubs graph evidence arrays, drops evidenced relationships and affected communities, and a garbage-collection sweep for evidence-less entities and dangling pointers; regression test proves deleted content unreachable through every retrieval layer.sci-rag corpus snapshot: named, immutable corpus fingerprints (counts, per-document content hashes, embedding versions, git commit, corpus digest); eval runs record the snapshot name via--snapshot.- Adaptive routing:
--profile autoresolves per query through transparent heuristics (multi-hop, overview, lookup cues) with reasons, an optional ambiguity-only LLM fallback, a router trace, and--explain-routing; default profile unchanged pending the published ablation. docs/benchmarks.md: measured demo-corpus results (all ablation configs including rerank and routing, judged answers, judge calibration) with confidence intervals, corpus snapshot, commit and model ids, reproducible viamake benchmark.docs/operations.md: backup/restore runbook (pg_dump, Cloud SQL, restore drill, Parquet export note).- Launch package:
docs/ROADMAP.md(waves 2-3, UW SSEC collaboration seams, BioCirV flagship, launch-gated decisions),docs/VERSIONING.md(0.x rules, 1.0 criteria),docs/GOVERNANCE.md,docs/choosing-sci-rag-kit.md(honest comparison),ADOPTERS.md, and a runnableexamples/bring_your_own_domain.ipynb(verified offline). - Doctor: embedding-version staleness and graph-hygiene checks.
Changed¶
- Retrieval eval reports state n and a 95% CI everywhere a mean appears; retrieval tables gained an nDCG@10 column.
/v1/queryacceptsprofile: "auto"andinclude_rerank.
[0.1.0a0] - 2026-08-26¶
First working release of the template.
Added¶
- Ingestion: Docling/pypdf/Markdown parsing, structure-aware chunking (section breadcrumbs, intact tables, 800/150 token defaults), content-hash deduplication, per-document license classes, JSONL corpus manifests.
- Storage: single-Postgres schema (Alembic) with pgvector HNSW and full-text GIN indexes; embedding version stamping.
- Embeddings: Google
gemini-embedding-001at 1536 dimensions (Matryoshka, re-normalized) via AI Studio key or Vertex AI; a deterministic offline hash embedder for tests and dry runs. - Knowledge graph: ontology-constrained LLM extraction with evidence provenance, incremental stamping, deterministic label-propagation communities with LLM summaries.
- Retrieval: five layers (vector, keyword, graph traversal, community summaries, HyDE) with weighted RRF fusion, interactive/deep profiles, per-stage timeouts and traces, fail-closed license/source/exclusion scoping inside every layer.
- Answering: numbered inline citations, refusal when nothing is in scope, streaming events.
- Evaluation: seed questions, hit@k/MRR with seven ablation configs, a two-pass blind judge (grounding never sees the reference answer), fingerprint-stamped JSON and Markdown reports, a CI smoke eval.
- Serving: FastAPI
/v1(SSE answers, RFC 9457 errors, request ids, scoped API keys with rate limits, BYO LLM key) and an MCP server with seven tools and two resources, over streamable HTTP and stdio. - Operations:
sci-rag doctor, docker-compose Postgres, Dockerfile, validated Terraform for Cloud SQL + Cloud Run, GitHub Actions CI. - Template ergonomics:
domain/specialization surface,scripts/init_domain.py, offline synthetic demo corpus with seed questions and committed real-model eval reports, full documentation suite with ADRs.