# quanttrinh/senpilot-demo architecture

> Architecture diagram of the GitHub repository quanttrinh/senpilot-demo, 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/quanttrinh/senpilot-demo
- Repository: https://github.com/quanttrinh/senpilot-demo

## Overview

Senpilot is an unattended UARB document-retrieval agent. An IMAP listener hands new email to the application entry point, which parses and validates the request with an LLM, scrapes the UARB portal, archives downloaded files, and sends a summary or error reply. The main orchestration and the distinct parsing, retrieval, archive, and reply stages are shown. The README also documents systemd supervision. Some scraper internals are only partially sampled, so uncertain internal navigation steps are omitted.

Main entry points: [`regulatory_agent/main.py`](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/main.py) (Agent orchestration), [`regulatory_agent/email/uarb_request_reader.py`](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/uarb_request_reader.py) (Request parser), [`regulatory_agent/email/uarb_request_responder.py`](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/uarb_request_responder.py) (Reply composition), [`regulatory_agent/llm/client.py`](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/llm/client.py) (LLM client)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_intake["Email intake"]
  node_listener["IMAP listener<br/>[listener.py]"]
  node_reader["Request parser"]
end

subgraph group_retrieval["Document retrieval"]
  node_scraper["UARB scraper<br/>[uarb_scraper.py]"]
  node_scraper_interface["Scraper interface<br/>[scraper.py]"]
  node_archive["ZIP archive helper<br/>[file.py]"]
end

subgraph group_reply["Reply delivery"]
  node_responder["Reply composition"]
  node_smtp["SMTP sender<br/>[sender.py]"]
end

subgraph group_runtime["Agent runtime"]
  node_entry["Agent orchestration<br/>[main.py]"]
  node_request_model["Request and result models<br/>[uarb_request.py]"]
  node_llm_base["LLM client<br/>[client.py]"]
  node_opencode["OpenCode provider<br/>[opencode.py]"]
  node_prompt_safety["Prompt safeguards<br/>[prompt.py]"]
  node_systemd["Systemd integration<br/>[systemd.py]"]
end

node_requester(("Requester"))
node_imap(("IMAP server"))
node_uarb(("UARB portal"))
node_mail_service(("Email service"))
node_llm_service(("LLM endpoint"))

node_requester -->|"sends request"| node_mail_service
node_imap -->|"provides email"| node_listener
node_entry -->|"starts listener"| node_listener
node_listener -->|"invokes callback"| node_entry
node_entry -->|"parses bytes"| node_reader
node_reader -->|"builds request"| node_request_model
node_entry -->|"scrapes request"| node_scraper
node_scraper -.->|"implements"| node_scraper_interface
node_scraper -->|"searches and downloads"| node_uarb
node_entry -->|"creates ZIP"| node_archive
node_entry -->|"sends outcome"| node_responder
node_responder -->|"delivers reply"| node_smtp
node_smtp -->|"sends email"| node_mail_service
node_reader -->|"extracts request fields"| node_llm_base
node_responder -->|"generates summary"| node_llm_base
node_llm_base -->|"gets request headers"| node_opencode
node_llm_base -->|"submits completion"| node_llm_service
node_reader -->|"guards email text"| node_prompt_safety
node_responder -->|"guards summary data"| node_prompt_safety
node_entry -->|"reports service state"| node_systemd

click node_entry "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/main.py"
click node_listener "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/listener.py"
click node_reader "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/uarb_request_reader.py"
click node_request_model "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/models/uarb_request.py"
click node_scraper "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/browser/uarb_scraper.py"
click node_scraper_interface "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/browser/scraper.py"
click node_archive "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/utils/file.py"
click node_responder "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/uarb_request_responder.py"
click node_smtp "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/sender.py"
click node_llm_base "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/llm/client.py"
click node_opencode "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/llm/opencode.py"
click node_prompt_safety "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/utils/prompt.py"
click node_systemd "https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/utils/systemd.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_listener,node_reader toneBlue
class node_scraper,node_scraper_interface,node_archive toneAmber
class node_responder,node_smtp,node_requester,node_imap toneMint
class node_entry,node_request_model,node_llm_base,node_opencode,node_prompt_safety,node_systemd toneRose
class node_uarb,node_mail_service,node_llm_service toneIndigo
```

## Components

### Email intake

- [IMAP listener](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/listener.py): `regulatory_agent/email/listener.py`
- [Request parser](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/uarb_request_reader.py): `regulatory_agent/email/uarb_request_reader.py`

### Document retrieval

- [UARB scraper](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/browser/uarb_scraper.py): `regulatory_agent/browser/uarb_scraper.py`
- [Scraper interface](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/browser/scraper.py): `regulatory_agent/browser/scraper.py`
- [ZIP archive helper](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/utils/file.py): `regulatory_agent/utils/file.py`

### Reply delivery

- [Reply composition](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/uarb_request_responder.py): `regulatory_agent/email/uarb_request_responder.py`
- [SMTP sender](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/email/sender.py): `regulatory_agent/email/sender.py`

### Agent runtime

- [Agent orchestration](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/main.py): `regulatory_agent/main.py`
- [Request and result models](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/models/uarb_request.py): `regulatory_agent/models/uarb_request.py`
- [LLM client](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/llm/client.py): `regulatory_agent/llm/client.py`
- [OpenCode provider](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/llm/opencode.py): `regulatory_agent/llm/opencode.py`
- [Prompt safeguards](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/utils/prompt.py): `regulatory_agent/utils/prompt.py`
- [Systemd integration](https://github.com/quanttrinh/senpilot-demo/blob/main/regulatory_agent/utils/systemd.py): `regulatory_agent/utils/systemd.py`

### Other components

- **Requester**
- **IMAP server**
- **UARB portal**
- **Email service**
- **LLM endpoint**

## Connections

- Requester → Email service: sends request
- IMAP server → IMAP listener: provides email
- Agent orchestration → IMAP listener: starts listener
- IMAP listener → Agent orchestration: invokes callback
- Agent orchestration → Request parser: parses bytes
- Request parser → Request and result models: builds request
- Agent orchestration → UARB scraper: scrapes request
- UARB scraper → Scraper interface: implements
- UARB scraper → UARB portal: searches and downloads
- Agent orchestration → ZIP archive helper: creates ZIP
- Agent orchestration → Reply composition: sends outcome
- Reply composition → SMTP sender: delivers reply
- SMTP sender → Email service: sends email
- Request parser → LLM client: extracts request fields
- Reply composition → LLM client: generates summary
- LLM client → OpenCode provider: gets request headers
- LLM client → LLM endpoint: submits completion
- Request parser → Prompt safeguards: guards email text
- Reply composition → Prompt safeguards: guards summary data
- Agent orchestration → Systemd integration: reports service state
