# kalyrifer/decision-history-rag architecture

> Architecture diagram of the GitHub repository kalyrifer/decision-history-rag, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-29). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/kalyrifer/decision-history-rag
- Repository: https://github.com/kalyrifer/decision-history-rag

## Overview

Decision History RAG turns GitHub repository history into searchable evidence for questions about engineering decisions. Its main workflow is Git/GitHub ingestion → normalization into entities and links → text chunks and embeddings → hybrid retrieval and graph expansion → LLM synthesis with reasons, sources, and a timeline, presented through the UI or CLI. The README documents additional file-path search, query rewriting, date relevance, and repository-specific signals. Some modules were not sampled, so their documented capabilities appear here without speculative internal call links.

Main entry points: [`retrieve/pipeline.py`](https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/pipeline.py) (Retrieval pipeline), [`synthesize/answer.py`](https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/answer.py) (Answer assembly), [`ingest/storage.py`](https://github.com/kalyrifer/decision-history-rag/blob/main/ingest/storage.py) (Raw JSONL), [`ui/app.py`](https://github.com/kalyrifer/decision-history-rag/blob/main/ui/app.py) (Streamlit interface)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_ingest["History ingestion"]
  node_raw["Raw JSONL<br/>[storage.py]"]
  node_git_ingest["Git history loader<br/>[git_source.py]"]
  node_gh_ingest["Issues and PR loader<br/>[github_source.py]"]
end

subgraph group_index["Knowledge preparation"]
  node_normalizer["Entity normalizer<br/>[parse_raw.py]"]
  node_relations["Relation extractor"]
  node_domain["Repository signals<br/>[pydantic.py]"]
  node_chunks["Text chunks<br/>[to_text.py]"]
  node_embed["Embedding builder<br/>[embed.py]"]
end

subgraph group_search["Evidence retrieval"]
  node_pipeline["Retrieval pipeline<br/>[pipeline.py]"]
  node_rewrite["Query rewriting<br/>[query_rewrite.py]"]
  node_hybrid["Dense and FTS search<br/>[hybrid.py]"]
  node_file_search["File-path search<br/>[file_search.py]"]
  node_expand["Graph expansion<br/>[expand.py]"]
  node_date["Date relevance<br/>[date_relevance.py]"]
end

subgraph group_answer["Answer delivery"]
  node_ui["Streamlit interface<br/>[app.py]"]
  node_cli["Command-line interface<br/>[cli.py]"]
  node_answer["Answer assembly<br/>[answer.py]"]
  node_focus["Aspect detection<br/>[focus.py]"]
  node_prompt["Prompt construction<br/>[prompt.py]"]
  node_llm["Model rotation<br/>[llm.py]"]
end

node_user(("Questioner"))
node_github["GitHub"]
node_db[("Postgres and pgvector")]
node_openrouter["OpenRouter"]

node_github -->|"provides Git history"| node_git_ingest
node_github -->|"provides issues and PRs"| node_gh_ingest
node_git_ingest -->|"writes records"| node_raw
node_gh_ingest -->|"writes records"| node_raw
node_raw -->|"supplies raw records"| node_normalizer
node_normalizer -->|"writes entities"| node_db
node_relations -->|"writes relations"| node_db
node_db -->|"supplies entity text"| node_chunks
node_chunks -->|"writes chunks"| node_db
node_db -->|"supplies chunks"| node_embed
node_embed -->|"writes vectors"| node_db
node_user -->|"asks question"| node_ui
node_user -->|"asks question"| node_cli
node_ui -->|"requests search"| node_pipeline
node_cli -->|"requests search"| node_pipeline
node_pipeline -->|"rewrites query"| node_rewrite
node_rewrite -->|"adds domain signals"| node_domain
node_pipeline -->|"runs dense and FTS"| node_hybrid
node_hybrid -->|"searches chunks"| node_db
node_pipeline -->|"searches file paths"| node_file_search
node_file_search -->|"reads files and relations"| node_db
node_pipeline -->|"expands anchors"| node_expand
node_expand -->|"reads relations"| node_db
node_pipeline -->|"adjusts result relevance"| node_date
node_pipeline -->|"passes evidence"| node_answer
node_answer -->|"detects aspects"| node_focus
node_answer -->|"builds synthesis prompt"| node_prompt
node_answer -->|"requests generation"| node_llm
node_llm -->|"calls model API"| node_openrouter
node_answer -->|"returns answer and sources"| node_ui
node_answer -->|"returns answer and sources"| node_cli

click node_raw "https://github.com/kalyrifer/decision-history-rag/blob/main/ingest/storage.py"
click node_git_ingest "https://github.com/kalyrifer/decision-history-rag/blob/main/ingest/git_source.py"
click node_gh_ingest "https://github.com/kalyrifer/decision-history-rag/blob/main/ingest/github_source.py"
click node_normalizer "https://github.com/kalyrifer/decision-history-rag/blob/main/normalize/parse_raw.py"
click node_relations "https://github.com/kalyrifer/decision-history-rag/blob/main/normalize/extract_relations.py"
click node_domain "https://github.com/kalyrifer/decision-history-rag/blob/main/domain/pydantic.py"
click node_chunks "https://github.com/kalyrifer/decision-history-rag/blob/main/represent/to_text.py"
click node_embed "https://github.com/kalyrifer/decision-history-rag/blob/main/represent/embed.py"
click node_ui "https://github.com/kalyrifer/decision-history-rag/blob/main/ui/app.py"
click node_cli "https://github.com/kalyrifer/decision-history-rag/blob/main/cli.py"
click node_pipeline "https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/pipeline.py"
click node_rewrite "https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/query_rewrite.py"
click node_hybrid "https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/hybrid.py"
click node_file_search "https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/file_search.py"
click node_expand "https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/expand.py"
click node_date "https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/date_relevance.py"
click node_answer "https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/answer.py"
click node_focus "https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/focus.py"
click node_prompt "https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/prompt.py"
click node_llm "https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/llm.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_raw,node_git_ingest,node_gh_ingest toneBlue
class node_normalizer,node_relations,node_domain,node_chunks,node_embed,node_db toneAmber
class node_pipeline,node_rewrite,node_hybrid,node_file_search,node_expand,node_date,node_openrouter toneMint
class node_ui,node_cli,node_answer,node_focus,node_prompt,node_llm toneRose
class node_user,node_github toneIndigo
```

## Components

### History ingestion

- [Raw JSONL](https://github.com/kalyrifer/decision-history-rag/blob/main/ingest/storage.py): `ingest/storage.py`
- [Git history loader](https://github.com/kalyrifer/decision-history-rag/blob/main/ingest/git_source.py): `ingest/git_source.py`
- [Issues and PR loader](https://github.com/kalyrifer/decision-history-rag/blob/main/ingest/github_source.py): `ingest/github_source.py`

### Knowledge preparation

- [Entity normalizer](https://github.com/kalyrifer/decision-history-rag/blob/main/normalize/parse_raw.py): `normalize/parse_raw.py`
- [Relation extractor](https://github.com/kalyrifer/decision-history-rag/blob/main/normalize/extract_relations.py): `normalize/extract_relations.py`
- [Repository signals](https://github.com/kalyrifer/decision-history-rag/blob/main/domain/pydantic.py): `domain/pydantic.py`
- [Text chunks](https://github.com/kalyrifer/decision-history-rag/blob/main/represent/to_text.py): `represent/to_text.py`
- [Embedding builder](https://github.com/kalyrifer/decision-history-rag/blob/main/represent/embed.py): `represent/embed.py`

### Evidence retrieval

- [Retrieval pipeline](https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/pipeline.py): `retrieve/pipeline.py`
- [Query rewriting](https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/query_rewrite.py): `retrieve/query_rewrite.py`
- [Dense and FTS search](https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/hybrid.py): `retrieve/hybrid.py`
- [File-path search](https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/file_search.py): `retrieve/file_search.py`
- [Graph expansion](https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/expand.py): `retrieve/expand.py`
- [Date relevance](https://github.com/kalyrifer/decision-history-rag/blob/main/retrieve/date_relevance.py): `retrieve/date_relevance.py`

### Answer delivery

- [Streamlit interface](https://github.com/kalyrifer/decision-history-rag/blob/main/ui/app.py): `ui/app.py`
- [Command-line interface](https://github.com/kalyrifer/decision-history-rag/blob/main/cli.py): `cli.py`
- [Answer assembly](https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/answer.py): `synthesize/answer.py`
- [Aspect detection](https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/focus.py): `synthesize/focus.py`
- [Prompt construction](https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/prompt.py): `synthesize/prompt.py`
- [Model rotation](https://github.com/kalyrifer/decision-history-rag/blob/main/synthesize/llm.py): `synthesize/llm.py`

### Other components

- **Questioner**
- **GitHub**
- **Postgres and pgvector**
- **OpenRouter**

## Connections

- GitHub → Git history loader: provides Git history
- GitHub → Issues and PR loader: provides issues and PRs
- Git history loader → Raw JSONL: writes records
- Issues and PR loader → Raw JSONL: writes records
- Raw JSONL → Entity normalizer: supplies raw records
- Entity normalizer → Postgres and pgvector: writes entities
- Relation extractor → Postgres and pgvector: writes relations
- Postgres and pgvector → Text chunks: supplies entity text
- Text chunks → Postgres and pgvector: writes chunks
- Postgres and pgvector → Embedding builder: supplies chunks
- Embedding builder → Postgres and pgvector: writes vectors
- Questioner → Streamlit interface: asks question
- Questioner → Command-line interface: asks question
- Streamlit interface → Retrieval pipeline: requests search
- Command-line interface → Retrieval pipeline: requests search
- Retrieval pipeline → Query rewriting: rewrites query
- Query rewriting → Repository signals: adds domain signals
- Retrieval pipeline → Dense and FTS search: runs dense and FTS
- Dense and FTS search → Postgres and pgvector: searches chunks
- Retrieval pipeline → File-path search: searches file paths
- File-path search → Postgres and pgvector: reads files and relations
- Retrieval pipeline → Graph expansion: expands anchors
- Graph expansion → Postgres and pgvector: reads relations
- Retrieval pipeline → Date relevance: adjusts result relevance
- Retrieval pipeline → Answer assembly: passes evidence
- Answer assembly → Aspect detection: detects aspects
- Answer assembly → Prompt construction: builds synthesis prompt
- Answer assembly → Model rotation: requests generation
- Model rotation → OpenRouter: calls model API
- Answer assembly → Streamlit interface: returns answer and sources
- Answer assembly → Command-line interface: returns answer and sources
