# mymtgo/sidecar architecture

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

- Interactive diagram: https://gitdiagram.com/mymtgo/sidecar
- Repository: https://github.com/mymtgo/sidecar

## Overview

MTGO Sidecar is a Windows helper that observes a live MTGO client through MTGOSDK and produces an NDJSON event stream and status file for the app’s PHP ingester. The main workflow is supervisor startup and version gating, SDK attachment and probing, match/game tracking, snapshot-to-event folding, and durable output. The graph includes documented status, logging, and cache capabilities. Some adapter and supervisor wiring is based on README descriptions because the supplied excerpts are partial.

Main entry points: [`MyMtgo.Sidecar/Program.cs`](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Program.cs) (Supervisor Loop), [`MyMtgo.Sidecar/Sdk/SessionRunner.cs`](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SessionRunner.cs) (Session Runner), [`MyMtgo.Sidecar/Sdk/SdkGameRecorder.cs`](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SdkGameRecorder.cs) (Game Recorder), [`MyMtgo.Sidecar.Core/Writer/EventWriter.cs`](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Writer/EventWriter.cs) (Event Writer)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_supervision["Supervision"]
  node_options["CLI Options<br/>[SidecarOptions.cs]"]
  node_program["Supervisor Loop<br/>[Program.cs]"]
  node_parent_watch["Parent Watch<br/>[ParentWatch.cs]"]
  node_version_gate["Version Gate<br/>[VersionGate.cs]"]
  node_known_good["Known-Good Cache<br/>[KnownGoodCache.cs]"]
end

subgraph group_sdk["MTGO Adapter"]
  node_attachment["SDK Attachment<br/>[SdkAttachment.cs]"]
  node_probe["Health Probe<br/>[Probe.cs]"]
  node_session["Session Runner<br/>[SessionRunner.cs]"]
  node_snapshot_reader["Snapshot Reader<br/>[SnapshotReader.cs]"]
  node_snapshot_mapper["Snapshot Mapper<br/>[SnapshotMapper.cs]"]
  node_catalog["Catalog Resolver<br/>[CatalogResolver.cs]"]
end

subgraph group_tracking["Game Tracking"]
  node_game_recorder["Game Recorder<br/>[SdkGameRecorder.cs]"]
  node_match_tracker["Match Tracker<br/>[SdkMatchTracker.cs]"]
  node_snapshot["Game Snapshot<br/>[GameSnapshot.cs]"]
  node_fold_recorder["Event Folding<br/>[GameRecorder.cs]"]
  node_snapshot_differ["Snapshot Differ<br/>[SnapshotDiffer.cs]"]
  node_keyframe["Keyframe Builder<br/>[KeyframeBuilder.cs]"]
end

subgraph group_events["Events and Output"]
  node_pending["Pending Events<br/>[PendingEvent.cs]"]
  node_event_writer["Event Writer<br/>[EventWriter.cs]"]
  node_envelope["Event Envelope<br/>[EventEnvelope.cs]"]
  node_event_file["NDJSON Stream"]
end

subgraph group_operations["Status and Diagnostics"]
  node_status_writer["Status Writer<br/>[StatusWriter.cs]"]
  node_status_file["Status JSON"]
  node_logger["Rolling Logger"]
  node_log_file["Diagnostic Log"]
end

node_app(("Parent App"))
node_mtgo(("MTGO Client"))
node_php(("PHP Ingester"))
node_remote_config(("Remote Config"))

node_app -->|"starts with PID"| node_program
node_program -->|"parses arguments"| node_options
node_program -->|"watches parent"| node_parent_watch
node_program -->|"checks version"| node_version_gate
node_version_gate -.->|"fetches versions"| node_remote_config
node_version_gate -->|"reads and refreshes"| node_known_good
node_program -->|"attaches to MTGO"| node_attachment
node_attachment -->|"connects to"| node_mtgo
node_program -->|"runs session"| node_session
node_session -->|"subscribes to hooks"| node_mtgo
node_session -->|"runs probes"| node_probe
node_session -->|"creates per game"| node_game_recorder
node_session -->|"tracks match state"| node_match_tracker
node_game_recorder -->|"reads game state"| node_snapshot_reader
node_snapshot_reader -->|"maps SDK data"| node_snapshot_mapper
node_snapshot_mapper -->|"resolves cards"| node_catalog
node_snapshot_mapper -->|"produces snapshot"| node_snapshot
node_game_recorder -->|"records snapshots"| node_fold_recorder
node_fold_recorder -->|"diffs ticks"| node_snapshot_differ
node_fold_recorder -->|"builds keyframes"| node_keyframe
node_snapshot_differ -->|"emits changes"| node_pending
node_keyframe -->|"emits keyframes"| node_pending
node_match_tracker -->|"emits match events"| node_pending
node_game_recorder -->|"submits events"| node_event_writer
node_match_tracker -->|"submits events"| node_event_writer
node_event_writer -->|"stamps events"| node_envelope
node_event_writer -->|"appends lines"| node_event_file
node_php -->|"ingests events"| node_event_file
node_php -->|"reads state"| node_status_file
node_program -->|"updates status"| node_status_writer
node_status_writer -->|"writes atomically"| node_status_file
node_program -->|"logs diagnostics"| node_logger
node_logger -->|"writes rolling log"| node_log_file

click node_options "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Host/SidecarOptions.cs"
click node_program "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Program.cs"
click node_parent_watch "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Host/ParentWatch.cs"
click node_version_gate "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Gate/VersionGate.cs"
click node_known_good "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Gate/KnownGoodCache.cs"
click node_attachment "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SdkAttachment.cs"
click node_probe "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/Probe.cs"
click node_session "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SessionRunner.cs"
click node_snapshot_reader "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SnapshotReader.cs"
click node_snapshot_mapper "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SnapshotMapper.cs"
click node_catalog "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/CatalogResolver.cs"
click node_game_recorder "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SdkGameRecorder.cs"
click node_match_tracker "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SdkMatchTracker.cs"
click node_snapshot "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Model/GameSnapshot.cs"
click node_fold_recorder "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Fold/GameRecorder.cs"
click node_snapshot_differ "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Fold/SnapshotDiffer.cs"
click node_keyframe "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Fold/KeyframeBuilder.cs"
click node_pending "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Writer/PendingEvent.cs"
click node_event_writer "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Writer/EventWriter.cs"
click node_envelope "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Envelope/EventEnvelope.cs"
click node_status_writer "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Status/StatusWriter.cs"
click node_logger "https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Logging/RollingFileLogger.cs"

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_options,node_program,node_parent_watch,node_version_gate,node_known_good,node_mtgo toneBlue
class node_attachment,node_probe,node_session,node_snapshot_reader,node_snapshot_mapper,node_catalog toneAmber
class node_game_recorder,node_match_tracker,node_snapshot,node_fold_recorder,node_snapshot_differ,node_keyframe toneMint
class node_pending,node_event_writer,node_envelope,node_event_file toneRose
class node_status_writer,node_status_file,node_logger,node_log_file,node_app,node_php,node_remote_config toneIndigo
```

## Components

### Supervision

- [CLI Options](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Host/SidecarOptions.cs): `MyMtgo.Sidecar.Core/Host/SidecarOptions.cs`
- [Supervisor Loop](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Program.cs): `MyMtgo.Sidecar/Program.cs`
- [Parent Watch](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Host/ParentWatch.cs): `MyMtgo.Sidecar.Core/Host/ParentWatch.cs`
- [Version Gate](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Gate/VersionGate.cs): `MyMtgo.Sidecar.Core/Gate/VersionGate.cs`
- [Known-Good Cache](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Gate/KnownGoodCache.cs): `MyMtgo.Sidecar.Core/Gate/KnownGoodCache.cs`

### MTGO Adapter

- [SDK Attachment](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SdkAttachment.cs): `MyMtgo.Sidecar/Sdk/SdkAttachment.cs`
- [Health Probe](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/Probe.cs): `MyMtgo.Sidecar/Sdk/Probe.cs`
- [Session Runner](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SessionRunner.cs): `MyMtgo.Sidecar/Sdk/SessionRunner.cs`
- [Snapshot Reader](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SnapshotReader.cs): `MyMtgo.Sidecar/Sdk/SnapshotReader.cs`
- [Snapshot Mapper](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SnapshotMapper.cs): `MyMtgo.Sidecar/Sdk/SnapshotMapper.cs`
- [Catalog Resolver](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/CatalogResolver.cs): `MyMtgo.Sidecar/Sdk/CatalogResolver.cs`

### Game Tracking

- [Game Recorder](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SdkGameRecorder.cs): `MyMtgo.Sidecar/Sdk/SdkGameRecorder.cs`
- [Match Tracker](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar/Sdk/SdkMatchTracker.cs): `MyMtgo.Sidecar/Sdk/SdkMatchTracker.cs`
- [Game Snapshot](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Model/GameSnapshot.cs): `MyMtgo.Sidecar.Core/Model/GameSnapshot.cs`
- [Event Folding](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Fold/GameRecorder.cs): `MyMtgo.Sidecar.Core/Fold/GameRecorder.cs`
- [Snapshot Differ](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Fold/SnapshotDiffer.cs): `MyMtgo.Sidecar.Core/Fold/SnapshotDiffer.cs`
- [Keyframe Builder](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Fold/KeyframeBuilder.cs): `MyMtgo.Sidecar.Core/Fold/KeyframeBuilder.cs`

### Events and Output

- [Pending Events](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Writer/PendingEvent.cs): `MyMtgo.Sidecar.Core/Writer/PendingEvent.cs`
- [Event Writer](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Writer/EventWriter.cs): `MyMtgo.Sidecar.Core/Writer/EventWriter.cs`
- [Event Envelope](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Envelope/EventEnvelope.cs): `MyMtgo.Sidecar.Core/Envelope/EventEnvelope.cs`
- **NDJSON Stream**

### Status and Diagnostics

- [Status Writer](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Status/StatusWriter.cs): `MyMtgo.Sidecar.Core/Status/StatusWriter.cs`
- **Status JSON**
- [Rolling Logger](https://github.com/mymtgo/sidecar/blob/main/MyMtgo.Sidecar.Core/Logging/RollingFileLogger.cs): `MyMtgo.Sidecar.Core/Logging/RollingFileLogger.cs`
- **Diagnostic Log**

### Other components

- **Parent App**
- **MTGO Client**
- **PHP Ingester**
- **Remote Config**

## Connections

- Parent App → Supervisor Loop: starts with PID
- Supervisor Loop → CLI Options: parses arguments
- Supervisor Loop → Parent Watch: watches parent
- Supervisor Loop → Version Gate: checks version
- Version Gate → Remote Config: fetches versions
- Version Gate → Known-Good Cache: reads and refreshes
- Supervisor Loop → SDK Attachment: attaches to MTGO
- SDK Attachment → MTGO Client: connects to
- Supervisor Loop → Session Runner: runs session
- Session Runner → MTGO Client: subscribes to hooks
- Session Runner → Health Probe: runs probes
- Session Runner → Game Recorder: creates per game
- Session Runner → Match Tracker: tracks match state
- Game Recorder → Snapshot Reader: reads game state
- Snapshot Reader → Snapshot Mapper: maps SDK data
- Snapshot Mapper → Catalog Resolver: resolves cards
- Snapshot Mapper → Game Snapshot: produces snapshot
- Game Recorder → Event Folding: records snapshots
- Event Folding → Snapshot Differ: diffs ticks
- Event Folding → Keyframe Builder: builds keyframes
- Snapshot Differ → Pending Events: emits changes
- Keyframe Builder → Pending Events: emits keyframes
- Match Tracker → Pending Events: emits match events
- Game Recorder → Event Writer: submits events
- Match Tracker → Event Writer: submits events
- Event Writer → Event Envelope: stamps events
- Event Writer → NDJSON Stream: appends lines
- PHP Ingester → NDJSON Stream: ingests events
- PHP Ingester → Status JSON: reads state
- Supervisor Loop → Status Writer: updates status
- Status Writer → Status JSON: writes atomically
- Supervisor Loop → Rolling Logger: logs diagnostics
- Rolling Logger → Diagnostic Log: writes rolling log
