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.
This guide covers installing HAPI, configuring the hub, and setting up optional features like Telegram notifications and the background runner.
Prerequisites
HAPI requires at least one AI agent CLI:
Claude Code
Cursor Agent
OpenCode
Codex
Gemini
npm install -g @anthropic-ai/claude-code
claude --version
macOS/Linux: curl https://cursor.com/install -fsS | bash
agent --version
Windows (PowerShell): irm 'https://cursor.com/install?win32=true' | iex
agent --version
# Install OpenCode CLI
npm install -g @opencode/cli
opencode --version
# Install Codex CLI
npm install -g @openai/codex-cli
codex --version
# Install Gemini CLI (via ACP)
npm install -g @google/gemini-cli
gemini --version
Install HAPI CLI
npm (Recommended)
Homebrew
npx (no install)
Prebuilt Binary
Build from Source
npm install -g @twsxtd/hapi --registry=https://registry.npmjs.org
Use the official npm registry for global install. Some mirrors may not sync platform packages in time.
brew install tiann/tap/hapi
# Run without installing
npx @twsxtd/hapi hub --relay
npx @twsxtd/hapi
Download from GitHub Releases : # macOS: Remove quarantine flag
xattr -d com.apple.quarantine ./hapi
chmod +x ./hapi
sudo mv ./hapi /usr/local/bin/
# Verify
hapi --version
git clone https://github.com/tiann/hapi.git
cd hapi
bun install
bun run build:single-exe
# Binary location
./cli/dist/hapi
Building from source requires Bun runtime.
Architecture Overview
HAPI has three components:
Component Role Required CLI Wraps AI agents (Claude/Codex/Cursor/Gemini/OpenCode), runs sessions Yes Hub Central coordinator: persistence, real-time sync, remote access Yes Runner Background service for remote session spawning Optional
How They Work Together
┌─────────────────────────────────────────────────────┐
│ Your Machine │
│ │
│ ┌─────────┐ Socket.IO ┌─────────────┐ │
│ │ CLI │◄───────────────►│ Hub │ │
│ │+ Agent │ │ + SQLite │ │
│ └─────────┘ └──────┬──────┘ │
│ ▲ │ SSE │
│ │ spawn ▼ │
│ ┌────┴────┐ ┌─────────────┐ │
│ │ Runner │◄────RPC────────►│ Web App │ │
│ │ (后台) │ └─────────────┘ │
│ └─────────┘ │
└─────────────────────────────────────────────────────┘
│
[Tunnel / Public URL]
│
┌─────▼─────┐
│ Phone/Web │
└───────────┘
Workflow:
CLI : Start a session with hapi. Wraps your AI agent and syncs with the hub.
Hub : Run hapi hub. Stores sessions, handles permissions, enables remote access.
Runner : Run hapi runner start. Spawn sessions from phone/web without keeping terminal open.
Hub Setup
Option 1: Public Relay (Recommended)
The public relay provides instant remote access with end-to-end encryption:
You’ll see:
┌─────────────────────────────────────────────────────────┐
│ │
│ HAPI Hub Started │
│ │
│ Local: http://localhost:3006 │
│ Remote: https://abc123.relay.hapi.run │
│ │
│ Access Token: hapi_1a2b3c4d5e6f... │
│ (saved to ~/.hapi/settings.json) │
│ │
│ [QR CODE] │
│ │
└─────────────────────────────────────────────────────────┘
The relay uses WireGuard + TLS for end-to-end encryption. Your data is encrypted from your device to your machine—the relay only forwards packets it cannot read.
UDP blocked? Some networks block UDP traffic. Force TCP mode:HAPI_RELAY_FORCE_TCP = true hapi hub --relay
Option 2: Local Only
Run the hub without remote access:
hapi hub
# or
hapi hub --no-relay
The hub listens on http://localhost:3006 by default.
Access from other devices on your local network:
http://<your-computer-ip>:3006
Option 3: Self-Hosted Tunnels
For lower latency or self-managed infrastructure, use your own tunnel:
Cloudflare Tunnel provides secure HTTPS access without exposing ports.Quick Tunnels not supported! Cloudflare Quick Tunnels (TryCloudflare) do not support SSE , which HAPI requires. Use a Named Tunnel instead.Setup: # Install cloudflared
# https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
# Create named tunnel
cloudflared tunnel create hapi
cloudflared tunnel route dns hapi hapi.yourdomain.com
# Start tunnel (use http2 protocol)
cloudflared tunnel --protocol http2 run hapi
Use --protocol http2 instead of QUIC (default) to avoid timeout issues with long-lived connections.
In a separate terminal: export HAPI_PUBLIC_URL = "https://hapi.yourdomain.com"
hapi hub
Tailscale creates a private mesh network between your devices.# Install and connect
sudo tailscale up
# Start hub
hapi hub
Access via your Tailscale IP: If your hub has a public IP, expose it directly: export HAPI_LISTEN_HOST = "0.0.0.0"
export HAPI_LISTEN_PORT = "3006"
hapi hub
Production Setup (HTTPS): Use a reverse proxy like Nginx or Caddy: # Nginx example
server {
listen 443 ssl http2;
server_name hapi.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3006;
proxy_http_version 1.1 ;
proxy_set_header Upgrade $ http_upgrade ;
proxy_set_header Connection "upgrade" ;
proxy_set_header Host $ host ;
proxy_set_header X-Real-IP $ remote_addr ;
}
}
Self-signed certificates? If using self-signed certs, the CLI may fail with “self signed certificate” error. Fix: # Preferred: Trust your CA
export NODE_EXTRA_CA_CERTS = "/path/to/your-ca.pem"
# Dev-only workaround (INSECURE)
export NODE_TLS_REJECT_UNAUTHORIZED = 0
CLI Configuration
If your hub is not on localhost, configure the CLI:
export HAPI_API_URL = "http://your-hub:3006"
export CLI_API_TOKEN = "your-token-here"
Or use interactive login:
Authentication Commands:
hapi auth status # Show current config
hapi auth login # Save token interactively
hapi auth logout # Clear saved credentials
Configuration Priority
ENV > settings.json > default
When ENV values are set, they’re automatically saved to settings.json.
Configuration Files
~/.hapi/
├── settings.json # Main configuration
├── hapi.db # SQLite database (hub)
├── runner.state.json # Runner process state
└── logs/ # Log files
settings.json example:
{
"$schema" : "https://hapi.run/docs/schemas/settings.schema.json" ,
"cliApiToken" : "hapi_1a2b3c4d5e6f..." ,
"apiUrl" : "http://localhost:3006" ,
"machineId" : "machine_xyz789" ,
"listenHost" : "0.0.0.0" ,
"listenPort" : 3006 ,
"publicUrl" : "https://your-domain.com"
}
Environment Variables
Required
Variable Default Description CLI_API_TOKENAuto-generated Shared secret for authentication HAPI_API_URLhttp://localhost:3006Hub URL for CLI connections
Optional
Variable Default Description HAPI_HOME~/.hapiConfig/data directory HAPI_LISTEN_HOST127.0.0.1Hub HTTP bind address HAPI_LISTEN_PORT3006Hub HTTP port HAPI_PUBLIC_URL- Public URL for external access CORS_ORIGINS- Allowed CORS origins (comma-separated) HAPI_RELAY_FORCE_TCPfalseForce TCP mode for relay HAPI_EXPERIMENTALfalseEnable experimental features HAPI_CLAUDE_PATH- Custom Claude executable path
Telegram
Variable Description TELEGRAM_BOT_TOKENToken from @BotFather TELEGRAM_NOTIFICATIONEnable notifications (default: true)
Voice Assistant
Variable Description ELEVENLABS_API_KEYElevenLabs API key ELEVENLABS_AGENT_IDCustom agent ID (auto-created if not set)
Runner
Variable Default Description HAPI_RUNNER_HEARTBEAT_INTERVAL60000Heartbeat interval (ms) HAPI_RUNNER_HTTP_TIMEOUT10000HTTP timeout (ms)
Runner Setup
The runner enables remote session spawning from your phone:
Benefits:
Spawn sessions remotely without terminal access
Sessions persist after terminal closes
Your machine appears in the “Machines” list
Runner Commands:
hapi runner start # Start runner as detached process
hapi runner stop # Stop runner gracefully
hapi runner status # Show diagnostics
hapi runner list # List active sessions
hapi runner logs # Print log file path
hapi runner stop-session < i d > # Terminate specific session
Check Status:
Output:
✓ Runner is running
PID: 12345
Port: 3007
Uptime: 2h 34m
Sessions: 3 active
Background Service Deployment
Keep HAPI running persistently across terminal closes and system restarts.
nohup (Quick)
pm2 (Recommended)
systemd (Linux)
launchd (macOS)
Simple one-liner for background runs: # Hub
nohup hapi hub --relay > ~/.hapi/logs/hub.log 2>&1 &
# Runner
nohup hapi runner start --foreground > ~/.hapi/logs/runner.log 2>&1 &
View logs: tail -f ~/.hapi/logs/hub.log
tail -f ~/.hapi/logs/runner.log
Stop: pkill -f "hapi hub"
pkill -f "hapi runner"
pm2 provides process management with auto-restart.# Install
npm install -g pm2
# Start services
pm2 start "hapi hub --relay" --name hapi-hub
pm2 start "hapi runner start --foreground" --name hapi-runner
# View status and logs
pm2 status
pm2 logs hapi-hub
pm2 logs hapi-runner
# Auto-restart on system reboot
pm2 startup # Follow printed instructions
pm2 save # Save current process list
Hub service (~/.config/systemd/user/hapi-hub.service):[Unit]
Description =HAPI Hub
After =network.target
[Service]
Type =simple
ExecStart =/usr/local/bin/hapi hub --relay
Restart =always
RestartSec =5
[Install]
WantedBy =default.target
Runner service (~/.config/systemd/user/hapi-runner.service):[Unit]
Description =HAPI Runner
After =network.target hapi-hub.service
[Service]
Type =simple
ExecStart =/usr/local/bin/hapi runner start --foreground
Restart =always
RestartSec =5
[Install]
WantedBy =default.target
Enable and start: # Reload systemd
systemctl --user daemon-reload
# Enable (auto-start on login)
systemctl --user enable hapi-hub
systemctl --user enable hapi-runner
# Start now
systemctl --user start hapi-hub
systemctl --user start hapi-runner
# View status/logs
systemctl --user status hapi-hub
journalctl --user -u hapi-hub -f
Persist after logout: loginctl enable-linger $USER
Hub plist (~/Library/LaunchAgents/com.hapi.hub.plist):<? xml version = "1.0" encoding = "UTF-8" ?>
<! DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd" >
< plist version = "1.0" >
< dict >
< key > Label </ key >
< string > com.hapi.hub </ string >
< key > ProgramArguments </ key >
< array >
< string > /usr/local/bin/hapi </ string >
< string > hub </ string >
< string > --relay </ string >
</ array >
< key > RunAtLoad </ key >
< true />
< key > KeepAlive </ key >
< true />
< key > StandardOutPath </ key >
< string > /Users/YOUR_USERNAME/.hapi/logs/hub.log </ string >
< key > StandardErrorPath </ key >
< string > /Users/YOUR_USERNAME/.hapi/logs/hub.log </ string >
</ dict >
</ plist >
Runner plist (~/Library/LaunchAgents/com.hapi.runner.plist):<? xml version = "1.0" encoding = "UTF-8" ?>
<! DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd" >
< plist version = "1.0" >
< dict >
< key > Label </ key >
< string > com.hapi.runner </ string >
< key > ProgramArguments </ key >
< array >
< string > /usr/local/bin/hapi </ string >
< string > runner </ string >
< string > start </ string >
< string > --foreground </ string >
</ array >
< key > RunAtLoad </ key >
< true />
< key > KeepAlive </ key >
< true />
< key > StandardOutPath </ key >
< string > /Users/YOUR_USERNAME/.hapi/logs/runner.log </ string >
< key > StandardErrorPath </ key >
< string > /Users/YOUR_USERNAME/.hapi/logs/runner.log </ string >
</ dict >
</ plist >
Load services: launchctl load ~/Library/LaunchAgents/com.hapi.hub.plist
launchctl load ~/Library/LaunchAgents/com.hapi.runner.plist
macOS sleep note: macOS may suspend background processes when display sleeps. Prevent with caffeinate:caffeinate -dimsu hapi hub --relay
Telegram Setup
Enable Telegram notifications and Mini App access:
Create Bot
Message @BotFather on Telegram: Follow prompts to create your bot and get the token.
Configure Hub
export TELEGRAM_BOT_TOKEN = "your-bot-token"
export HAPI_PUBLIC_URL = "https://your-public-url"
hapi hub --relay
Telegram Mini Apps require HTTPS and a public URL. Use the relay or a tunnel.
Bind Account
Message your bot with /start
Tap “Open App”
Enter your CLI_API_TOKEN when prompted
You’ll now receive notifications for permission requests and session events.
Voice Assistant Setup
Enable voice control with ElevenLabs:
Configure Hub
export ELEVENLABS_API_KEY = "your-api-key"
hapi hub --relay
HAPI will auto-create an agent if ELEVENLABS_AGENT_ID is not set.
Use Voice
In the web app:
Open a session
Click the microphone button
Start speaking
The AI will respond with voice and execute commands.
Diagnostics
Run full system diagnostics:
Output:
✓ Hub connectivity: OK (http://localhost:3006)
✓ Authentication: Valid token
✓ Claude CLI: Found at /usr/local/bin/claude (v1.2.3)
✓ Cursor Agent: Found at /usr/local/bin/agent (v0.9.1)
✓ OpenCode: Not found
✓ Runner: Running (PID 12345, port 3007)
✓ Sessions: 2 active, 15 archived
✓ Database: ~/.hapi/hapi.db (4.2 MB)
Recent logs:
[2024-03-06 10:32:15] Session started: session_abc123
[2024-03-06 10:35:42] Permission approved: edit file.ts
Clean up runaway processes:
Security Best Practices
Token Security:
Keep your CLI_API_TOKEN secret
Rotate tokens if compromised
Use strong, unique tokens for production
Network Security:
Always use HTTPS for public access
Restrict CORS origins in production
Use firewall rules to limit access
Firewall Example (ufw):
# Allow from local network only
ufw allow from 192.168.1.0/24 to any port 3006
Rotate Access Token:
# Generate new token
rm ~/.hapi/settings.json
hapi hub --relay
# Update CLI
hapi auth login
Next Steps
Quickstart Get up and running in 2 minutes
How It Works Understand the architecture
GitHub View source and contribute
Telegram Community Join the discussion