System Architecture
Happy is a distributed system that enables remote control of AI coding agents through mobile devices. The architecture consists of three main components that communicate through encrypted channels.Component Overview
Monorepo Structure
The codebase is organized as a Yarn monorepo with five packages:Package Responsibilities
happy-cli
Command-line tool that wraps AI agents (Claude Code, Gemini, Codex) and enables remote control from mobile devices.Technologies: Node.js, TypeScript, Socket.IO Client, TweetNaCl
happy-server
Central coordination server handling authentication, message routing, and state synchronization.Technologies: Node.js, Fastify, Socket.IO Server, PostgreSQL, Prisma, Redis
happy-app
React Native mobile application for iOS and Android providing remote agent control.Technologies: React Native, Expo, Socket.IO Client, TweetNaCl
happy-wire
Shared protocol definitions and message schemas used across all components.Technologies: TypeScript, Zod
happy-agent
Shared agent utilities and common functionality (legacy, being consolidated).Technologies: TypeScript
CLI Architecture (happy-cli)
Directory Structure
Key Components
API Layer (packages/happy-cli/src/api/)
API Layer (packages/happy-cli/src/api/)
The API layer handles all communication with the server:
- ApiClient (
api.ts:13): Creates and manages sessions, handles authentication tokens - ApiSessionClient (
apiSession.ts:74): WebSocket-based real-time client with RPC support - Encryption (
encryption.ts): End-to-end encryption using TweetNaCl - RPC System (
rpc/): Remote procedure call handlers for mobile-initiated actions
- Generate encryption key (either legacy secret-based or new data key)
- Encrypt metadata and agent state
- POST to
/v1/sessionswith tag for deduplication - Establish WebSocket connection for real-time updates
Claude Integration (packages/happy-cli/src/claude/)
Claude Integration (packages/happy-cli/src/claude/)
Integration with Claude Code through Anthropic’s SDK:
- loop.ts:47: Main control loop alternating between local (terminal) and remote (mobile) modes
- session.ts:8: Session state management with keep-alive mechanism
- claudeSdk.ts: Direct SDK integration using
@anthropic-ai/claude-code - Protocol Mapper: Converts Claude’s message format to Happy’s Session Protocol
- Local Mode: User interacts directly with Claude in terminal
- Remote Mode: Mobile app sends messages, CLI forwards to Claude
Persistence Layer (packages/happy-cli/src/persistence.ts)
Persistence Layer (packages/happy-cli/src/persistence.ts)
Local storage for configuration and credentials:
- Private Keys: Stored in
~/.happy/access.key(or$HAPPY_HOME_DIR) - Settings: Machine metadata, sandbox config, AI backend profiles
- Encryption: All sensitive data encrypted before storage
- Global:
~/.happy/(production) or~/.happy-dev/(development) - Local:
.happy/in current directory (project-specific overrides)
Server Architecture (happy-server)
Directory Structure
Core Services
Event Router (app/events/eventRouter.ts)
Event Router (app/events/eventRouter.ts)
Central hub for distributing updates across connected clients:
- Maintains map of user ID → connected sockets
- Routes messages based on recipient filters (user-scoped, session-scoped)
- Implements optimistic concurrency control with sequence numbers
- Skips sender connection to avoid echo
Session Management (app/api/routes/sessionRoutes.ts)
Session Management (app/api/routes/sessionRoutes.ts)
RESTful endpoints for session lifecycle:
POST /v1/sessions: Create or retrieve session by tagGET /v3/sessions/:id/messages: Fetch message historyPOST /v3/sessions/:id/messages: Send message batch
WebSocket Handlers (app/api/socket/)
WebSocket Handlers (app/api/socket/)
Real-time bidirectional communication:
sessionUpdateHandler.ts:11: Metadata/state updates, keep-alive pingsmachineUpdateHandler.ts: Machine registration and daemon stateaccessKeyHandler.ts: RPC request routing between clients
user-scoped: Mobile app (receives all user’s updates)session-scoped: CLI (receives only specific session updates)machine-scoped: CLI daemon (receives machine-specific updates)
Presence System (app/presence/sessionCache.ts)
Presence System (app/presence/sessionCache.ts)
Tracks active sessions and online machines:
- In-memory cache with Redis backing
- Periodic database sync for last-active timestamps
- Efficient broadcast of session activity updates
Database Schema
The server uses PostgreSQL with Prisma ORM:- Account: User accounts with authentication
- Session: AI agent sessions with encrypted metadata
- SessionMessage: Message history with sequence numbers
- Machine: Registered CLI instances per user
- AccessKey: Long-lived authentication tokens
Mobile Architecture (happy-app)
Key Features
Session List
Real-time view of all active and recent sessions across machines
Message Stream
Live feed of agent messages, tool calls, and file edits
Remote Control
Send messages to agent, approve permissions, switch modes
Multi-Device Sync
All data synchronized across multiple mobile devices
State Management
The mobile app uses a custom reducer pattern:- Storage: Local-first with remote sync
- Optimistic Updates: Immediate UI response before server confirmation
- Event Processing: Incoming messages processed through reducer
- Protocol Support: Handles both legacy and new Session Protocol formats
Communication Patterns
Authentication Flow
Security: Challenge-response prevents replay attacks. Secret key never transmitted.Message Flow (Remote Mode)
Session Lifecycle
Scaling Considerations
Horizontal Scaling
Horizontal Scaling
The server can be scaled horizontally:
- Redis Pub/Sub: Distributes events across server instances
- Stateless Design: No server-side session state (all in database)
- Load Balancer: WebSocket sticky sessions required
Performance Optimizations
Performance Optimizations
- In-Memory Caching: Session presence cached in memory
- Batch Operations: Message outbox flushes in batches
- Sequence Allocation: Pre-allocated sequence ranges reduce DB queries
- Volatile Events: Keep-alive pings don’t persist to database
Database Optimization
Database Optimization
- Indexes: Composite indexes on (accountId, sessionId, seq)
- Partitioning: Messages table partitioned by date (future)
- Archival: Old sessions archived to cold storage (future)
Error Handling
Network Resilience
- Automatic Reconnection: WebSocket reconnects with exponential backoff
- Offline Mode: CLI continues working when server unreachable
- Message Queuing: Outbound messages queued until connection restored
- Version Conflicts: Optimistic concurrency with automatic retry
Encryption Failures
- Key Mismatch: Client displays error, prevents message corruption
- Decryption Failure: Message logged but skipped (no crash)
- Legacy Support: Falls back to legacy encryption format if needed
Development Setup
See Development Setup for detailed instructions on running the full stack locally.Next Steps
Data Flow
Understand message routing between components
Encryption Layer
Deep dive into TweetNaCl implementation
Session Lifecycle
Learn session creation and management
Server Component
Explore server architecture details