7.0 KiB
Personal Assistant API
Backend API for the Personal Assistant system - provides Claude-powered voice/text interface to all PA capabilities (calendar, tasks, messages, smart home, etc.).
Quick Reference
| Setting | Value |
|---|---|
| Domain | pa.htsn.io |
| Local IP | 10.10.10.207:8401 |
| Server | docker-host2 (PVE2 VMID 302) |
| Compose | /opt/pa-api/docker-compose.yml |
| Access | Tailscale only (not publicly exposed) |
| GitHub | Private repo: pa-api |
Architecture
Android/Telegram
│
▼
┌─────────────────┐
│ PA API │ ← Claude SDK, model routing
│ docker-host2 │
│ :8401 │
└────────┬────────┘
│
┌────┴────┐
│ │
▼ ▼
┌───────┐ ┌──────────┐
│ Rube │ │MCP Bridge│ ← Mac Mini (Beeper, Proton, etc.)
│ Exa │ │ :8400 │
│ etc. │ └──────────┘
└───────┘
PA API handles:
- Claude SDK integration (no CLI startup delay)
- Model routing (Haiku/Sonnet/Opus)
- Session management
- Direct API tools (Exa, Ref, Rube, Airtable)
MCP Bridge handles:
- Tools requiring Mac Mini (Beeper, Proton Bridge, filesystem)
- Runs on Mac Mini at 10.10.10.125:8400
API Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/chat |
POST | Main query endpoint (streaming SSE) |
/health |
GET | Health check |
POST /chat
Request:
{
"message": "What's on my calendar today?",
"session_id": "abc123"
}
Response (Server-Sent Events):
data: {"type": "model", "name": "sonnet"}
data: {"type": "chunk", "text": "You have "}
data: {"type": "chunk", "text": "3 meetings today..."}
data: {"type": "done", "full_text": "You have 3 meetings today..."}
Model Routing
| Query Type | Model | Examples |
|---|---|---|
| Simple facts | Haiku | "How old is X?", "What's 15% of 80?" |
| PA queries | Sonnet | "What's on my calendar?", "Add task" |
| Complex reasoning | Opus | "Help me plan my week" |
Override: Say "Use Opus" to force model selection (sticky per session).
Deployment
Docker Compose
Location: /opt/pa-api/docker-compose.yml
version: '3.8'
services:
pa-api:
image: pa-api:latest
build: .
container_name: pa-api
restart: unless-stopped
ports:
- "8401:8401"
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- MCP_BRIDGE_URL=http://10.10.10.125:8400
- EXA_API_KEY=${EXA_API_KEY}
# Add other API keys as needed
volumes:
- ./data:/app/data
networks:
- pa-network
networks:
pa-network:
driver: bridge
Environment Variables
| Variable | Purpose |
|---|---|
ANTHROPIC_API_KEY |
Claude API access |
MCP_BRIDGE_URL |
Mac Mini bridge endpoint |
EXA_API_KEY |
Exa web search |
AIRTABLE_API_KEY |
Airtable access |
Store in /opt/pa-api/.env (not committed to git).
Traefik Configuration
File: /etc/traefik/conf.d/pa-api.yaml (on CT 202)
http:
routers:
pa-api:
rule: "Host(`pa.htsn.io`)"
entryPoints:
- websecure
service: pa-api
tls:
certResolver: cloudflare
services:
pa-api:
loadBalancer:
servers:
- url: "http://10.10.10.207:8401"
Note: This service is Tailscale-only. The Traefik route exists for convenience but should not be exposed publicly via Cloudflare.
Common Tasks
Start/Stop Service
# SSH to docker-host2
ssh docker-host2
# Start
cd /opt/pa-api && docker-compose up -d
# Stop
cd /opt/pa-api && docker-compose down
# View logs
docker logs -f pa-api
# Restart
docker-compose restart pa-api
Update Service
ssh docker-host2
cd /opt/pa-api
git pull
docker-compose build
docker-compose up -d
Health Check
# From any machine on network
curl http://10.10.10.207:8401/health
# Test chat endpoint
curl -X POST http://10.10.10.207:8401/chat \
-H "Content-Type: application/json" \
-d '{"message": "Hello", "session_id": "test"}'
MCP Bridge (Mac Mini)
The MCP Bridge runs on Mac Mini and exposes MCP tools as HTTP endpoints.
| Setting | Value |
|---|---|
| Location | Mac Mini (10.10.10.125) |
| Port | 8400 |
| Purpose | Execute MCP tools (Beeper, Proton, TickTick, HA, etc.) |
Bridge Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/tools |
GET | List available tools |
/execute |
POST | Execute a tool |
/health |
GET | Health check |
Start MCP Bridge
# SSH to Mac Mini
ssh macmini
# Start bridge (managed by launchd)
launchctl load ~/Library/LaunchAgents/com.hutson.mcp-bridge.plist
# Check status
curl http://localhost:8400/health
Integration Points
Related Services
| Service | Relationship |
|---|---|
| n8n | Telegram bot uses n8n → Claude CLI (separate path) |
| MetaMCP | PA API does NOT use MetaMCP (direct MCP Bridge) |
| Home Assistant | Controlled via MCP Bridge |
| Claude-Mem | Shared memory database for context |
Clients
| Client | Connection |
|---|---|
| Android App | HTTPS via Tailscale → pa.htsn.io |
| (Future) Web UI | Same endpoint |
Monitoring
Health Checks
# PA API
curl -s http://10.10.10.207:8401/health | jq
# MCP Bridge
curl -s http://10.10.10.125:8400/health | jq
Logs
# PA API logs
ssh docker-host2 'docker logs -f pa-api --tail 100'
# MCP Bridge logs (Mac Mini)
ssh macmini 'tail -f ~/Library/Logs/mcp-bridge.log'
Troubleshooting
PA API Not Responding
-
Check container status:
ssh docker-host2 'docker ps | grep pa-api' -
Check logs for errors:
ssh docker-host2 'docker logs pa-api --tail 50' -
Verify network:
curl http://10.10.10.207:8401/health
MCP Bridge Not Responding
-
Check if Mac Mini is reachable:
ping 10.10.10.125 -
Check bridge process:
ssh macmini 'pgrep -f mcp-bridge' -
Restart bridge:
ssh macmini 'launchctl unload ~/Library/LaunchAgents/com.hutson.mcp-bridge.plist' ssh macmini 'launchctl load ~/Library/LaunchAgents/com.hutson.mcp-bridge.plist'
Model Routing Issues
- Check Claude API key is valid
- Verify Haiku classifier is responding
- Check session storage for stuck model overrides
Related Documentation
- IP-ASSIGNMENTS.md - Service IP mapping
- VMS.md - docker-host2 VM details
- TRAEFIK.md - Reverse proxy configuration
- Personal Assistant Project - PA system overview
- Services Matrix - All MCP tools
Last Updated: 2026-01-07