Domain-structured RAG pipeline template
Project description
right-rag
right-rag is a domain-structured RAG template for corpora where plain text
chunking loses too much context: laws, policies, contracts, manuals, academic
papers, handbooks, and other hierarchical documents.
Instead of starting with "split text every N tokens", right-rag starts with the
document's real structure: sections, clauses, rules, definitions, procedures,
tables, exceptions, and citations. You customize that structure through small
plugins under spec/.
Why right-rag
Most RAG failures are not embedding failures. They are structure failures:
- the answer is split away from its exception
- the citation points to a broad page instead of the exact clause
- metadata is stored but not connected to retrieval
- a vector index becomes the design instead of one possible implementation
right-rag keeps the core pipeline generic and lets each domain define what its evidence means.
Architecture
flowchart LR
A[Source documents] --> B[Document loaders]
B --> C[Unit parsers]
C --> D[Semantic units]
D --> E[Chunk parsers]
E --> F[Retrieval-ready chunks]
D --> G[Unit savers]
F --> H[Chunk savers]
G --> I[Unit artifacts]
H --> J[Chunk artifacts]
I --> K[Retrievers]
J --> K
K --> L[Answer generator]
L --> M[Answer with evidence]
M --> N[Evaluators and reports]
Index and query are separate:
flowchart TD
subgraph Index
A[Load] --> B[Parse units] --> C[Parse chunks] --> D[Save artifacts]
end
subgraph Query
E[User query] --> F[Retrievers use artifacts] --> G[Answer generator]
end
subgraph Evaluate
H[Eval cases] --> E
G --> I[Evaluator] --> J[Report]
end
Install
Requirements:
- Python 3.13+
Install from PyPI:
pip install right-rag
Or run without a permanent install:
uvx --from right-rag right-rag --help
Quick Start
Create a new RAG project:
right-rag init my-rag
cd my-rag
Add source documents:
data/documents/
Run the default smoke pipeline:
right-rag index
right-rag query "your question"
right-rag evaluate
Generated local artifacts:
output/units/output/chunks/.right-rag-state.jsonoutput/evaluation/
The default unit and chunk parsers are smoke-test implementations only. For
production, write domain parsers under spec/.
Project Template
right-rag init creates:
my-rag/
right_rag.toml
data/documents/
eval/cases.example.json
output/
spec/
document_loaders/
unit_parsers/
chunk_parsers/
unit_savers/
chunk_savers/
retrievers/
answer_generators/
evaluators/
reporters/
You adapt the project by editing spec/, not by forking the framework.
Extension Points
| Folder | Purpose |
|---|---|
spec/document_loaders/ |
Load source documents from files, APIs, stores, or custom extractors. |
spec/unit_parsers/ |
Convert documents into a faithful ParsedUnit tree. |
spec/chunk_parsers/ |
Convert semantic Unit objects into retrieval-ready Chunk records. |
spec/unit_savers/ |
Persist units and return artifacts that can be used later. |
spec/chunk_savers/ |
Persist chunks and return artifacts that can be used later. |
spec/retrievers/ |
Read artifacts and decide how to retrieve evidence. |
spec/answer_generators/ |
Generate answers from retrieved evidence. |
spec/evaluators/ |
Score query outputs for the domain. |
spec/reporters/ |
Write evaluation reports. |
Artifacts are intentionally storage-agnostic. A saver can write JSON, SQL, VectorDB, a graph, an external service, or something domain-specific. The retriever should use artifact capabilities instead of depending on a storage implementation.
Domain Modeling
Start by looking at the source documents, not by picking a retrieval method. Choose units that match the author's structure:
- laws: act -> chapter -> section -> clause -> subclause
- contracts: agreement -> article -> clause -> schedule item
- policies: policy -> section -> rule -> exception
- manuals: manual -> chapter -> procedure -> step
- academic papers: paper -> section -> subsection -> paragraph/table/figure note
Good unit parsers:
- preserve hierarchy with
ParsedUnit.subunits - set source spans when possible
- keep
fulltextfaithful to the source - store provenance in attributes or metadata
- reject unsupported formats visibly
- avoid catch-all parsers
Good chunk parsers:
- chunk inside a single unit
- keep rules with their exceptions and limitations
- carry citation/filter attributes
- prefer fewer useful chunks over many tiny fragments
Minimal Unit Parser
from collections.abc import Iterable
from right_rag.interfaces import UnitParser
from right_rag.model import Document, ParsedUnit
class SectionParser(UnitParser):
@property
def parser_name(self) -> str:
return "sections"
def parser_can_handle_document(self, document: Document) -> bool:
return "Section " in document.text
def parse_document(self, document: Document) -> Iterable[ParsedUnit]:
yield ParsedUnit(
topic="Section 1",
fulltext="Exact source text for section 1",
source_start=0,
source_end=31,
attributes={
"unit_type": "section",
"role": "rule",
"citation": "Section 1",
},
)
Minimal Chunk Parser
from right_rag.interfaces import ChunkParser
from right_rag.model import Chunk, Unit
from right_rag.pipeline_state import stable_hash
class SemanticChunkParser(ChunkParser):
@property
def parser_name(self) -> str:
return "semantic"
def parse_unit(self, unit: Unit):
text = f"{unit.temporal_topic}\n\n{unit.fulltext}"
yield Chunk(
id=stable_hash({"unit_id": unit.id, "parser": self.parser_name}),
document_id=unit.document_id,
unit_id=unit.id,
topic=unit.topic,
fulltext=text,
attributes={
**unit.attributes,
"parser_name": self.parser_name,
"source_unit": unit.temporal_topic,
},
)
Evaluation
Evaluation is built into the pipeline:
right-rag evaluate eval/cases.example.json --output output/evaluation/report.md
The default evaluator is intentionally simple. It is useful for smoke tests and
regression checks. Real projects should add domain-specific evaluators under
spec/evaluators/.
Development
Clone and test the framework:
git clone https://github.com/sunmodza/right-rag.git
cd right-rag
uv sync
python -m compileall src/right_rag
python -m unittest discover -s tests
uv build
Run plugin discovery:
uv run python -c "from right_rag.registry import build_registry; r=build_registry(); print(r.document_loaders, r.unit_parsers, r.chunk_parsers, r.unit_savers, r.chunk_savers)"
Release
CI runs tests and builds the package on pushes to main and pull requests.
Publishing runs on version tags:
git tag v0.1.0
git push origin v0.1.0
PyPI Trusted Publishing is configured for:
- project:
right-rag - workflow:
publish.yml - environment:
pypi
Design Rules
- Put domain logic in
spec/. - Keep
src/right_rag/pipeline.pyfocused on orchestration. - Return
ParsedUnitfrom unit parsers. - Let the library create
Unit. - Treat metadata as stored context, not control flow.
- Do not couple the framework to vector search, keyword search, SQL, or graph retrieval.
- Use stdlib before adding dependencies.
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 right_rag-0.1.1.tar.gz.
File metadata
- Download URL: right_rag-0.1.1.tar.gz
- Upload date:
- Size: 187.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3f1f8ed2252ecdc2da46629e066768482408bbb5c42ff6875793c188f5b41df
|
|
| MD5 |
3b688d6c0eff19a1c003002a7e50a915
|
|
| BLAKE2b-256 |
9881d7fa0b810904f7dfbc14fb42216af5c8ca7041d42cbe79926c6b817e006c
|
Provenance
The following attestation bundles were made for right_rag-0.1.1.tar.gz:
Publisher:
publish.yml on sunmodza/right-rag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
right_rag-0.1.1.tar.gz -
Subject digest:
c3f1f8ed2252ecdc2da46629e066768482408bbb5c42ff6875793c188f5b41df - Sigstore transparency entry: 2108334337
- Sigstore integration time:
-
Permalink:
sunmodza/right-rag@f0e013f1f842671c0d4dfdc61c109f63b6703c55 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/sunmodza
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f0e013f1f842671c0d4dfdc61c109f63b6703c55 -
Trigger Event:
push
-
Statement type:
File details
Details for the file right_rag-0.1.1-py3-none-any.whl.
File metadata
- Download URL: right_rag-0.1.1-py3-none-any.whl
- Upload date:
- Size: 32.4 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 |
710ccd031a5fd2c7844c46c307e563297cd7fd971b73ab41f8dc6ddbbd35070e
|
|
| MD5 |
7590f83bd1cb39c6684126da9a9012fd
|
|
| BLAKE2b-256 |
141c9eb28f3ae235dc52d4fd8eda065b81150c19fb6bf6cc81a9d0f4e90738b4
|
Provenance
The following attestation bundles were made for right_rag-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on sunmodza/right-rag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
right_rag-0.1.1-py3-none-any.whl -
Subject digest:
710ccd031a5fd2c7844c46c307e563297cd7fd971b73ab41f8dc6ddbbd35070e - Sigstore transparency entry: 2108334501
- Sigstore integration time:
-
Permalink:
sunmodza/right-rag@f0e013f1f842671c0d4dfdc61c109f63b6703c55 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/sunmodza
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f0e013f1f842671c0d4dfdc61c109f63b6703c55 -
Trigger Event:
push
-
Statement type: