When Neo's laptop is off, Trinity-CLI answers. Same Claude family, different machine.
Runs claude -p on the Oracle VM with a
concatenated CLAUDE.md of all
.cursor/rules/*.mdc files, so it shares memory with Trinity-Cursor.
Zion auto-routes between the two — Neo just sends @trinity from WhatsApp and gets an answer,
no matter where.
Routing is now prefix-driven with a 10-min sticky session per chat
— no more heartbeat decisions. Zion remembers who owns the chat (CLI or Cursor)
and silently extends the timer on follow-ups. Owner-gated: only Neo can open
a Trinity / Trinity-CLI session.
NEW · Apr 2026
Construct-CLI · Peer Consult Endpoint
Trinity-CLI can now directly consult Trinity-Cursor (or any registered
Construct) without going through Neo. Visible to Neo by design — the back-and-forth shows
up live in his chat with [X→Y] envelopes.
Generic primitive — same path could call Lobo, future agents, etc. via
constructs.json.
WIRE FORMAT
[Trinity-CLI→Trinity] <question> # caller envelope (visible to Neo) [Trinity→Trinity-CLI] <answer> # peer reply (visible to Neo) [Trinity-CLI] <final reply> # Trinity-CLI's own message to Neo
# Generic — same envelope format for any pair listed in constructs.json. # Zion never adds a "Received ✓" ack to a peer envelope.
Reads CLAUDE.md (built from same .mdc files as Trinity-Cursor)
Always available — VM is 24/7 on free tier
NEW: peer-consults Trinity-Cursor via construct_cli.py
Reply: [Trinity-CLI] (when Neo wrote @trinity-cli) or [Trinity] (when Neo wrote @trinity)
Used for: Q&A any time, peer consults, sticky CLI sessions
Heartbeat & Claim Lock (no double-reply)
# trinity_ws.py — VM side, on every WebSocket HEARTBEAT from laptopdef update_heartbeat(worker_id):
conn.execute(
"INSERT INTO trinity_workers (worker_id, worker_type, last_seen, status) ""VALUES (?, 'cursor', ?, 'online') ""ON CONFLICT(worker_id) DO UPDATE SET last_seen=?, status='online'",
(worker_id, now, now))
# trinity_queue.py — the liveness check Zion usesdef is_online():
last = row['last_seen']
return (utcnow() - last).total_seconds() < HEARTBEAT_TIMEOUT# 45s# trinity_cli_runner.py — atomic claim lock, prevents double-replydef claim_as_cli(task_id):
cur = db.execute(
"UPDATE trinity_tasks ""SET claimed_by='trinity-cli', status='claimed' ""WHERE task_id=? AND (claimed_by IS NULL OR claimed_by='')",
(task_id,))
return cur.rowcount > 0 # True = we got it, False = laptop beat us
Live tests
Real messages, real replies — through the actual system.
Routing · 21-Apr-2026
Neo → @trinity-cli E2E test: reply in 5 words confirming you are Trinity-CLI on VM
[Trinity-CLI] VM-based Trinity-CLI is operational here.
Neo → @trinity-cli are you in VM or laptop?
[Trinity-CLI] I'm on the VM (Oracle Cloud, 80.225.205.232).
Construct-CLI peer consult · 26-Apr-2026
Neo → @trinity-cli yes, that's my understanding... can you talk to Trinity (laptop) as well? Confirm the [Trinity] vs [Trinity-CLI] prefix and discuss together. Trinity should reply with 3 options.
[Trinity-CLI→Trinity] Neo wants us to discuss the agent-comm plan. Do you think a generic constructs.json registry is the right call vs hardcoding trinity-cli ↔ trinity?
[Trinity→Trinity-CLI] Generic registry. Trade-off: 3 more lines today, but adding @loki / @future_agent later costs zero.
[Trinity-CLI] Trinity-Cursor agrees. Going with constructs.json. Options: (1) implement registry + peer consult now, (2) hardcode just CLI↔Cursor and generalize later, (3) skip and rely on user-mediated relays. Recommendation: option 1.
Tech Stack
AI ModelAnthropic Claude Sonnet/Opus (Claude Pro subscription — reachmanav@gmail.com)
Runtime@anthropic-ai/claude-code CLI on Oracle VM (Node.js)
AuthOAuth on laptop → .credentials.json scp'd to VM
MemoryCLAUDE.md (52 KB) auto-built from 4 .mdc files