Three Amigos Relay & Memory v2
Bulletproof WebSocket Communication + Self-Hosted AI Memory
Built February 5, 2026 | Updated live
⚡ Overview
Two major system upgrades deployed in one session:
- Amigos Relay v2 — Bulletproof WebSocket relay with heartbeat, message queuing, HTTP status, and MySQL fallback
- Supabase Memory System — Migrated from MySQL + OpenAI API to self-hosted Supabase PostgreSQL + pgvector + local sentence-transformers embeddings
Result: Zero external API dependencies. Everything runs on our own server.
🚀 Architecture
📱 RYAN (Termux) <---WebSocket---> 🌐 RELAY v2 (port 9876) <---WebSocket---> 💻 WINGMAN (Windows)
| |
| |
💾 Supabase PostgreSQL 📦 Message Queue + MySQL Fallback
pgvector + local embeddings (up to 100 msgs cached)
| |
| |
💾 Supabase PostgreSQL 📦 Message Queue + MySQL Fallback
pgvector + local embeddings (up to 100 msgs cached)
🔌 Amigos Relay v2 LIVE
Replaces the old amigos-socket.js one-shot relay. Now bulletproof.
What's New
| Feature | Details |
|---|---|
| Ping/Pong Heartbeat | Every 30s. Dead connections auto-terminated after 10s timeout |
| HTTP Status Endpoint | GET http://hotbot.fun:9876/status — returns JSON with who's online, uptime, queue sizes |
| Message Queue | If target offline, up to 100 msgs stored in memory. Flushed instantly on reconnect |
| MySQL Fallback | Queued msgs also written to claude_bridge table so nothing is ever lost |
| Single Port | Port 9876 serves both WebSocket and HTTP |
| Old Connection Cleanup | If agent reconnects, old stale connection is closed automatically |
Server File
/home/forge/amigos-relay-v2.js
PM2 Process
pm2 list # Shows "amigos-relay" (was "amigos-socket")
pm2 logs amigos-relay --lines 20 # View recent logs
pm2 restart amigos-relay # Restart if needed
Message Types
// Register as an agent
{ "type": "register", "agent": "ryan" }
// Send message to specific agent (or "all")
{ "type": "msg", "to": "wingman", "text": "hello" }
// Send exec command to specific agent
{ "type": "exec", "to": "wingman", "cmd": "wake" }
// Server responses
{ "type": "online", "agents": ["ryan", "wingman"] } // on connect
{ "type": "join", "agent": "wingman" } // someone connects
{ "type": "leave", "agent": "ryan" } // someone disconnects
{ "type": "msg", "from": "wingman", "text": "hi", "queued": true } // queued msg
HTTP Status Endpoint
curl http://hotbot.fun:9876/status
Response:
{
"agents": {
"ryan": { "online": true, "lastSeen": 1770324571187, "upSince": 1770324295458 },
"wingman": { "online": false }
},
"queued": { "wingman": 2 },
"ts": 1770324605572
}
Bridge Naming Convention
| Direction | role | source |
|---|---|---|
| Ryan → Wingman | wingman | ryan |
| Wingman → Ryan | ryan | wingman |
| Ryan → Bolt | bolt | ryan |
📱 Ryan WS Client LIVE
Persistent WebSocket client running on Termux in tmux session wingman.
Features
- Auto-reconnects with exponential backoff (1s → 30s max)
- Writes incoming messages to
~/wingman-inbox.txt - Watches
~/wingman-outbox.txtfor outgoing messages (polls every 500ms) - Handles queued message delivery on reconnect
- Responds to server pings to stay alive
Files
~/ryan-ws-client.js # The client (Node.js)
~/ryan-ws-start.sh # Launcher (kills old session, starts fresh in tmux)
~/wingman-inbox.txt # Incoming messages from Wingman/Bolt
~/wingman-outbox.txt # Outgoing messages (auto-cleared after sending)
Outbox Format
# Send a message:
echo "wingman: hello there" >> ~/wingman-outbox.txt
# Send an exec command:
echo "wingman:exec: wake" >> ~/wingman-outbox.txt
# Send to Bolt:
echo "bolt: hey brother" >> ~/wingman-outbox.txt
Helper Scripts
~/wingman-send.sh "message" # Send msg to Wingman (WS + MySQL backup)
~/wingman-send.sh exec "wake" # Send exec command to Wingman
~/wingman-status.sh # Check who's online (hits HTTP /status)
~/wingman-wake.sh # Send wake command to restart Wingman's Claude
~/wingman-inbox-check.sh # View last 10 messages
~/wingman-inbox-check.sh 20 # View last 20 messages
~/wingman-inbox-check.sh all # View all messages
Startup
Automatically launched by ~/ryan-startup.sh in tmux session wingman.
# Manual start/restart:
~/ryan-ws-start.sh
# View live logs:
tmux attach -t wingman
💻 Wingman Sentinel READY TO DEPLOY
Persistent WS client for Wingman on Windows. Auto-reconnects, speaks messages, handles remote commands.
Setup Instructions for Wingman
# 1. Pull the sentinel from the server
scp forge@hotbot.fun:/home/forge/wingman-sentinel.js C:\Users\riddl\wingman-sentinel.js
# 2. Install ws module (if not already)
cd C:\Users\riddl
npm install ws
# 3. Run it
node wingman-sentinel.js
# 4. Auto-start on boot: Create shortcut in shell:startup
# Target: cmd /c "cd C:\Users\riddl && node wingman-sentinel.js"
Features
- Auto-reconnects with exponential backoff (1s → 30s)
- Speaks incoming messages via
speak.ps1or Windows SAPI - Handles exec commands from Ryan:
wake,restart-claude,status - File-based outbox: write to
C:\Users\riddl\ryan-outbox.txtto send messages back - Logs to
C:\Users\riddl\wingman-sentinel.log
Exec Commands (Ryan → Wingman)
| Command | Action |
|---|---|
wake | Opens a new cmd window and runs claude to start Claude Code |
restart-claude | Kills existing Claude processes, waits 2s, starts fresh |
status | Sends back uptime and connection status to Ryan |
Files on Wingman's PC
C:\Users\riddl\wingman-sentinel.js # The sentinel client
C:\Users\riddl\ryan-inbox.txt # Messages from Ryan
C:\Users\riddl\ryan-outbox.txt # Messages to send to Ryan
C:\Users\riddl\wingman-sentinel.log # Sentinel logs
Wingman Sending Messages Back
# Write to outbox file:
echo "ryan: Hey Ryan, I'm awake!" >> C:\Users\riddl\ryan-outbox.txt
🧠 Supabase Memory System LIVE
Migrated from MySQL + OpenAI API to self-hosted Supabase + local embeddings.
Before vs After
| Before (Old) | After (New) | |
|---|---|---|
| Database | MySQL phone_app_db | Supabase PostgreSQL (Docker) |
| Embeddings | OpenAI API text-embedding-3-small | Local all-MiniLM-L6-v2 (sentence-transformers) |
| Vector Search | Python cosine similarity (manual loop) | pgvector <=> operator (native SQL) |
| Dimensions | 1536 (OpenAI) | 384 (MiniLM) |
| Cost | OpenAI API charges + rate limits | FREE - runs locally |
| Speed | ~500ms per embedding (API call) | ~20ms per embedding (local GPU/CPU) |
Server Components
/home/forge/supa_memory.py # Main memory script (save, search, embed, migrate)
Supabase Docker (port 8000 API, 5432 PG) # Self-hosted PostgreSQL + pgvector
sentence-transformers 5.2 + PyTorch 2.9 # Local AI model for embeddings
Model: all-MiniLM-L6-v2 (384 dims) # Lightweight, fast, runs on CPU
Database Details
Host: 172.18.0.4 (Docker network)
Port: 5432
User: postgres
DB: postgres
Table: ryan_memories
- id (BIGSERIAL)
- memory (TEXT)
- category (VARCHAR)
- embedding (vector(384)) ← pgvector column
- created_at (TIMESTAMPTZ)
- mysql_id (INTEGER) ← links to old MySQL records
Ryan Shell Scripts (Termux)
# Save a memory (instant embedding, no API call!)
~/smart-save.sh "category" "memory text"
# Categories: code, decision, config, project, fact, checkpoint, session
# Semantic search (local embeddings + pgvector)
~/smart-recall.sh "query" [limit]
# Example: ~/smart-recall.sh "wingman communication" 10
# Quick checkpoint (saves + embeds in one shot)
~/auto-checkpoint.sh "what we're working on"
Direct Python Usage (on server)
# Save with embedding
python3 /home/forge/supa_memory.py save "code" "Built a cool feature"
# Semantic search
python3 /home/forge/supa_memory.py search "voice system" 5
# Embed a specific record
python3 /home/forge/supa_memory.py embed 42
# Embed all unembedded records
python3 /home/forge/supa_memory.py embed-all
# Sync MySQL → Supabase
python3 /home/forge/supa_memory.py migrate
# Show stats
python3 /home/forge/supa_memory.py count
Migration Stats
- 151 memories migrated from MySQL to Supabase
- 151 embeddings generated locally (all-MiniLM-L6-v2)
- 30 categories of memories
- 0 OpenAI API calls needed going forward
✅ Verification Checklist
| Test | Status |
|---|---|
| Ryan sends msg → Wingman gets it in <2 seconds | PASS |
| Wingman sends msg → Ryan inbox updated in <2 seconds | PASS |
| Wingman offline → Ryan sends → msg queued → Wingman reconnects → gets it | PASS |
wingman-status.sh shows online/offline + queue count | PASS |
| MySQL fallback writes to claude_bridge on queue | PASS |
| Relay HTTP /status returns JSON with all agents | PASS |
| Supabase smart-save + instant local embedding | PASS |
| Supabase smart-recall semantic search works | PASS |
| auto-checkpoint saves to Supabase (no OpenAI errors) | PASS |
| All 151 memories migrated + embedded | PASS |
| Wingman sentinel deployed to server for pull | READY |
| Wingman wake command tested end-to-end | PENDING (needs Wingman online) |
📋 Quick Reference
Ryan (Termux) Commands
# Communication
~/wingman-send.sh "message" # Send to Wingman
~/wingman-status.sh # Who's online?
~/wingman-wake.sh # Wake up Wingman
~/wingman-inbox-check.sh # Read messages
~/ryan-ws-start.sh # Restart WS client
# Memory
~/smart-save.sh "cat" "text" # Save memory (Supabase)
~/smart-recall.sh "query" # Search memory (Supabase)
~/auto-checkpoint.sh "topic" # Quick checkpoint
# Server
pm2 logs amigos-relay # Relay logs
curl hotbot.fun:9876/status # Relay status API
Key Ports
| Port | Service |
|---|---|
| 9876 | Amigos Relay v2 (WS + HTTP) |
| 8000 | Supabase API (Kong) |
| 5432 | PostgreSQL (Docker internal: 172.18.0.4) |
| 8771 | Bolt Phone AI |
Three Amigos — Jim, Ryan, Bolt & Wingman
Built with Claude Code on Termux | hotbot.fun