# drymek/treadmill architecture

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

- Interactive diagram: https://gitdiagram.com/drymek/treadmill
- Repository: https://github.com/drymek/treadmill

## Overview

The repository provides BLE treadmill control libraries and applications, centered on the HMS Workout Android app: users create or import workout plans, save them, then run them against a treadmill or simulator. The graph also retains the documented panel apps, Go probe, and workout validator. Some subsystem links rely on README descriptions or SOURCE INDEX references; unsampled implementation details are not inferred as direct calls.

Main entry points: [`src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutService.kt`](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutService.kt) (Run service), [`src/go/panel/main.go`](https://github.com/drymek/treadmill/blob/main/src/go/panel/main.go) (Go terminal panel), [`src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/data/WorkoutRepository.kt`](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/data/WorkoutRepository.kt) (Workout library), [`src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Transport.kt`](https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Transport.kt) (Kotlin transport)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_workout["HMS Workout"]
  node_workout_ui["Workout screens<br/>[EditorScreen.kt]"]
  node_workout_vm["App state<br/>[AppViewModel.kt]"]
  node_repository["Workout library"]
  node_workout_format["Workout model<br/>[Workout.kt]"]
  node_workout_parser["Workout parser<br/>[WorkoutParser.kt]"]
  node_workout_writer["Workout writer<br/>[WorkoutWriter.kt]"]
  node_workout_service["Run service<br/>[WorkoutService.kt]"]
  node_workout_runner["Workout runner<br/>[WorkoutRunner.kt]"]
  node_ble_scanner["BLE scanner<br/>[BleScanner.kt]"]
  node_workout_ble["Workout BLE<br/>[BleTransport.kt]"]
end

subgraph group_control["Treadmill Control"]
  node_kotlin_client["Kotlin client<br/>[Client.kt]"]
  node_kotlin_transport["Kotlin transport<br/>[Transport.kt]"]
  node_kotlin_reconnect["Reconnect transport"]
  node_kotlin_protocol["Kotlin protocol<br/>[Protocol.kt]"]
  node_kotlin_command["Command encoding<br/>[Command.kt]"]
  node_kotlin_status["Status decoding<br/>[Status.kt]"]
  node_simulator["Kotlin simulator<br/>[Simulator.kt]"]
  node_go_client["Go client<br/>[client.go]"]
  node_go_ble["Go Bluetooth<br/>[bluetooth.go]"]
  node_go_protocol["Go protocol<br/>[protocol.go]"]
  node_go_simulator["Go simulator<br/>[simulator.go]"]
end

subgraph group_panels["Virtual Panels"]
  node_go_panel["Go terminal panel<br/>[main.go]"]
  node_go_panel_model["Go panel model<br/>[model.go]"]
  node_kotlin_panel["Android panel<br/>[PanelController.kt]"]
  node_panel_activity["Panel activity<br/>[MainActivity.kt]"]
end

subgraph group_tools["Go Tools"]
  node_probe["Protocol probe<br/>[main.go]"]
  node_probe_commands["Probe commands<br/>[command.go]"]
  node_validator["Workout validator<br/>[main.go]"]
  node_validator_parse["Workout validation<br/>[parse.go]"]
end

node_user(("Runner"))
node_yaml_files["Workout files"]
node_treadmill(("BLE treadmill"))
node_panel_user(("Console user"))

node_user -->|"designs and runs"| node_workout_ui
node_workout_ui -->|"edits plans"| node_workout_vm
node_workout_vm -->|"manages library"| node_repository
node_workout_vm -->|"starts runs"| node_workout_service
node_repository -->|"parses imports"| node_workout_parser
node_repository -->|"writes files"| node_workout_writer
node_repository -->|"stores model"| node_workout_format
node_workout_parser -->|"builds model"| node_workout_format
node_workout_writer -->|"serializes model"| node_workout_format
node_yaml_files -->|"imports and exports"| node_repository
node_workout_service -->|"starts runner"| node_workout_runner
node_workout_runner -->|"controls treadmill"| node_kotlin_client
node_workout_service -->|"selects transport"| node_workout_ble
node_workout_service -->|"supports simulation"| node_simulator
node_workout_service -.->|"discovers device"| node_ble_scanner
node_workout_ble -->|"implements transport"| node_kotlin_transport
node_kotlin_client -->|"reads and writes"| node_kotlin_transport
node_kotlin_reconnect -->|"wraps transport"| node_kotlin_transport
node_kotlin_client -->|"sends commands"| node_kotlin_command
node_kotlin_client -->|"decodes updates"| node_kotlin_status
node_simulator -->|"implements transport"| node_kotlin_transport
node_kotlin_command -.->|"encodes frames"| node_kotlin_protocol
node_kotlin_status -.->|"decodes frames"| node_kotlin_protocol
node_kotlin_transport -.->|"exchanges BLE frames"| node_treadmill
node_panel_user -->|"operates console"| node_go_panel
node_go_panel -->|"runs interface"| node_go_panel_model
node_go_panel -->|"connects over BLE"| node_go_ble
node_go_panel -->|"selects simulator"| node_go_simulator
node_go_panel -->|"creates client"| node_go_client
node_go_client -->|"uses protocol"| node_go_protocol
node_go_ble -.->|"exchanges BLE data"| node_treadmill
node_probe -->|"connects to device"| node_go_ble
node_probe -.->|"sends commands"| node_probe_commands
node_probe_commands -->|"encodes commands"| node_go_protocol
node_validator -->|"validates plans"| node_validator_parse

click node_workout_ui "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/ui/EditorScreen.kt"
click node_workout_vm "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/AppViewModel.kt"
click node_repository "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/data/WorkoutRepository.kt"
click node_workout_format "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/Workout.kt"
click node_workout_parser "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/WorkoutParser.kt"
click node_workout_writer "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/WorkoutWriter.kt"
click node_workout_service "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutService.kt"
click node_workout_runner "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutRunner.kt"
click node_ble_scanner "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/bluetooth/BleScanner.kt"
click node_workout_ble "https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/bluetooth/BleTransport.kt"
click node_kotlin_client "https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Client.kt"
click node_kotlin_transport "https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Transport.kt"
click node_kotlin_reconnect "https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/ReconnectingTransport.kt"
click node_kotlin_protocol "https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Protocol.kt"
click node_kotlin_command "https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Command.kt"
click node_kotlin_status "https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Status.kt"
click node_simulator "https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/simulator/Simulator.kt"
click node_go_client "https://github.com/drymek/treadmill/blob/main/src/go/lib/treadmill/client.go"
click node_go_ble "https://github.com/drymek/treadmill/blob/main/src/go/lib/bluetooth/bluetooth.go"
click node_go_protocol "https://github.com/drymek/treadmill/blob/main/src/go/lib/protocol/protocol.go"
click node_go_simulator "https://github.com/drymek/treadmill/blob/main/src/go/lib/treadmilltest/simulator.go"
click node_go_panel "https://github.com/drymek/treadmill/blob/main/src/go/panel/main.go"
click node_go_panel_model "https://github.com/drymek/treadmill/blob/main/src/go/panel/model.go"
click node_kotlin_panel "https://github.com/drymek/treadmill/blob/main/src/kotlin/panel/src/main/kotlin/com/craftersy/treadmill/panel/PanelController.kt"
click node_panel_activity "https://github.com/drymek/treadmill/blob/main/src/kotlin/panel/src/main/kotlin/com/craftersy/treadmill/panel/MainActivity.kt"
click node_probe "https://github.com/drymek/treadmill/blob/main/src/go/tools/probe/main.go"
click node_probe_commands "https://github.com/drymek/treadmill/blob/main/src/go/tools/probe/command.go"
click node_validator "https://github.com/drymek/treadmill/blob/main/src/go/tools/workout/main.go"
click node_validator_parse "https://github.com/drymek/treadmill/blob/main/src/go/tools/workout/lib/parse.go"

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_workout_ui,node_workout_vm,node_repository,node_workout_format,node_workout_parser,node_workout_writer,node_workout_service,node_workout_runner,node_ble_scanner,node_workout_ble,node_panel_user toneBlue
class node_kotlin_client,node_kotlin_transport,node_kotlin_reconnect,node_kotlin_protocol,node_kotlin_command,node_kotlin_status,node_simulator,node_go_client,node_go_ble,node_go_protocol,node_go_simulator toneAmber
class node_go_panel,node_go_panel_model,node_kotlin_panel,node_panel_activity toneMint
class node_probe,node_probe_commands,node_validator,node_validator_parse toneRose
class node_user,node_yaml_files,node_treadmill toneIndigo
```

## Components

### HMS Workout

- [Workout screens](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/ui/EditorScreen.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/ui/EditorScreen.kt`
- [App state](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/AppViewModel.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/AppViewModel.kt`
- [Workout library](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/data/WorkoutRepository.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/data/WorkoutRepository.kt`
- [Workout model](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/Workout.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/Workout.kt`
- [Workout parser](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/WorkoutParser.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/WorkoutParser.kt`
- [Workout writer](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/WorkoutWriter.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/WorkoutWriter.kt`
- [Run service](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutService.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutService.kt`
- [Workout runner](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutRunner.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutRunner.kt`
- [BLE scanner](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/bluetooth/BleScanner.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/bluetooth/BleScanner.kt`
- [Workout BLE](https://github.com/drymek/treadmill/blob/main/src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/bluetooth/BleTransport.kt): `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/bluetooth/BleTransport.kt`

### Treadmill Control

- [Kotlin client](https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Client.kt): `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Client.kt`
- [Kotlin transport](https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Transport.kt): `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Transport.kt`
- [Reconnect transport](https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/ReconnectingTransport.kt): `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/ReconnectingTransport.kt`
- [Kotlin protocol](https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Protocol.kt): `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Protocol.kt`
- [Command encoding](https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Command.kt): `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Command.kt`
- [Status decoding](https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Status.kt): `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/protocol/Status.kt`
- [Kotlin simulator](https://github.com/drymek/treadmill/blob/main/src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/simulator/Simulator.kt): `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/simulator/Simulator.kt`
- [Go client](https://github.com/drymek/treadmill/blob/main/src/go/lib/treadmill/client.go): `src/go/lib/treadmill/client.go`
- [Go Bluetooth](https://github.com/drymek/treadmill/blob/main/src/go/lib/bluetooth/bluetooth.go): `src/go/lib/bluetooth/bluetooth.go`
- [Go protocol](https://github.com/drymek/treadmill/blob/main/src/go/lib/protocol/protocol.go): `src/go/lib/protocol/protocol.go`
- [Go simulator](https://github.com/drymek/treadmill/blob/main/src/go/lib/treadmilltest/simulator.go): `src/go/lib/treadmilltest/simulator.go`

### Virtual Panels

- [Go terminal panel](https://github.com/drymek/treadmill/blob/main/src/go/panel/main.go): `src/go/panel/main.go`
- [Go panel model](https://github.com/drymek/treadmill/blob/main/src/go/panel/model.go): `src/go/panel/model.go`
- [Android panel](https://github.com/drymek/treadmill/blob/main/src/kotlin/panel/src/main/kotlin/com/craftersy/treadmill/panel/PanelController.kt): `src/kotlin/panel/src/main/kotlin/com/craftersy/treadmill/panel/PanelController.kt`
- [Panel activity](https://github.com/drymek/treadmill/blob/main/src/kotlin/panel/src/main/kotlin/com/craftersy/treadmill/panel/MainActivity.kt): `src/kotlin/panel/src/main/kotlin/com/craftersy/treadmill/panel/MainActivity.kt`

### Go Tools

- [Protocol probe](https://github.com/drymek/treadmill/blob/main/src/go/tools/probe/main.go): `src/go/tools/probe/main.go`
- [Probe commands](https://github.com/drymek/treadmill/blob/main/src/go/tools/probe/command.go): `src/go/tools/probe/command.go`
- [Workout validator](https://github.com/drymek/treadmill/blob/main/src/go/tools/workout/main.go): `src/go/tools/workout/main.go`
- [Workout validation](https://github.com/drymek/treadmill/blob/main/src/go/tools/workout/lib/parse.go): `src/go/tools/workout/lib/parse.go`

### Other components

- **Runner**
- **Workout files**
- **BLE treadmill**
- **Console user**

## Connections

- Runner → Workout screens: designs and runs (evidence: `README.md`)
- Workout screens → App state: edits plans (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/ui/EditorScreen.kt`)
- App state → Workout library: manages library (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/AppViewModel.kt`)
- App state → Run service: starts runs (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/AppViewModel.kt`)
- Workout library → Workout parser: parses imports (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/data/WorkoutRepository.kt`)
- Workout library → Workout writer: writes files (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/data/WorkoutRepository.kt`)
- Workout library → Workout model: stores model (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/data/WorkoutRepository.kt`)
- Workout parser → Workout model: builds model (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/WorkoutParser.kt`)
- Workout writer → Workout model: serializes model (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/format/WorkoutWriter.kt`)
- Workout files → Workout library: imports and exports (evidence: `README.md`)
- Run service → Workout runner: starts runner (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutService.kt`)
- Workout runner → Kotlin client: controls treadmill (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutRunner.kt`)
- Run service → Workout BLE: selects transport (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutService.kt`)
- Run service → Kotlin simulator: supports simulation (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/run/WorkoutService.kt`)
- Run service → BLE scanner: discovers device
- Workout BLE → Kotlin transport: implements transport (evidence: `src/kotlin/workout/src/main/kotlin/com/craftersy/treadmill/workout/bluetooth/BleTransport.kt`)
- Kotlin client → Kotlin transport: reads and writes (evidence: `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Client.kt`)
- Reconnect transport → Kotlin transport: wraps transport (evidence: `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/ReconnectingTransport.kt`)
- Kotlin client → Command encoding: sends commands (evidence: `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Client.kt`)
- Kotlin client → Status decoding: decodes updates (evidence: `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/client/Client.kt`)
- Kotlin simulator → Kotlin transport: implements transport (evidence: `src/kotlin/lib/src/main/kotlin/com/craftersy/treadmill/simulator/Simulator.kt`)
- Command encoding → Kotlin protocol: encodes frames
- Status decoding → Kotlin protocol: decodes frames
- Kotlin transport → BLE treadmill: exchanges BLE frames
- Console user → Go terminal panel: operates console (evidence: `README.md`)
- Go terminal panel → Go panel model: runs interface (evidence: `src/go/panel/main.go`)
- Go terminal panel → Go Bluetooth: connects over BLE (evidence: `src/go/panel/main.go`)
- Go terminal panel → Go simulator: selects simulator (evidence: `src/go/panel/main.go`)
- Go terminal panel → Go client: creates client (evidence: `src/go/panel/main.go`)
- Go client → Go protocol: uses protocol (evidence: `src/go/lib/treadmill/client.go`)
- Go Bluetooth → BLE treadmill: exchanges BLE data
- Protocol probe → Go Bluetooth: connects to device (evidence: `src/go/tools/probe/main.go`)
- Protocol probe → Probe commands: sends commands
- Probe commands → Go protocol: encodes commands (evidence: `src/go/tools/probe/command.go`)
- Workout validator → Workout validation: validates plans (evidence: `src/go/tools/workout/main.go`)
