Voice-driven supervisor for Claude Code and Codex. You talk to a low-latency Realtime model in your terminal; whenever you ask for real work, it dispatches a job to a background coding agent and narrates the result when it lands.
🎤 ──▶ OpenAI Realtime (gpt-realtime-2) ──▶ 🔈
│
│ tool: delegate_to_orchestrator(slug, intent, …)
│ tool: sub_agent_progress(slug)
▼
OrchestratorJobManager
│ one worker task per slug, ordered within a slug,
│ concurrent across slugs
▼
┌───────┴────────┐
`claude -p` `codex exec`
(Claude Code) (Codex CLI)
There is exactly one realtime voice loop and an async worker pool for background agent jobs. Those are the two halves of the binary.
A single tokio::select!
loop that owns:
- a microphone stream (
cpal
, mono, resampled to 24 kHz) - a websocket to the OpenAI Realtime API
- a playback buffer (
cpal
again, jittered) - a channel of job-completion events from the worker pool
On startup it sends a session.update
that registers two tools — delegate_to_orchestrator
and sub_agent_progress
— and tells the model to use stable snake_case slugs for each background task. Reusing a slug continues the same orchestrator conversation; new slugs spawn parallel work. Run gamechat --print-realtime-config
to inspect the exact JSON.
OrchestratorJobManager
runs in its own task. Behind it:
One worker per slug. All sends forrefactor_docs
go through the sameOrchestratorSession
, in order. Different slugs run concurrently in independent sessions.A Workers stream snippets into a slug-keyed buffer;ProgressStore
.sub_agent_progress
queries it with built-in rate limiting (~5 s) so the model can't poll itself into a loop.A with two backends:Provider
/Session
trait— spawnsclaude
claude -p
per send. First send uses--name <slug>
; subsequent sends use--resume <session_id>
. Claude Code's server-side prompt cache does the heavy lifting; we don't maintain our own.— spawnscodex
codex exec
per send and tails its output back through the sameSendResult
shape.
Adding a third backend means implementing Provider
and wiring one match arm in main.rs
. The voice loop doesn't know which agent is on the other end.
curl -fsSL https://raw.githubusercontent.com/zdql/gamechat/main/install.sh | sh
Pulls the latest prebuilt binary for your platform from GitHub Releases and drops it in ~/.local/bin/gamechat
. Supported platforms: darwin-arm64
, darwin-x86_64
, linux-x86_64
, linux-arm64
.
The installer also prompts (hidden input) for your OPENAI_API_KEY
and stores it at ~/.config/gamechat/env
(mode 0600). gamechat
reads that file automatically from any working directory, so gamechat --realtime
just works after install. Skip the prompt with GAMECHAT_NO_PROMPT=1
.
If ~/.local/bin
isn't on your PATH
, the installer prints the line to add to your shell profile.
Pin a version or change install location:
GAMECHAT_VERSION=v0.1.0 INSTALL_DIR=/usr/local/bin \
sh -c "$(curl -fsSL https://raw.githubusercontent.com/zdql/gamechat/main/install.sh)"
git clone https://github.com/zdql/gamechat.git && cd gamechat
cargo install --path .
Requires Rust 1.87+. Linux additionally needs libasound2-dev
(and pkg-config
) for cpal
.
— required. The Realtime API runs on OpenAI regardless of which background agent you use.OPENAI_API_KEY
A coding agent on your$PATH
:Claude Code(claude
) — default backend.Codex CLI(codex
) — pass--provider codex
.
- Microphone + speakers.
gamechat
looks for env vars in three places, in order: the process environment, then a .env
file in the current directory or any parent, then $XDG_CONFIG_HOME/gamechat/env
(defaults to ~/.config/gamechat/env
). The installer writes that last file; per-project .env
s override it. First match wins per variable.
gamechat --realtime
gamechat --realtime --provider codex --codex-model gpt-5-codex
gamechat --once "summarize the last 5 commits" --slug summarize_commits
gamechat --print-realtime-config
| Flag | Default | Description |
|---|---|---|
--realtime |
||
| — | Live voice loop (mic + speakers). | |
--once <msg> |
||
| — | Single delegation; prints the VoiceUpdate JSON. |
|
| `--provider <claude | codex>` | |
claude |
||
| Background coding agent. | ||
--model <id> |
||
gpt-realtime-2 |
||
| Realtime voice model. | ||
--slug <slug> |
||
default |
||
Background task slug (used with --once ). |
||
--claude-bin / --claude-model |
||
| autodetect | Override the claude binary or its model. |
|
--codex-bin / --codex-model |
||
| autodetect | Override the codex binary or its model. |
gamechat/
├── src/
│ ├── main.rs # CLI, dotenv, provider wiring
│ ├── types.rs # DelegateToOrchestratorArgs, VoiceUpdate
│ ├── voice_loop/
│ │ ├── mod.rs # The select! loop
│ │ ├── session.rs # session.update JSON + tool defs
│ │ └── audio.rs # cpal input/output, resampling
│ └── orchestrator/
│ ├── interface.rs # Provider / Session traits, public types
│ ├── jobs.rs # OrchestratorJobManager + per-slug workers
│ ├── progress.rs # ProgressStore + rate-limited snapshots
│ ├── bridge.rs # Realtime tool calls ↔ job events
│ ├── shared.rs # Logging / stream helpers
│ ├── claude/ # `claude -p` backend
│ └── openai/ # `codex exec` backend
├── install.sh # curl|sh installer
└── .github/workflows/release.yml # cross-platform release builds
MIT.