# watchleo/karutaocr architecture

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

- Interactive diagram: https://gitdiagram.com/watchleo/karutaocr
- Repository: https://github.com/watchleo/karutaocr

## Overview

Karuta Wishlist Evaluator is a Discord client that watches configured channels, detects drop announcements and evaluator analyses, chooses a card, then reacts to the drop message before the claim window expires. The main workflow is coordinated in bot.py; evaluator.py parses card details and ranks candidates, while stealth.py supplies session identity, persistence, and reconnect helpers. The README documents the detection, recovery, selection, and reaction behavior. Some internal calls are not shown in the excerpts, so only documented or evidenced relationships are drawn.

Main entry points: [`bot.py`](https://github.com/watchleo/karutaocr/blob/main/bot.py) (Discord client), [`evaluator.py`](https://github.com/watchleo/karutaocr/blob/main/evaluator.py) (Analysis parser), [`stealth.py`](https://github.com/watchleo/karutaocr/blob/main/stealth.py) (Client identity)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_monitoring["Drop Monitoring"]
  node_client["Discord client<br/>[bot.py]"]
  node_drop_watch["Drop tracking<br/>[bot.py]"]
  node_analysis_recovery["Analysis recovery<br/>[bot.py]"]
end

subgraph group_decision["Evaluation and Grabbing"]
  node_parser["Analysis parser<br/>[evaluator.py]"]
  node_card_ranking["Card ranking<br/>[evaluator.py]"]
  node_reaction_choice["Reaction resolution<br/>[bot.py]"]
  node_claim["Claim reaction<br/>[bot.py]"]
end

subgraph group_session["Session Support"]
  node_state[("Persistent state<br/>[stealth.py]")]
  node_identity["Client identity<br/>[stealth.py]"]
  node_reconnect["Reconnect backoff<br/>[stealth.py]"]
end

node_operator(("Operator"))
node_discord{{"Discord"}}
node_karuta{{"Karuta"}}

node_operator -->|"configures"| node_client
node_client -->|"connects to"| node_discord
node_discord -->|"delivers messages"| node_drop_watch
node_drop_watch -->|"tracks drop"| node_analysis_recovery
node_analysis_recovery -->|"parses analysis"| node_parser
node_parser -->|"provides cards"| node_card_ranking
node_card_ranking -->|"selects card"| node_reaction_choice
node_reaction_choice -->|"resolves emoji"| node_claim
node_claim -->|"reacts to message"| node_discord
node_karuta -->|"posts drops"| node_discord
node_client -.->|"builds profile"| node_identity
node_client -.->|"backs off"| node_reconnect

click node_client "https://github.com/watchleo/karutaocr/blob/main/bot.py"
click node_drop_watch "https://github.com/watchleo/karutaocr/blob/main/bot.py"
click node_analysis_recovery "https://github.com/watchleo/karutaocr/blob/main/bot.py"
click node_parser "https://github.com/watchleo/karutaocr/blob/main/evaluator.py"
click node_card_ranking "https://github.com/watchleo/karutaocr/blob/main/evaluator.py"
click node_reaction_choice "https://github.com/watchleo/karutaocr/blob/main/bot.py"
click node_claim "https://github.com/watchleo/karutaocr/blob/main/bot.py"
click node_state "https://github.com/watchleo/karutaocr/blob/main/stealth.py"
click node_identity "https://github.com/watchleo/karutaocr/blob/main/stealth.py"
click node_reconnect "https://github.com/watchleo/karutaocr/blob/main/stealth.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_client,node_drop_watch,node_analysis_recovery toneBlue
class node_parser,node_card_ranking,node_reaction_choice,node_claim toneAmber
class node_state,node_identity,node_reconnect toneMint
class node_operator,node_discord,node_karuta toneIndigo
```

## Components

### Drop Monitoring

- [Discord client](https://github.com/watchleo/karutaocr/blob/main/bot.py): `bot.py`
- [Drop tracking](https://github.com/watchleo/karutaocr/blob/main/bot.py): `bot.py`
- [Analysis recovery](https://github.com/watchleo/karutaocr/blob/main/bot.py): `bot.py`

### Evaluation and Grabbing

- [Analysis parser](https://github.com/watchleo/karutaocr/blob/main/evaluator.py): `evaluator.py`
- [Card ranking](https://github.com/watchleo/karutaocr/blob/main/evaluator.py): `evaluator.py`
- [Reaction resolution](https://github.com/watchleo/karutaocr/blob/main/bot.py): `bot.py`
- [Claim reaction](https://github.com/watchleo/karutaocr/blob/main/bot.py): `bot.py`

### Session Support

- [Persistent state](https://github.com/watchleo/karutaocr/blob/main/stealth.py): `stealth.py`
- [Client identity](https://github.com/watchleo/karutaocr/blob/main/stealth.py): `stealth.py`
- [Reconnect backoff](https://github.com/watchleo/karutaocr/blob/main/stealth.py): `stealth.py`

### Other components

- **Operator**
- **Discord**
- **Karuta**

## Connections

- Operator → Discord client: configures (evidence: `README.md`)
- Discord client → Discord: connects to (evidence: `README.md`)
- Discord → Drop tracking: delivers messages (evidence: `README.md`)
- Drop tracking → Analysis recovery: tracks drop (evidence: `README.md`)
- Analysis recovery → Analysis parser: parses analysis (evidence: `README.md`)
- Analysis parser → Card ranking: provides cards (evidence: `evaluator.py`)
- Card ranking → Reaction resolution: selects card (evidence: `README.md`)
- Reaction resolution → Claim reaction: resolves emoji (evidence: `README.md`)
- Claim reaction → Discord: reacts to message (evidence: `README.md`)
- Karuta → Discord: posts drops (evidence: `README.md`)
- Discord client → Client identity: builds profile (evidence: `bot.py`)
- Discord client → Reconnect backoff: backs off (evidence: `bot.py`)
