Files
paseo/.claude/CLAUDE.md
T
Mohamed Boudra 97f2ff2cac refactor: enhance TTS playback management with abort signal support
- Update TTSManager to accept an optional abort signal, allowing for graceful cancellation of TTS playback.
- Implement abort handling in the generateAndWaitForPlayback method to clean up pending playbacks and reject promises when playback is aborted.
- Modify Session class to pass the abort signal during TTS generation, improving control over playback interruptions.

These changes improve the robustness of the voice assistant's TTS functionality and enhance user experience by allowing for better management of audio playback.
2025-10-20 16:19:34 +02:00

7.5 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Voice-controlled terminal assistant using OpenAI's Realtime API (via Whisper STT, GPT-4, and TTS). Single-service architecture combining Express server, React UI, and tmux-based terminal management.

Monorepo Structure

This is an npm workspace monorepo:

  • Root: Workspace configuration and shared TypeScript config
  • packages/voice-assistant: Main application (only active package currently)

Development Commands

All commands run from the repository root:

# Development (starts Express server with integrated Vite middleware)
npm run dev

# Build everything
npm run build

# Type checking
npm run typecheck

# Production
npm run start

Voice Assistant Package Commands

From packages/voice-assistant/:

# Development
npm run dev              # Watch mode: Express server + Vite HMR
npm run dev:server       # Express server only (port 3000)

# Building
npm run build            # Build both UI and server
npm run build:ui         # Vite build � dist/ui
npm run build:server     # TypeScript � dist/server

# Production
npm start                # Run built server

# Type checking
npm run typecheck        # Check both UI and server

Architecture

Overall Structure

Single service with three main subsystems:

  1. Server Layer (src/server/):

    • Express HTTP server (port 3000)
    • WebSocket server for bidirectional communication
    • Vite middleware in development, static files in production
  2. Agent Layer (src/server/agent/):

    • orchestrator.ts: Main conversation manager
    • llm-openai.ts: GPT-4 streaming with tool execution
    • stt-openai.ts: Whisper transcription
    • tts-openai.ts: OpenAI TTS synthesis
    • system-prompt.ts: Agent instructions (voice-first UX focused)
  3. Daemon Layer (src/server/daemon/):

    • terminal-manager.ts: High-level terminal operations
    • tmux.ts: Low-level tmux integration
    • tool-definitions.ts: OpenAI function schemas for LLM
  4. UI Layer (src/ui/):

    • React 18 + Vite
    • WebSocket client for real-time communication
    • Audio capture and playback handling

Key Architecture Decisions

Terminal Model:

  • Uses tmux session "voice-dev" with windows-as-terminals
  • Each terminal = one tmux window with single pane
  • Terminal ID = tmux window ID (format: @123)
  • Terminal names must be unique

Voice-First Design:

  • All responses designed for TTS output
  • STT errors handled intelligently (see agent-prompt.md)
  • No visual feedback assumptions

Streaming Architecture:

  • Audio: Browser � WebSocket � Whisper STT � LLM � TTS � WebSocket � Browser
  • Text chunks streamed for real-time response
  • Tool calls logged as activity events

Data Flow

  1. Voice Input: Browser captures audio � sends chunks via WebSocket � STT transcribes � orchestrator processes
  2. LLM Processing: Orchestrator streams GPT-4 responses � executes tool calls � accumulates response
  3. Voice Output: Response � TTS synthesis � base64 audio � WebSocket � browser playback

TypeScript Configuration

Three separate configs:

  1. tsconfig.base.json: Root workspace defaults (ES2020, ESNext modules)
  2. packages/voice-assistant/tsconfig.json: UI build config (React JSX, bundler mode, noEmit)
  3. packages/voice-assistant/tsconfig.server.json: Server build config (NodeNext modules, outputs to dist/server)

Module System:

  • Server: ES modules with .js extensions in imports (NodeNext resolution)
  • UI: Vite bundler mode (no file extensions needed)

Environment Variables

Required in packages/voice-assistant/.env:

OPENAI_API_KEY=sk-...     # Required for GPT-4, Whisper, and TTS

# Optional TTS configuration
TTS_VOICE=alloy           # alloy|echo|fable|onyx|nova|shimmer
TTS_MODEL=tts-1           # tts-1 (fast) | tts-1-hd (quality)

# Server config
PORT=3000
NODE_ENV=development

Terminal Control (MCP-like Tools)

The LLM has access to terminal operations via function calling:

  • list_terminals(): Get all terminals with status
  • create_terminal(name, workingDirectory, initialCommand?): Create new terminal
  • send_text(terminalId, text, pressEnter, captureOutput?): Execute commands
  • capture_terminal(terminalId, lines?, wait?): Read terminal output
  • kill_terminal(terminalId): Remove terminal

See src/server/daemon/tool-definitions.ts for complete schemas.

WebSocket Protocol

Message types (see src/server/types.ts):

Client � Server:

  • user_message: Text input
  • audio_chunk: Audio data (base64, includes format and isLast flag)
  • recording_state: Recording started/stopped
  • ping: Keepalive

Server � Client:

  • activity_log: Conversation events (transcript, tool calls, errors)
  • assistant_chunk: Streaming response text
  • audio_output: Complete TTS audio (base64 MP3)
  • transcription_result: STT output
  • status: Connection state
  • pong: Keepalive response

Agent System Prompt

Located in agent-prompt.md (32KB) - loaded by system-prompt.ts.

Critical aspects:

  • Voice-first interaction guidelines
  • STT error handling strategies
  • Terminal operation best practices
  • Response brevity requirements (user is on phone)

Testing

Currently manual testing:

  1. Start dev server: npm run dev
  2. Open http://localhost:3000
  3. Test WebSocket connection (status indicator)
  4. Test voice recording/playback
  5. Test terminal operations via /api/test-terminal

Test scripts:

  • test-llm.sh: Direct LLM streaming test
  • test-orchestrator.js: Conversation flow test

File Organization

packages/voice-assistant/
�� src/
   �� server/
      �� agent/          # LLM, STT, TTS, orchestration
      �� daemon/         # Terminal management + tool schemas
      �� index.ts        # Express + WebSocket server
      �� websocket-server.ts
      �� types.ts        # Shared server types
   �� ui/
       �� components/     # React components
       �� hooks/          # WebSocket, audio hooks
       �� lib/            # Audio capture/playback utilities
       �� App.tsx
       �� main.tsx
�� dist/                   # Build output (gitignored)
�� agent-prompt.md         # System prompt source
�� package.json
�� tsconfig.json           # UI TypeScript config
�� tsconfig.server.json    # Server TypeScript config
�� vite.config.ts

Common Tasks

Adding a new terminal tool:

  1. Add function schema to daemon/tool-definitions.ts
  2. Implement handler in agent/llm-openai.ts executeTool function
  3. If needed, add low-level tmux operation to daemon/tmux.ts

Modifying agent behavior:

  1. Edit agent-prompt.md for instructions
  2. Restart server (prompt loaded on startup)

Changing audio formats:

  1. STT: Modify agent/stt-openai.ts (currently accepts webm/ogg/mp3)
  2. TTS: Change TTS_MODEL env var or tts-openai.ts config

WebSocket message types:

  1. Add type to types.ts WebSocketMessage union
  2. Add handler in websocket-server.ts or client hooks

Known Patterns

  • No barrel files: Direct imports only (no index.ts exports)
  • Function declarations: Always use function not arrow functions for exports
  • Error handling: Let errors bubble to Express/WebSocket error handlers
  • Tool execution: Synchronous within LLM streaming loop (tools modify conversation state)
  • Conversation cleanup: Auto-cleanup runs every 10 minutes (60 min TTL)
  • never run dev server, user will test manually