# kotlinds/ai-plays-pokemon architecture

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

- Interactive diagram: https://gitdiagram.com/kotlinds/ai-plays-pokemon
- Repository: https://github.com/kotlinds/ai-plays-pokemon

## Overview

ai-plays-pokemon is a live Pokémon HeartGold-playing application: a person selects a backend and mode, then either the built-in player or an external MCP agent observes game state and acts through the emulator. Its main stages are emulator-backed state/action handling, agent memory and orchestration, and decision backends; the UI also exposes configuration and run results. README-documented capabilities include Jev, Koog LLMs, Claude Code, MCP tools, and Pure/Assisted/Hybrid modes. Some subsystem links rely on README descriptions because their implementation was not sampled.

Main entry points: [`src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt`](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt) (App controller), [`src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/GameMcpServer.kt`](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/GameMcpServer.kt) (MCP game server), [`src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/ConsoleHost.kt`](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/ConsoleHost.kt) (Console host), [`src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PokemonPlayer.kt`](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PokemonPlayer.kt) (Autonomous player)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_app["App and control"]
  node_main["Application entry<br/>[Main.kt]"]
  node_ui["Desktop UI<br/>[App.kt]"]
  node_panel["Control panel<br/>[ControlPanel.kt]"]
  node_controller["App controller<br/>[AppController.kt]"]
  node_config["App configuration<br/>[AppConfig.kt]"]
end

subgraph group_gameplay["Agent gameplay"]
  node_settings["Player settings<br/>[PlayerSettings.kt]"]
  node_player["Autonomous player<br/>[PokemonPlayer.kt]"]
  node_session["Agent session<br/>[AgentSession.kt]"]
  node_gamesession["Game state and actions<br/>[GameSession.kt]"]
  node_memory["Agent memory<br/>[AgentMemory.kt]"]
  node_stats["Run statistics<br/>[RunStats.kt]"]
end

subgraph group_decisions["Decision backends"]
  node_decision["Decision interface<br/>[DecisionModel.kt]"]
  node_jev["Jev decision model"]
  node_jevclient["Jev API client<br/>[JevClient.kt]"]
  node_llm["Koog LLM model"]
  node_provider["LLM providers<br/>[LlmProvider.kt]"]
  node_claude["Claude Code model"]
end

subgraph group_emulator["Emulation"]
  node_console["Console host<br/>[ConsoleHost.kt]"]
  node_emulator["Emulator adapter<br/>[Emulator.kt]"]
  node_screen["Emulator display<br/>[EmulatorScreen.kt]"]
end

subgraph group_mcp["External agents"]
  node_mcpserver["MCP game server<br/>[GameMcpServer.kt]"]
  node_delivery["Delivery tracking<br/>[DeliveryTracker.kt]"]
end

node_person(("Person"))
node_agent(("External MCP agent"))
node_ai(("Model service"))

node_person -->|"controls"| node_ui
node_main -->|"starts"| node_ui
node_ui -->|"renders"| node_panel
node_ui -->|"renders"| node_screen
node_panel -->|"configures"| node_controller
node_controller -->|"reads and saves"| node_config
node_controller -->|"sets"| node_settings
node_controller -->|"controls"| node_console
node_controller -->|"creates"| node_player
node_controller -->|"starts"| node_mcpserver
node_player -->|"runs"| node_session
node_player -->|"requests choices"| node_decision
node_player -->|"records runs"| node_stats
node_session -->|"delegates state and actions"| node_gamesession
node_session -->|"uses"| node_memory
node_gamesession -->|"observes console"| node_console
node_decision -->|"implemented by"| node_jev
node_decision -->|"implemented by"| node_llm
node_decision -->|"implemented by"| node_claude
node_jev -->|"sends requests"| node_jevclient
node_jevclient -->|"calls Jev API"| node_ai
node_llm -->|"uses"| node_provider
node_provider -->|"calls model service"| node_ai
node_claude -->|"invokes CLI"| node_ai
node_console -->|"wraps"| node_emulator
node_console -->|"supplies display"| node_screen
node_agent -->|"calls tools"| node_mcpserver
node_mcpserver -->|"reads and acts"| node_gamesession
node_mcpserver -->|"accesses emulator"| node_console
node_mcpserver -->|"tracks delivery"| node_delivery

click node_main "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/Main.kt"
click node_ui "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/App.kt"
click node_panel "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/ControlPanel.kt"
click node_controller "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt"
click node_config "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/config/AppConfig.kt"
click node_settings "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PlayerSettings.kt"
click node_player "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PokemonPlayer.kt"
click node_session "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/AgentSession.kt"
click node_gamesession "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/GameSession.kt"
click node_memory "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/AgentMemory.kt"
click node_stats "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/RunStats.kt"
click node_decision "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/DecisionModel.kt"
click node_jev "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/jev/JevDecisionModel.kt"
click node_jevclient "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/jev/JevClient.kt"
click node_llm "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/llm/LlmDecisionModel.kt"
click node_provider "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/llm/LlmProvider.kt"
click node_claude "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/claudecode/ClaudeCodeDecisionModel.kt"
click node_console "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/ConsoleHost.kt"
click node_emulator "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/Emulator.kt"
click node_screen "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/EmulatorScreen.kt"
click node_mcpserver "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/GameMcpServer.kt"
click node_delivery "https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/DeliveryTracker.kt"

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_main,node_ui,node_panel,node_controller,node_config toneBlue
class node_settings,node_player,node_session,node_gamesession,node_memory,node_stats toneAmber
class node_decision,node_jev,node_jevclient,node_llm,node_provider,node_claude toneMint
class node_console,node_emulator,node_screen toneRose
class node_mcpserver,node_delivery,node_person,node_agent,node_ai toneIndigo
```

## Components

### App and control

- [Application entry](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/Main.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/Main.kt`
- [Desktop UI](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/App.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/App.kt`
- [Control panel](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/ControlPanel.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/ControlPanel.kt`
- [App controller](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt`
- [App configuration](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/config/AppConfig.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/config/AppConfig.kt`

### Agent gameplay

- [Player settings](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PlayerSettings.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PlayerSettings.kt`
- [Autonomous player](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PokemonPlayer.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PokemonPlayer.kt`
- [Agent session](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/AgentSession.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/AgentSession.kt`
- [Game state and actions](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/GameSession.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/GameSession.kt`
- [Agent memory](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/AgentMemory.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/AgentMemory.kt`
- [Run statistics](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/RunStats.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/RunStats.kt`

### Decision backends

- [Decision interface](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/DecisionModel.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/DecisionModel.kt`
- [Jev decision model](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/jev/JevDecisionModel.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/jev/JevDecisionModel.kt`
- [Jev API client](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/jev/JevClient.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/jev/JevClient.kt`
- [Koog LLM model](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/llm/LlmDecisionModel.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/llm/LlmDecisionModel.kt`
- [LLM providers](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/llm/LlmProvider.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/llm/LlmProvider.kt`
- [Claude Code model](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/claudecode/ClaudeCodeDecisionModel.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/claudecode/ClaudeCodeDecisionModel.kt`

### Emulation

- [Console host](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/ConsoleHost.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/ConsoleHost.kt`
- [Emulator adapter](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/Emulator.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/Emulator.kt`
- [Emulator display](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/EmulatorScreen.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/EmulatorScreen.kt`

### External agents

- [MCP game server](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/GameMcpServer.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/GameMcpServer.kt`
- [Delivery tracking](https://github.com/kotlinds/ai-plays-pokemon/blob/main/src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/DeliveryTracker.kt): `src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/DeliveryTracker.kt`

### Other components

- **Person**
- **External MCP agent**
- **Model service**

## Connections

- Person → Desktop UI: controls (evidence: `README.md`)
- Application entry → Desktop UI: starts (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/Main.kt`)
- Desktop UI → Control panel: renders (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/App.kt`)
- Desktop UI → Emulator display: renders (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/App.kt`)
- Control panel → App controller: configures (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/ControlPanel.kt`)
- App controller → App configuration: reads and saves (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt`)
- App controller → Player settings: sets (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt`)
- App controller → Console host: controls (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt`)
- App controller → Autonomous player: creates (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt`)
- App controller → MCP game server: starts (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/ui/AppController.kt`)
- Autonomous player → Agent session: runs (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PokemonPlayer.kt`)
- Autonomous player → Decision interface: requests choices (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PokemonPlayer.kt`)
- Autonomous player → Run statistics: records runs (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/PokemonPlayer.kt`)
- Agent session → Game state and actions: delegates state and actions (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/AgentSession.kt`)
- Agent session → Agent memory: uses (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/AgentSession.kt`)
- Game state and actions → Console host: observes console (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/agent/GameSession.kt`)
- Decision interface → Jev decision model: implemented by (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/jev/JevDecisionModel.kt`)
- Decision interface → Koog LLM model: implemented by (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/llm/LlmDecisionModel.kt`)
- Decision interface → Claude Code model: implemented by (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/claudecode/ClaudeCodeDecisionModel.kt`)
- Jev decision model → Jev API client: sends requests (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/jev/JevDecisionModel.kt`)
- Jev API client → Model service: calls Jev API (evidence: `README.md`)
- Koog LLM model → LLM providers: uses (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/decision/llm/LlmDecisionModel.kt`)
- LLM providers → Model service: calls model service (evidence: `README.md`)
- Claude Code model → Model service: invokes CLI (evidence: `README.md`)
- Console host → Emulator adapter: wraps (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/emulator/ConsoleHost.kt`)
- Console host → Emulator display: supplies display (evidence: `README.md`)
- External MCP agent → MCP game server: calls tools (evidence: `README.md`)
- MCP game server → Game state and actions: reads and acts (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/GameMcpServer.kt`)
- MCP game server → Console host: accesses emulator (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/GameMcpServer.kt`)
- MCP game server → Delivery tracking: tracks delivery (evidence: `src/main/kotlin/me/nathanfallet/aiplayspokemon/mcp/GameMcpServer.kt`)
