# ricardomsanti/antagon architecture

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

- Interactive diagram: https://gitdiagram.com/ricardomsanti/antagon
- Repository: https://github.com/ricardomsanti/antagon

## Overview

Antagon is a local, terminal-based voice and text sparring partner. The user’s thoughts are captured into a transcript, structured as an argument map, reviewed and explicitly approved, then challenged by a selected persona; intensity and depth control the challenge. The TUI drives session orchestration, while the voice engine handles local transcription, barge-in, and speech playback. The README also documents persona creation and optional Unbound models. Some subsystem links are based on README or module documentation because their implementation was not sampled.

Main entry points: [`antagon/session/controller.py`](https://github.com/ricardomsanti/antagon/blob/master/antagon/session/controller.py) (Session controller), [`antagon/voice/engine.py`](https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/engine.py) (Voice engine), [`antagon/tui/app.py`](https://github.com/ricardomsanti/antagon/blob/master/antagon/tui/app.py) (Terminal UI), [`antagon/llm/client.py`](https://github.com/ricardomsanti/antagon/blob/master/antagon/llm/client.py) (Ollama client)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_interaction["Session interaction"]
  node_tui["Terminal UI<br/>[app.py]"]
  node_controller["Session controller<br/>[controller.py]"]
  node_state["Session state<br/>[state.py]"]
end

subgraph group_reasoning["Argument and debate"]
  node_argmap["Argument mapping<br/>[argument_map.py]"]
  node_contrast["Contrast engine<br/>[contrast.py]"]
end

subgraph group_voice["Voice pipeline"]
  node_voice_engine["Voice engine<br/>[engine.py]"]
  node_vad["Speech detection<br/>[vad.py]"]
  node_stt["Speech recognition<br/>[stt.py]"]
  node_tts["Speech synthesis<br/>[tts.py]"]
end

subgraph group_personas["Persona management"]
  node_persona_data["Persona sheets"]
  node_persona_loader["Persona roster<br/>[personas.py]"]
  node_forge_ui["Persona forge UI<br/>[forge.py]"]
  node_forge["Persona authoring<br/>[persona_forge.py]"]
end

subgraph group_runtime["Local runtime"]
  node_config["Configuration<br/>[config.py]"]
  node_ollama_client["Ollama client<br/>[client.py]"]
end

node_user(("User"))
node_ollama{{"Ollama"}}
node_audio{{"Microphone and speakers"}}
node_unbound{{"Unbound model"}}

node_user -->|"type thoughts"| node_tui
node_user -->|"speak"| node_audio
node_audio -->|"audio input"| node_voice_engine
node_tui -->|"drive session"| node_controller
node_controller -->|"update session"| node_state
node_controller -->|"read settings"| node_config
node_controller -->|"load roster"| node_persona_loader
node_persona_loader -->|"read sheets"| node_persona_data
node_controller -->|"structure transcript"| node_argmap
node_argmap -->|"request map"| node_ollama_client
node_controller -->|"draft challenge"| node_contrast
node_contrast -->|"request reply"| node_ollama_client
node_ollama_client -->|"chat requests"| node_ollama
node_tui -->|"consume voice events"| node_voice_engine
node_voice_engine -->|"detect speech"| node_vad
node_voice_engine -->|"transcribe audio"| node_stt
node_voice_engine -->|"synthesize replies"| node_tts
node_voice_engine -->|"play audio"| node_audio
node_tui -->|"open forge"| node_forge_ui
node_forge_ui -->|"author persona"| node_forge
node_forge -->|"generate sheet"| node_ollama_client
node_forge_ui -->|"install persona"| node_controller
node_forge -->|"write sheet"| node_persona_data
node_contrast -.->|"optional model"| node_unbound

click node_tui "https://github.com/ricardomsanti/antagon/blob/master/antagon/tui/app.py"
click node_controller "https://github.com/ricardomsanti/antagon/blob/master/antagon/session/controller.py"
click node_state "https://github.com/ricardomsanti/antagon/blob/master/antagon/session/state.py"
click node_config "https://github.com/ricardomsanti/antagon/blob/master/antagon/config.py"
click node_argmap "https://github.com/ricardomsanti/antagon/blob/master/antagon/llm/argument_map.py"
click node_contrast "https://github.com/ricardomsanti/antagon/blob/master/antagon/contrast.py"
click node_ollama_client "https://github.com/ricardomsanti/antagon/blob/master/antagon/llm/client.py"
click node_persona_data "https://github.com/ricardomsanti/antagon/tree/master/personas"
click node_persona_loader "https://github.com/ricardomsanti/antagon/blob/master/antagon/personas.py"
click node_forge_ui "https://github.com/ricardomsanti/antagon/blob/master/antagon/tui/forge.py"
click node_forge "https://github.com/ricardomsanti/antagon/blob/master/antagon/persona_forge.py"
click node_voice_engine "https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/engine.py"
click node_vad "https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/vad.py"
click node_stt "https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/stt.py"
click node_tts "https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/tts.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_tui,node_controller,node_state,node_user toneBlue
class node_argmap,node_contrast toneAmber
class node_voice_engine,node_vad,node_stt,node_tts toneMint
class node_persona_data,node_persona_loader,node_forge_ui,node_forge toneRose
class node_config,node_ollama_client,node_ollama,node_audio,node_unbound toneIndigo
```

## Components

### Session interaction

- [Terminal UI](https://github.com/ricardomsanti/antagon/blob/master/antagon/tui/app.py): `antagon/tui/app.py`
- [Session controller](https://github.com/ricardomsanti/antagon/blob/master/antagon/session/controller.py): `antagon/session/controller.py`
- [Session state](https://github.com/ricardomsanti/antagon/blob/master/antagon/session/state.py): `antagon/session/state.py`

### Argument and debate

- [Argument mapping](https://github.com/ricardomsanti/antagon/blob/master/antagon/llm/argument_map.py): `antagon/llm/argument_map.py`
- [Contrast engine](https://github.com/ricardomsanti/antagon/blob/master/antagon/contrast.py): `antagon/contrast.py`

### Voice pipeline

- [Voice engine](https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/engine.py): `antagon/voice/engine.py`
- [Speech detection](https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/vad.py): `antagon/voice/vad.py`
- [Speech recognition](https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/stt.py): `antagon/voice/stt.py`
- [Speech synthesis](https://github.com/ricardomsanti/antagon/blob/master/antagon/voice/tts.py): `antagon/voice/tts.py`

### Persona management

- [Persona sheets](https://github.com/ricardomsanti/antagon/tree/master/personas): `personas`
- [Persona roster](https://github.com/ricardomsanti/antagon/blob/master/antagon/personas.py): `antagon/personas.py`
- [Persona forge UI](https://github.com/ricardomsanti/antagon/blob/master/antagon/tui/forge.py): `antagon/tui/forge.py`
- [Persona authoring](https://github.com/ricardomsanti/antagon/blob/master/antagon/persona_forge.py): `antagon/persona_forge.py`

### Local runtime

- [Configuration](https://github.com/ricardomsanti/antagon/blob/master/antagon/config.py): `antagon/config.py`
- [Ollama client](https://github.com/ricardomsanti/antagon/blob/master/antagon/llm/client.py): `antagon/llm/client.py`

### Other components

- **User**
- **Ollama**
- **Microphone and speakers**
- **Unbound model**

## Connections

- User → Terminal UI: type thoughts
- User → Microphone and speakers: speak
- Microphone and speakers → Voice engine: audio input
- Terminal UI → Session controller: drive session
- Session controller → Session state: update session
- Session controller → Configuration: read settings
- Session controller → Persona roster: load roster
- Persona roster → Persona sheets: read sheets
- Session controller → Argument mapping: structure transcript
- Argument mapping → Ollama client: request map
- Session controller → Contrast engine: draft challenge
- Contrast engine → Ollama client: request reply
- Ollama client → Ollama: chat requests
- Terminal UI → Voice engine: consume voice events
- Voice engine → Speech detection: detect speech
- Voice engine → Speech recognition: transcribe audio
- Voice engine → Speech synthesis: synthesize replies
- Voice engine → Microphone and speakers: play audio
- Terminal UI → Persona forge UI: open forge
- Persona forge UI → Persona authoring: author persona
- Persona authoring → Ollama client: generate sheet
- Persona forge UI → Session controller: install persona
- Persona authoring → Persona sheets: write sheet
- Contrast engine → Unbound model: optional model
