# prasannashr/twin architecture

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

- Interactive diagram: https://gitdiagram.com/prasannashr/twin
- Repository: https://github.com/prasannashr/twin
- Video tour (about a minute): https://gitdiagram.com/prasannashr/twin/video

## Overview

This is a privacy-filtered digital-twin career assistant. A visitor asks a question or supplies job requirements through the chat UI; the agent may search the profile or gather evidence per requirement, then returns a bounded, citation-checked answer with source passages and research actions. The README documents ingestion, chunking, and in-memory BM25 indexing; those internals are represented at the documented subsystem level because their source was not sampled.

Main entry points: [`twin/agent/graph.py`](https://github.com/prasannashr/twin/blob/main/twin/agent/graph.py) (Bounded agent loop), [`twin/ui/interface.py`](https://github.com/prasannashr/twin/blob/main/twin/ui/interface.py) (Chat interface), [`twin/agent/tools.py`](https://github.com/prasannashr/twin/blob/main/twin/agent/tools.py) (Read-only tool dispatch), [`twin/retrieval/loader.py`](https://github.com/prasannashr/twin/blob/main/twin/retrieval/loader.py) (Document ingestion)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_experience["Chat experience"]
  node_chat_ui["Chat interface<br/>[interface.py]"]
  node_app_entry["App entry<br/>[app.py]"]
  node_chat_result["Answer and evidence<br/>[interface.py]"]
end

subgraph group_agent["Agent and safety"]
  node_agent_loop["Bounded agent loop<br/>[graph.py]"]
  node_agent_prompts["Agent instructions<br/>[prompts.py]"]
  node_tool_dispatch["Read-only tool dispatch<br/>[tools.py]"]
  node_privacy["Privacy checks<br/>[privacy.py]"]
  node_source_registry["Request source IDs<br/>[tools.py]"]
end

subgraph group_retrieval["Profile retrieval"]
  node_summary_doc["Profile summary<br/>[summary.txt]"]
  node_linkedin_doc["Career PDF<br/>[linkedin.pdf]"]
  node_document_loader["Document ingestion<br/>[loader.py]"]
  node_bm25_index[("In-memory BM25 index<br/>[knowledge_base.py]")]
end

subgraph group_services["Model service"]
  node_provider_client["Provider client<br/>[provider.py]"]
  node_runtime_config["Runtime settings<br/>[config.py]"]
end

node_visitor(("Visitor"))
node_experiential_labs["Experiential Labs"]

node_visitor -->|"asks question"| node_chat_ui
node_app_entry -->|"launches UI"| node_chat_ui
node_chat_ui -->|"checks input"| node_privacy
node_chat_ui -->|"runs request"| node_agent_loop
node_agent_loop -->|"uses instructions"| node_agent_prompts
node_agent_loop -->|"requests completion"| node_provider_client
node_provider_client -->|"reads settings"| node_runtime_config
node_provider_client -->|"sends completion"| node_experiential_labs
node_agent_loop -->|"dispatches tools"| node_tool_dispatch
node_tool_dispatch -->|"searches passages"| node_bm25_index
node_tool_dispatch -->|"filters queries"| node_privacy
node_tool_dispatch -->|"registers evidence"| node_source_registry
node_source_registry -->|"returns evidence"| node_agent_loop
node_agent_loop -->|"validates answer"| node_privacy
node_summary_doc -->|"provides text"| node_document_loader
node_linkedin_doc -->|"provides PDF"| node_document_loader
node_document_loader -->|"filters passages"| node_privacy
node_document_loader -->|"builds index"| node_bm25_index
node_agent_loop -->|"returns answer and sources"| node_chat_ui
node_chat_ui -->|"renders evidence"| node_chat_result
node_chat_result -->|"shows response"| node_visitor

click node_chat_ui "https://github.com/prasannashr/twin/blob/main/twin/ui/interface.py"
click node_app_entry "https://github.com/prasannashr/twin/blob/main/app.py"
click node_chat_result "https://github.com/prasannashr/twin/blob/main/twin/ui/interface.py"
click node_agent_loop "https://github.com/prasannashr/twin/blob/main/twin/agent/graph.py"
click node_agent_prompts "https://github.com/prasannashr/twin/blob/main/twin/agent/prompts.py"
click node_tool_dispatch "https://github.com/prasannashr/twin/blob/main/twin/agent/tools.py"
click node_privacy "https://github.com/prasannashr/twin/blob/main/twin/privacy.py"
click node_source_registry "https://github.com/prasannashr/twin/blob/main/twin/agent/tools.py"
click node_summary_doc "https://github.com/prasannashr/twin/blob/main/data/summary.txt"
click node_linkedin_doc "https://github.com/prasannashr/twin/blob/main/data/linkedin.pdf"
click node_document_loader "https://github.com/prasannashr/twin/blob/main/twin/retrieval/loader.py"
click node_bm25_index "https://github.com/prasannashr/twin/blob/main/twin/retrieval/knowledge_base.py"
click node_provider_client "https://github.com/prasannashr/twin/blob/main/twin/provider.py"
click node_runtime_config "https://github.com/prasannashr/twin/blob/main/twin/config.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_chat_ui,node_app_entry,node_chat_result toneBlue
class node_agent_loop,node_agent_prompts,node_tool_dispatch,node_privacy,node_source_registry toneAmber
class node_summary_doc,node_linkedin_doc,node_document_loader,node_bm25_index toneMint
class node_provider_client,node_runtime_config toneRose
class node_visitor,node_experiential_labs toneIndigo
```

## Components

### Chat experience

- [Chat interface](https://github.com/prasannashr/twin/blob/main/twin/ui/interface.py): `twin/ui/interface.py`
- [App entry](https://github.com/prasannashr/twin/blob/main/app.py): `app.py`
- [Answer and evidence](https://github.com/prasannashr/twin/blob/main/twin/ui/interface.py): `twin/ui/interface.py`

### Agent and safety

- [Bounded agent loop](https://github.com/prasannashr/twin/blob/main/twin/agent/graph.py): `twin/agent/graph.py`
- [Agent instructions](https://github.com/prasannashr/twin/blob/main/twin/agent/prompts.py): `twin/agent/prompts.py`
- [Read-only tool dispatch](https://github.com/prasannashr/twin/blob/main/twin/agent/tools.py): `twin/agent/tools.py`
- [Privacy checks](https://github.com/prasannashr/twin/blob/main/twin/privacy.py): `twin/privacy.py`
- [Request source IDs](https://github.com/prasannashr/twin/blob/main/twin/agent/tools.py): `twin/agent/tools.py`

### Profile retrieval

- [Profile summary](https://github.com/prasannashr/twin/blob/main/data/summary.txt): `data/summary.txt`
- [Career PDF](https://github.com/prasannashr/twin/blob/main/data/linkedin.pdf): `data/linkedin.pdf`
- [Document ingestion](https://github.com/prasannashr/twin/blob/main/twin/retrieval/loader.py): `twin/retrieval/loader.py`
- [In-memory BM25 index](https://github.com/prasannashr/twin/blob/main/twin/retrieval/knowledge_base.py): `twin/retrieval/knowledge_base.py`

### Model service

- [Provider client](https://github.com/prasannashr/twin/blob/main/twin/provider.py): `twin/provider.py`
- [Runtime settings](https://github.com/prasannashr/twin/blob/main/twin/config.py): `twin/config.py`

### Other components

- **Visitor**
- **Experiential Labs**

## Connections

- Visitor → Chat interface: asks question
- App entry → Chat interface: launches UI
- Chat interface → Privacy checks: checks input
- Chat interface → Bounded agent loop: runs request
- Bounded agent loop → Agent instructions: uses instructions
- Bounded agent loop → Provider client: requests completion
- Provider client → Runtime settings: reads settings
- Provider client → Experiential Labs: sends completion
- Bounded agent loop → Read-only tool dispatch: dispatches tools
- Read-only tool dispatch → In-memory BM25 index: searches passages
- Read-only tool dispatch → Privacy checks: filters queries
- Read-only tool dispatch → Request source IDs: registers evidence
- Request source IDs → Bounded agent loop: returns evidence
- Bounded agent loop → Privacy checks: validates answer
- Profile summary → Document ingestion: provides text
- Career PDF → Document ingestion: provides PDF
- Document ingestion → Privacy checks: filters passages
- Document ingestion → In-memory BM25 index: builds index
- Bounded agent loop → Chat interface: returns answer and sources
- Chat interface → Answer and evidence: renders evidence
- Answer and evidence → Visitor: shows response
