Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tiann/hapi/llms.txt
Use this file to discover all available pages before exploring further.
Overview
HAPI Hub uses Socket.IO for bidirectional real-time communication between the CLI and hub.
Namespace
CLI connections use the /cli namespace:
Connection Process
1. CLI Connects to Hub
import { io } from 'socket.io-client'
const socket = io('http://127.0.0.1:3006/cli', {
auth: {
sessionId: 'abc123', // Optional: join session room
machineId: 'machine_xyz', // Optional: join machine room
namespace: 'default' // Required: user namespace
},
transports: ['websocket', 'polling']
})
2. Authentication
Authentication is performed via the auth object in the handshake:
3. Rooms
When authenticated, the socket automatically joins rooms:
session:<sessionId> - Receives updates for this session
machine:<machineId> - Receives updates for this machine
Connection Example
import { io, Socket } from 'socket.io-client'
import type { ClientToServerEvents, ServerToClientEvents } from '@hapi/protocol'
type TypedSocket = Socket<ServerToClientEvents, ClientToServerEvents>
const socket: TypedSocket = io('http://127.0.0.1:3006/cli', {
auth: {
sessionId: 'abc123',
machineId: 'machine_xyz',
namespace: 'default'
}
})
socket.on('connect', () => {
console.log('Connected to hub:', socket.id)
})
socket.on('disconnect', (reason) => {
console.log('Disconnected:', reason)
})
socket.on('error', (data) => {
console.error('Socket error:', data)
})
Event Flow
CLI to Hub
Hub to CLI
Hub to Web
Web clients receive updates via:
- SSE (
GET /api/events) - One-way events
- REST API - Request/response
Error Handling
The hub emits error events for:
Access Errors
socket.on('error', (data) => {
if (data.code === 'access-denied') {
// Session/machine belongs to different namespace
} else if (data.code === 'not-found') {
// Session/machine doesn't exist
} else if (data.code === 'namespace-missing') {
// Client didn't provide namespace in auth
}
})
Error Structure
interface SocketError {
message: string
code?: 'namespace-missing' | 'access-denied' | 'not-found'
scope?: 'session' | 'machine'
id?: string // Session or machine ID
}
Reconnection
Socket.IO automatically handles reconnection:
socket.io.on('reconnect', (attempt) => {
console.log('Reconnected after', attempt, 'attempts')
})
socket.io.on('reconnect_attempt', (attempt) => {
console.log('Reconnection attempt', attempt)
})
socket.io.on('reconnect_failed', () => {
console.error('Reconnection failed')
})
Custom Reconnection Logic
const socket = io('http://127.0.0.1:3006/cli', {
auth: { sessionId: 'abc123', namespace: 'default' },
reconnection: true,
reconnectionAttempts: 10,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000
})
Heartbeat
The CLI should send periodic heartbeats:
Session Heartbeat
setInterval(() => {
socket.emit('session-alive', {
sid: 'abc123',
time: Date.now(),
thinking: false,
mode: 'remote',
permissionMode: 'default'
})
}, 5000) // Every 5 seconds
Machine Heartbeat
setInterval(() => {
socket.emit('machine-alive', {
machineId: 'machine_xyz',
time: Date.now()
})
}, 10000) // Every 10 seconds
Ping/Pong
Test connection latency:
socket.emit('ping', () => {
console.log('Pong received')
})
Transport Options
Socket.IO supports multiple transports:
WebSocket Only (Recommended)
const socket = io('http://127.0.0.1:3006/cli', {
transports: ['websocket']
})
WebSocket with Polling Fallback
const socket = io('http://127.0.0.1:3006/cli', {
transports: ['websocket', 'polling']
})
CORS Configuration
Configure CORS for Socket.IO connections:
CORS_ORIGINS=https://app.example.com,https://other.example.com
# or
CORS_ORIGINS=*
The hub automatically allows:
- Same-origin requests
- Origins derived from
HAPI_PUBLIC_URL
- Origins in
CORS_ORIGINS
Security
Namespace Isolation
All operations are scoped to the authenticated namespace:
- Sessions and machines are filtered by namespace
- Cross-namespace access returns
access-denied error
- Each namespace is isolated (multi-tenant)
No Token Auth
Socket.IO connections don’t use JWT tokens. Instead:
- CLI connects with
namespace in auth
- Hub validates namespace exists
- CLI can only access resources in its namespace
Session/Machine Ownership
The hub verifies:
- Session belongs to the namespace
- Machine belongs to the namespace
- No cross-namespace data leakage
Next Steps
Socket Events
Detailed event documentation
RPC
Remote procedure calls