Decisions (ADR)
The architecture decision records behind RAGSpine — immutable, append-only, and superseded rather than edited.
An Architecture Decision Record (ADR) captures one significant decision: the context that forced it, the decision itself, the alternatives that were rejected, and the consequences that follow. RAGSpine keeps its ADRs as immutable historical records.
How ADRs work here
- One decision per file. Each record is a single, self-contained choice
(
docs/adr/NNNN-kebab-title.mdin the repo). - Append-only and immutable. An ADR is never edited after it is accepted. To reverse a decision, you add a new ADR that supersedes the old one — the history stays intact and auditable.
- Supersede, don't edit. This is why a record can describe an older path (for
example, pre-
src/layout file locations) without being "wrong": it documents the decision as it stood at the time. - Exempt from drift tracking. Because they are historical, ADRs carry no
coversfrontmatter and are not checked byscripts/check_doc_drift.py.
The through-line
The recurring principle across these decisions is to separate guarantees from flexibility:
invariants (anti-fabrication, provenance, source isolation, dependency licensing, the security
gate) are hard, deterministic, and non-pluggable, while everything else (domain, language, LLM,
embedding, reranker, parsing strategy) is soft — config- or Protocol-driven.
The records
ADR 0002 is the umbrella product-direction record; it indexes the eight per-decision ADRs (0003–0010) settled in the same design interview.
ADR numbers are repository-local
Website ADRs 0012–0015 preserve an earlier family/website publication sequence. The current
RAGSpine engine repository also has its own ADR files with some of the same numbers; for example,
the website's ADR 0012 records the corespine LLM seam, while engine
docs/adr/0012-onboarding-complexity-budget.md is a different decision. Do not infer identity
from the number alone. The new website ADRs 0016–0018 below are English transcriptions of the
engine records with those matching numbers.
| # | Title | Summary | Status |
|---|---|---|---|
| 0001 | Deterministic dual-channel over a single LLM path | Two deterministic channels (structured numeric + narrative RAG); the LLM is confined to synthesis, never to inventing facts. | accepted |
| 0002 | Product direction: a general-purpose, license-clean, framework-unlocked RAG library | The umbrella north star; separates hard invariants from soft, config-/Protocol-driven flexibility and indexes ADRs 0003–0010. | accepted |
| 0003 | Audience: a general-purpose OSS library for others to build on | The primary audience is developers building their own RAG on top of RAGSpine; finance becomes one example domain, not the identity. | accepted |
| 0004 | Full generality: DomainProfile and arbitrary-dimension facts | Generalize fully — CompanyProfile becomes DomainProfile; the structured channel becomes a typed-fact store with arbitrary user-defined dimensions. | accepted |
| 0005 | Lean core; quarantine dormant capability as experimental/extras | Ship only what runs in the default offline path; move OCR, real vector, and the verifier into clearly-labeled experimental modules/extras. | accepted |
| 0006 | Quality bar: invariants as property tests, plus one real retrieval benchmark | Define quality as guarantees (invariants proven by property tests), plus one real labeled retrieval benchmark; punt domain accuracy to the user's data. | accepted |
| 0007 | Multilingual: architect for five, ship two; the rest as locale packs | Thread a locale seam through every layer; ship and test Chinese + English in core; Japanese / Italian / German ship as community locale packs. | accepted |
| 0008 | Prompts: a packaged PromptRegistry under ragspine/prompts/<locale>/ | Externalize prompts into packaged, locale-keyed template files behind a PromptRegistry Protocol, filled from DomainProfile at runtime. | accepted |
| 0009 | "Framework-free" redefined: no framework lock-in + permissive-license-only | Redefine framework-free as no orchestration lock-in plus permissive-license-only (≤ Apache-2.0); real backends are opt-in extras for weight, not purity. | accepted |
| 0010 | Intent parsing: deterministic security gate + pluggable IntentParser | Decouple the always-on, never-pluggable deterministic security gate from a pluggable IntentParser Protocol. | accepted |
| 0011 | Adopt the python-project-standard; migrate to src/ layout, keep the rest | Adopt the house standard as governing philosophy; align the one bounded structural invariant (src/ragspine/ layout) and accept four documented divergences. | accepted |
| 0012 | Adopt the corespine LLM seam — chat / ChatCompletion over create_message | Move the LLMProvider Protocol to the shared family core (corespine), adopt the OpenAI chat-completions shape, and add an optional active TPM throttle. Shipped in 0.3.0. | accepted |
| 0013 | Dify workflow YAML → pure-Python compiler + static optimization advisor | Compile a Dify .yml into framework-free imperative Python through a de-Dify-ized IR (parse → IR → codegen), plus eight purely static optimization rules; PyYAML behind a [dify] extra. Shipped in 0.4.0. | accepted |
| 0014 | Dify workflow as a service (analyze / compile / run) with three-layer safe execution | Three service endpoints of increasing trust: analyze / compile always on; run off by default behind an L0 static import gate, an L1 restricted sandbox, and (Linux) L2 subprocess isolation; the provider is always server-decided. Shipped in 0.5.0. | proposed |
| 0015 | Relation extraction — an opt-in slot with model-derived / unverified provenance markers | Add a RelationExtractor Protocol slot beside build_relation_graph; the default stays byte-identical, LLM-extracted edges are stamped model-derived + unverified, screened through the SecurityGate, and never silently trusted. Shipped in 0.9.0. | accepted |
| 0016 | Retrieval productization config | Add narrowing metadata filters, multi-library RRF routing with provenance, a parent-child preset, and an economy mode that constructs no embedding/vector components. | accepted |
| 0017 | Conversation history is generation-only context | Add first-class history while keeping it out of intent parsing, security, retrieval queries, and evidence. | accepted |
| 0018 | Parent-child store-level expansion | Persist hierarchy/window fields, wire chunkers through ingestion, and expand only after isolation while citations remain on the child hit. | accepted |
Python API
Core orchestration, stores, retrieval, workflow formats/scaffolding/preview, and Dify/n8n conversion entry points.
ADR 0001: Deterministic dual-channel over a single LLM path
Use two deterministic channels (structured numeric + narrative RAG) with the LLM confined to synthesis, never to inventing facts.