# k-electron/cfr-copilot architecture

> Architecture diagram of the GitHub repository k-electron/cfr-copilot, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-12). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/k-electron/cfr-copilot
- Repository: https://github.com/k-electron/cfr-copilot

## Overview

CFR Copilot is a local FDA regulatory-compliance assistant. Users ask regulatory questions through the CLI or Streamlit chat; the agent can choose regulation search or structured recall queries, while plain and structured RAG offer direct retrieval and citation-checked answers. Ingestion loads eCFR sections and openFDA recalls into separate search and relational stores. The README also documents retrieval/answer evaluation and optional tracing. Edges use README statements or SOURCE INDEX references; unsampled subsystems are represented only where those references support them.

Main entry points: [`src/cfr_copilot/cli.py`](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/cli.py) (CLI), [`src/cfr_copilot/agent/agent.py`](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/agent.py) (Tool-using agent), [`src/cfr_copilot/ingest/index.py`](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/index.py) (CFR indexer), [`src/cfr_copilot/retrieval/retriever.py`](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/retrieval/retriever.py) (Composed retriever)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_interfaces["User interfaces"]
  node_cli["CLI<br/>[cli.py]"]
  node_chat["Chat UI<br/>[streamlit_app.py]"]
end

subgraph group_answers["Question answering"]
  node_agent["Tool-using agent<br/>[agent.py]"]
  node_agent_context["Retrieval context<br/>[context.py]"]
  node_tools["Agent tools<br/>[tools.py]"]
  node_middleware["Agent middleware<br/>[middleware.py]"]
  node_rag["RAG chain<br/>[rag.py]"]
  node_structured["Verified answers<br/>[structured.py]"]
  node_schemas["Answer schemas<br/>[schemas.py]"]
  node_retriever["Composed retriever<br/>[retriever.py]"]
  node_reranker["Reranking<br/>[rerank.py]"]
  node_llm["Local model client<br/>[llm.py]"]
end

subgraph group_corpus["Data ingestion"]
  node_ecfr_ingest["eCFR loader<br/>[ecfr.py]"]
  node_chunking["Legal chunking<br/>[chunking.py]"]
  node_indexing["CFR indexer<br/>[index.py]"]
  node_recall_ingest["Recall loader<br/>[openfda.py]"]
end

subgraph group_storage["Search and storage"]
  node_vectorstore[("Hybrid vector store<br/>[vectorstore.py]")]
  node_sections[("Full CFR sections<br/>[sections.py]")]
  node_database[("Postgres pool<br/>[db.py]")]
  node_config["Configuration<br/>[config.py]"]
end

subgraph group_quality["Evaluation and observability"]
  node_eval_data["Evaluation dataset<br/>[dataset.py]"]
  node_eval_retrieval["Retrieval evaluation<br/>[retrieval.py]"]
  node_eval_answers["Answer evaluation<br/>[answers.py]"]
  node_tracing["Tracing<br/>[tracing.py]"]
end

node_user(("User"))
node_ecfr["eCFR service"]
node_openfda["openFDA service"]
node_ollama["Ollama"]

node_user -->|"asks via CLI"| node_cli
node_user -->|"asks in chat"| node_chat
node_cli -->|"runs agent"| node_agent
node_chat -->|"streams agent"| node_agent
node_agent -->|"uses context"| node_agent_context
node_agent -->|"dispatches tools"| node_tools
node_agent -->|"installs middleware"| node_middleware
node_tools -->|"searches regulations"| node_retriever
node_tools -->|"queries recalls"| node_database
node_cli -->|"runs direct RAG"| node_rag
node_cli -->|"requests verified answer"| node_structured
node_structured -->|"builds on RAG"| node_rag
node_structured -->|"returns typed answer"| node_schemas
node_rag -->|"retrieves documents"| node_vectorstore
node_retriever -->|"searches candidates"| node_vectorstore
node_retriever -->|"reranks candidates"| node_reranker
node_retriever -->|"expands sections"| node_sections
node_rag -->|"generates answer"| node_llm
node_agent -->|"creates agent model"| node_llm
node_ecfr -->|"provides CFR XML"| node_ecfr_ingest
node_ecfr_ingest -->|"supplies sections"| node_chunking
node_cli -->|"runs indexing"| node_indexing
node_indexing -->|"loads CFR"| node_ecfr_ingest
node_indexing -->|"chunks sections"| node_chunking
node_indexing -->|"writes vectors"| node_vectorstore
node_indexing -->|"stores full sections"| node_sections
node_openfda -->|"provides recall data"| node_recall_ingest
node_recall_ingest -->|"stores recalls"| node_database
node_sections -->|"reads and writes"| node_database
node_vectorstore -->|"embeds queries"| node_llm
node_llm -->|"calls local models"| node_ollama
node_cli -->|"loads evaluation set"| node_eval_data
node_eval_retrieval -->|"uses questions"| node_eval_data
node_eval_retrieval -->|"measures retrieval"| node_retriever
node_eval_answers -->|"uses questions"| node_eval_data
node_eval_answers -->|"evaluates answers"| node_structured
node_chat -.->|"optional tracing"| node_tracing

click node_cli "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/cli.py"
click node_chat "https://github.com/k-electron/cfr-copilot/blob/main/app/streamlit_app.py"
click node_agent "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/agent.py"
click node_agent_context "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/context.py"
click node_tools "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/tools.py"
click node_middleware "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/middleware.py"
click node_rag "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/chains/rag.py"
click node_structured "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/chains/structured.py"
click node_schemas "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/chains/schemas.py"
click node_retriever "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/retrieval/retriever.py"
click node_reranker "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/retrieval/rerank.py"
click node_llm "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/llm.py"
click node_ecfr_ingest "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/ecfr.py"
click node_chunking "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/chunking.py"
click node_indexing "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/index.py"
click node_recall_ingest "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/openfda.py"
click node_vectorstore "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/retrieval/vectorstore.py"
click node_sections "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/sections.py"
click node_database "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/db.py"
click node_config "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/config.py"
click node_eval_data "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/evaluation/dataset.py"
click node_eval_retrieval "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/evaluation/retrieval.py"
click node_eval_answers "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/evaluation/answers.py"
click node_tracing "https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/tracing.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_cli,node_chat,node_user toneBlue
class node_agent,node_agent_context,node_tools,node_middleware,node_rag,node_structured,node_schemas,node_retriever,node_reranker,node_llm toneAmber
class node_ecfr_ingest,node_chunking,node_indexing,node_recall_ingest toneMint
class node_vectorstore,node_sections,node_database,node_config toneRose
class node_eval_data,node_eval_retrieval,node_eval_answers,node_tracing,node_ecfr,node_openfda,node_ollama toneIndigo
```

## Components

### User interfaces

- [CLI](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/cli.py): `src/cfr_copilot/cli.py`
- [Chat UI](https://github.com/k-electron/cfr-copilot/blob/main/app/streamlit_app.py): `app/streamlit_app.py`

### Question answering

- [Tool-using agent](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/agent.py): `src/cfr_copilot/agent/agent.py`
- [Retrieval context](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/context.py): `src/cfr_copilot/agent/context.py`
- [Agent tools](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/tools.py): `src/cfr_copilot/agent/tools.py`
- [Agent middleware](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/agent/middleware.py): `src/cfr_copilot/agent/middleware.py`
- [RAG chain](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/chains/rag.py): `src/cfr_copilot/chains/rag.py`
- [Verified answers](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/chains/structured.py): `src/cfr_copilot/chains/structured.py`
- [Answer schemas](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/chains/schemas.py): `src/cfr_copilot/chains/schemas.py`
- [Composed retriever](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/retrieval/retriever.py): `src/cfr_copilot/retrieval/retriever.py`
- [Reranking](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/retrieval/rerank.py): `src/cfr_copilot/retrieval/rerank.py`
- [Local model client](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/llm.py): `src/cfr_copilot/llm.py`

### Data ingestion

- [eCFR loader](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/ecfr.py): `src/cfr_copilot/ingest/ecfr.py`
- [Legal chunking](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/chunking.py): `src/cfr_copilot/ingest/chunking.py`
- [CFR indexer](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/index.py): `src/cfr_copilot/ingest/index.py`
- [Recall loader](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/ingest/openfda.py): `src/cfr_copilot/ingest/openfda.py`

### Search and storage

- [Hybrid vector store](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/retrieval/vectorstore.py): `src/cfr_copilot/retrieval/vectorstore.py`
- [Full CFR sections](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/sections.py): `src/cfr_copilot/sections.py`
- [Postgres pool](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/db.py): `src/cfr_copilot/db.py`
- [Configuration](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/config.py): `src/cfr_copilot/config.py`

### Evaluation and observability

- [Evaluation dataset](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/evaluation/dataset.py): `src/cfr_copilot/evaluation/dataset.py`
- [Retrieval evaluation](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/evaluation/retrieval.py): `src/cfr_copilot/evaluation/retrieval.py`
- [Answer evaluation](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/evaluation/answers.py): `src/cfr_copilot/evaluation/answers.py`
- [Tracing](https://github.com/k-electron/cfr-copilot/blob/main/src/cfr_copilot/tracing.py): `src/cfr_copilot/tracing.py`

### Other components

- **User**
- **eCFR service**
- **openFDA service**
- **Ollama**

## Connections

- User → CLI: asks via CLI (evidence: `README.md`)
- User → Chat UI: asks in chat (evidence: `README.md`)
- CLI → Tool-using agent: runs agent (evidence: `src/cfr_copilot/cli.py`)
- Chat UI → Tool-using agent: streams agent (evidence: `README.md`)
- Tool-using agent → Retrieval context: uses context (evidence: `src/cfr_copilot/agent/agent.py`)
- Tool-using agent → Agent tools: dispatches tools (evidence: `src/cfr_copilot/agent/agent.py`)
- Tool-using agent → Agent middleware: installs middleware (evidence: `src/cfr_copilot/agent/agent.py`)
- Agent tools → Composed retriever: searches regulations (evidence: `src/cfr_copilot/agent/tools.py`)
- Agent tools → Postgres pool: queries recalls (evidence: `src/cfr_copilot/agent/tools.py`)
- CLI → RAG chain: runs direct RAG (evidence: `src/cfr_copilot/cli.py`)
- CLI → Verified answers: requests verified answer (evidence: `src/cfr_copilot/cli.py`)
- Verified answers → RAG chain: builds on RAG (evidence: `src/cfr_copilot/chains/structured.py`)
- Verified answers → Answer schemas: returns typed answer (evidence: `src/cfr_copilot/chains/structured.py`)
- RAG chain → Hybrid vector store: retrieves documents (evidence: `src/cfr_copilot/chains/rag.py`)
- Composed retriever → Hybrid vector store: searches candidates (evidence: `src/cfr_copilot/retrieval/retriever.py`)
- Composed retriever → Reranking: reranks candidates (evidence: `src/cfr_copilot/retrieval/retriever.py`)
- Composed retriever → Full CFR sections: expands sections (evidence: `src/cfr_copilot/retrieval/retriever.py`)
- RAG chain → Local model client: generates answer (evidence: `src/cfr_copilot/chains/rag.py`)
- Tool-using agent → Local model client: creates agent model (evidence: `src/cfr_copilot/agent/agent.py`)
- eCFR service → eCFR loader: provides CFR XML (evidence: `src/cfr_copilot/ingest/ecfr.py`)
- eCFR loader → Legal chunking: supplies sections (evidence: `src/cfr_copilot/ingest/chunking.py`)
- CLI → CFR indexer: runs indexing (evidence: `src/cfr_copilot/cli.py`)
- CFR indexer → eCFR loader: loads CFR (evidence: `src/cfr_copilot/ingest/index.py`)
- CFR indexer → Legal chunking: chunks sections (evidence: `src/cfr_copilot/ingest/index.py`)
- CFR indexer → Hybrid vector store: writes vectors (evidence: `src/cfr_copilot/ingest/index.py`)
- CFR indexer → Full CFR sections: stores full sections (evidence: `src/cfr_copilot/ingest/index.py`)
- openFDA service → Recall loader: provides recall data (evidence: `src/cfr_copilot/ingest/openfda.py`)
- Recall loader → Postgres pool: stores recalls (evidence: `src/cfr_copilot/ingest/openfda.py`)
- Full CFR sections → Postgres pool: reads and writes (evidence: `src/cfr_copilot/sections.py`)
- Hybrid vector store → Local model client: embeds queries (evidence: `src/cfr_copilot/retrieval/vectorstore.py`)
- Local model client → Ollama: calls local models (evidence: `src/cfr_copilot/llm.py`)
- CLI → Evaluation dataset: loads evaluation set (evidence: `src/cfr_copilot/cli.py`)
- Retrieval evaluation → Evaluation dataset: uses questions (evidence: `src/cfr_copilot/evaluation/retrieval.py`)
- Retrieval evaluation → Composed retriever: measures retrieval (evidence: `src/cfr_copilot/evaluation/retrieval.py`)
- Answer evaluation → Evaluation dataset: uses questions (evidence: `src/cfr_copilot/evaluation/answers.py`)
- Answer evaluation → Verified answers: evaluates answers (evidence: `src/cfr_copilot/evaluation/answers.py`)
- Chat UI → Tracing: optional tracing
