# cagrianilokumus/squadreader architecture

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

## Overview

sqreader is a read-only Squad server observer that captures live game state, records matches, computes player statistics/ELO, and serves replay and stats views. Its main workflow runs from an administrator starting the agent, through process-memory sampling and match recording, to browser replay. The README documents the two-tier capture cadence, compressed replay format, local persistence, and optional central push. Source excerpts are partial, so links between unsampled backend orchestration and subsystems are limited to documented behavior.

Main entry points: [`sqreader/cli.py`](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/cli.py) (CLI and orchestration), [`frontend/src/App.tsx`](https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/App.tsx) (Viewer application), [`sqreader/httpsrv.py`](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/httpsrv.py) (HTTP service), [`sqreader/ingest_client.py`](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/ingest_client.py) (Central ingest client)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_capture["Memory capture"]
  node_scanner["Process discovery<br/>[scanner.py]"]
  node_memory["Process memory access<br/>[mem.py]"]
  node_ue["Unreal object reader<br/>[uobject.py]"]
  node_snapshot["Game snapshot builder<br/>[snapshot.py]"]
  node_sampler["Position sampler<br/>[possample.py]"]
  node_worker["Full-frame worker<br/>[buildworker.py]"]
end

subgraph group_record["Recording and stats"]
  node_recorder["Match recorder<br/>[recorder.py]"]
  node_lifecycle["Recording lifecycle"]
  node_sqrx["Compressed replay files<br/>[sqrx.py]"]
  node_stats[("Stats and ELO<br/>[stats.py]")]
end

subgraph group_serve["Agent serving"]
  node_cli["CLI and orchestration<br/>[cli.py]"]
  node_http["HTTP service<br/>[httpsrv.py]"]
end

subgraph group_viewer["Replay viewer"]
  node_app["Viewer application<br/>[App.tsx]"]
  node_replayapi["Replay loading<br/>[replay.ts]"]
  node_playback["Replay playback<br/>[playback.ts]"]
  node_store["Viewer state<br/>[viewerStore.ts]"]
  node_canvas["Live map rendering<br/>[MapCanvas.tsx]"]
  node_killfeed["Kill feed<br/>[useKillFeed.ts]"]
  node_statsui["Player stats view<br/>[PlayerStats.tsx]"]
end

subgraph group_integrations["External integrations"]
  node_game["Squad server process"]
  node_central["Optional central platform"]
  node_push["Central ingest client<br/>[ingest_client.py]"]
end

node_admin(("Server administrator"))
node_browser(("Viewer user"))

node_admin -->|"starts agent"| node_cli
node_cli -->|"discovers process"| node_scanner
node_scanner -->|"selects process"| node_game
node_snapshot -->|"reads memory"| node_memory
node_ue -->|"reads objects"| node_memory
node_snapshot -->|"resolves objects"| node_ue
node_sampler -->|"samples positions"| node_memory
node_worker -->|"builds frames"| node_snapshot
node_cli -->|"starts worker"| node_worker
node_cli -->|"runs sampler"| node_sampler
node_cli -->|"records matches"| node_recorder
node_recorder -->|"writes replay"| node_sqrx
node_cli -->|"manages matches"| node_lifecycle
node_cli -->|"computes stats"| node_stats
node_cli -->|"starts service"| node_http
node_browser -->|"opens viewer"| node_app
node_app -->|"loads replay"| node_replayapi
node_replayapi -->|"requests replay"| node_http
node_http -->|"serves replay"| node_sqrx
node_app -->|"starts playback"| node_playback
node_playback -->|"updates playhead"| node_store
node_app -->|"reads state"| node_store
node_app -->|"renders map"| node_canvas
node_app -->|"activates feed"| node_killfeed
node_app -->|"shows stats"| node_statsui
node_statsui -->|"requests stats"| node_http
node_http -->|"reads statistics"| node_stats
node_cli -.->|"pushes finished matches"| node_push
node_push -.->|"reads match bundle"| node_stats
node_push -.->|"sends enrolled data"| node_central

click node_cli "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/cli.py"
click node_scanner "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/scanner.py"
click node_memory "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/mem.py"
click node_ue "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/ue/uobject.py"
click node_snapshot "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/squad/snapshot.py"
click node_sampler "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/squad/possample.py"
click node_worker "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/squad/buildworker.py"
click node_recorder "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/recorder.py"
click node_lifecycle "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/recording_lifecycle.py"
click node_sqrx "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/sqrx.py"
click node_stats "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/stats.py"
click node_http "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/httpsrv.py"
click node_app "https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/App.tsx"
click node_replayapi "https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/api/replay.ts"
click node_playback "https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/api/playback.ts"
click node_store "https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/state/viewerStore.ts"
click node_canvas "https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/canvas/MapCanvas.tsx"
click node_killfeed "https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/killfeed/useKillFeed.ts"
click node_statsui "https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/ui/PlayerStats.tsx"
click node_push "https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/ingest_client.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_scanner,node_memory,node_ue,node_snapshot,node_sampler,node_worker,node_browser toneBlue
class node_recorder,node_lifecycle,node_sqrx,node_stats toneAmber
class node_cli,node_http,node_admin toneMint
class node_app,node_replayapi,node_playback,node_store,node_canvas,node_killfeed,node_statsui toneRose
class node_game,node_central,node_push toneIndigo
```

## Components

### Memory capture

- [Process discovery](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/scanner.py): `sqreader/scanner.py`
- [Process memory access](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/mem.py): `sqreader/mem.py`
- [Unreal object reader](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/ue/uobject.py): `sqreader/ue/uobject.py`
- [Game snapshot builder](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/squad/snapshot.py): `sqreader/squad/snapshot.py`
- [Position sampler](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/squad/possample.py): `sqreader/squad/possample.py`
- [Full-frame worker](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/squad/buildworker.py): `sqreader/squad/buildworker.py`

### Recording and stats

- [Match recorder](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/recorder.py): `sqreader/recorder.py`
- [Recording lifecycle](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/recording_lifecycle.py): `sqreader/recording_lifecycle.py`
- [Compressed replay files](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/sqrx.py): `sqreader/sqrx.py`
- [Stats and ELO](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/stats.py): `sqreader/stats.py`

### Agent serving

- [CLI and orchestration](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/cli.py): `sqreader/cli.py`
- [HTTP service](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/httpsrv.py): `sqreader/httpsrv.py`

### Replay viewer

- [Viewer application](https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/App.tsx): `frontend/src/App.tsx`
- [Replay loading](https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/api/replay.ts): `frontend/src/api/replay.ts`
- [Replay playback](https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/api/playback.ts): `frontend/src/api/playback.ts`
- [Viewer state](https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/state/viewerStore.ts): `frontend/src/state/viewerStore.ts`
- [Live map rendering](https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/canvas/MapCanvas.tsx): `frontend/src/canvas/MapCanvas.tsx`
- [Kill feed](https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/killfeed/useKillFeed.ts): `frontend/src/killfeed/useKillFeed.ts`
- [Player stats view](https://github.com/cagrianilokumus/squadreader/blob/main/frontend/src/ui/PlayerStats.tsx): `frontend/src/ui/PlayerStats.tsx`

### External integrations

- **Squad server process**
- **Optional central platform**
- [Central ingest client](https://github.com/cagrianilokumus/squadreader/blob/main/sqreader/ingest_client.py): `sqreader/ingest_client.py`

### Other components

- **Server administrator**
- **Viewer user**

## Connections

- Server administrator → CLI and orchestration: starts agent
- CLI and orchestration → Process discovery: discovers process
- Process discovery → Squad server process: selects process
- Game snapshot builder → Process memory access: reads memory
- Unreal object reader → Process memory access: reads objects
- Game snapshot builder → Unreal object reader: resolves objects
- Position sampler → Process memory access: samples positions
- Full-frame worker → Game snapshot builder: builds frames
- CLI and orchestration → Full-frame worker: starts worker
- CLI and orchestration → Position sampler: runs sampler
- CLI and orchestration → Match recorder: records matches
- Match recorder → Compressed replay files: writes replay
- CLI and orchestration → Recording lifecycle: manages matches
- CLI and orchestration → Stats and ELO: computes stats
- CLI and orchestration → HTTP service: starts service
- Viewer user → Viewer application: opens viewer
- Viewer application → Replay loading: loads replay
- Replay loading → HTTP service: requests replay
- HTTP service → Compressed replay files: serves replay
- Viewer application → Replay playback: starts playback
- Replay playback → Viewer state: updates playhead
- Viewer application → Viewer state: reads state
- Viewer application → Live map rendering: renders map
- Viewer application → Kill feed: activates feed
- Viewer application → Player stats view: shows stats
- Player stats view → HTTP service: requests stats
- HTTP service → Stats and ELO: reads statistics
- CLI and orchestration → Central ingest client: pushes finished matches
- Central ingest client → Stats and ELO: reads match bundle
- Central ingest client → Optional central platform: sends enrolled data
