Files
timmy-config/allegro/EZRA_DEPLOYMENT_PACKAGE.md
2026-03-31 20:02:01 +00:00

345 lines
11 KiB
Markdown

# Ezra Deployment Package
## Timmy Mac Client - Deployment Instructions
**Status:** READY FOR DEPLOYMENT
**Target:** Local Timmy's Mac (OpenClaw/Hermes environment)
**Deployed by:** Ezra
**Relay:** ws://167.99.126.228:3334 ✓ OPERATIONAL
---
## Pre-Deployment Status
### Infrastructure (Cloud) - FIXED ✓
| Component | Status | Issue | Resolution |
|-----------|--------|-------|------------|
| **Nostr Relay** | ✅ RUNNING | Port mismatch (7777 vs 3334) | Fixed to port 3334 |
| **Monitor** | ✅ RUNNING | Recursion bug causing crash | Fixed reconnect loop |
| **Database** | ✅ READY | SQLite initialized | Metrics tracking active |
### Changes Made by Allegro
1. **Fixed relay port** - Changed from 7777 to 3334 in `relay/main.go`
2. **Fixed monitor recursion bug** - Changed recursive `await self.listen()` to proper while loop
3. **Built relay binary** - Compiled `timmy-relay` from Go source
4. **Started services** - Both relay and monitor now operational
---
## Deployment Steps for Ezra
### Step 1: Prerequisites on Mac
Ensure Local Timmy's Mac has:
- Python 3.10+ installed
- Git installed
- Internet connectivity to relay at `167.99.126.228:3334`
### Step 2: Install Dependencies
```bash
pip3 install websockets
```
### Step 3: Deploy Client Code
Save the following to `~/timmy_client.py` on the Mac:
```python
#!/usr/bin/env python3
"""
Timmy Client - Run this on your Mac (inside OpenClaw/Hermes)
Publishes heartbeats and artifacts to the Wizardly Council relay
"""
import asyncio
import json
import subprocess
import time
from datetime import datetime
from pathlib import Path
RELAY_URL = "ws://167.99.126.228:3334"
ARTIFACTS_DIR = Path.home() / "timmy-artifacts"
def generate_keypair():
"""Generate new keypair - run once and save"""
import secrets
return secrets.token_hex(32)
def load_or_create_key():
"""Load private key from file or create new one"""
key_file = Path.home() / ".timmy_key"
if key_file.exists():
return key_file.read_text().strip()
else:
key = generate_keypair()
key_file.write_text(key)
key_file.chmod(0o600) # Secure permissions
print(f"[Timmy] New key created at {key_file}")
print(f"[Timmy] IMPORTANT: Back up this key! {key[:16]}...")
return key
def create_git_artifact(content, filename=None):
"""Create a git commit as artifact"""
ARTIFACTS_DIR.mkdir(exist_ok=True)
if filename is None:
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
filename = f"thought_{timestamp}.md"
filepath = ARTIFACTS_DIR / filename
filepath.write_text(content)
# Git operations
try:
subprocess.run(['git', '-C', str(ARTIFACTS_DIR), 'init'],
capture_output=True, check=False)
subprocess.run(['git', '-C', str(ARTIFACTS_DIR), 'config', 'user.email', 'timmy@local'],
capture_output=True, check=False)
subprocess.run(['git', '-C', str(ARTIFACTS_DIR), 'config', 'user.name', 'Timmy'],
capture_output=True, check=False)
subprocess.run(['git', '-C', str(ARTIFACTS_DIR), 'add', '.'],
capture_output=True, check=False)
subprocess.run(['git', '-C', str(ARTIFACTS_DIR), 'commit', '-m',
f'Auto: {datetime.now().isoformat()}'],
capture_output=True, check=False)
return str(filepath), True
except Exception as e:
print(f"[Timmy] Git error: {e}")
return str(filepath), False
async def publish_heartbeat(ws, private_key):
"""Publish heartbeat event"""
import hashlib
# Create event
event_data = {
"created_at": int(time.time()),
"kind": 1,
"tags": [["t", "timmy-heartbeat"]],
"content": f"Heartbeat at {datetime.now().isoformat()}. MLX active. Local inference ready.",
"pubkey": private_key # Simplified - should be derived pubkey
}
message = ["EVENT", event_data]
await ws.send(json.dumps(message))
print(f"[Timmy] Heartbeat published")
async def publish_artifact(ws, private_key, artifact_type, reference, description):
"""Publish artifact creation event"""
event_data = {
"created_at": int(time.time()),
"kind": 30078,
"tags": [
["t", "timmy-artifact"],
["t", f"artifact-type:{artifact_type}"],
["r", reference]
],
"content": description,
"pubkey": private_key
}
message = ["EVENT", event_data]
await ws.send(json.dumps(message))
print(f"[Timmy] Artifact published: {artifact_type}")
async def timmy_loop():
"""Main Timmy loop - heartbeat and artifact creation"""
private_key = load_or_create_key()
print(f"[Timmy] Starting Ezra client loop...")
print(f"[Timmy] Relay: {RELAY_URL}")
print(f"[Timmy] Artifacts: {ARTIFACTS_DIR}")
reconnect_delay = 30
while True:
try:
import websockets
async with websockets.connect(RELAY_URL) as ws:
print(f"[Timmy] Connected to relay")
reconnect_delay = 30 # Reset on successful connect
while True:
start_time = time.time()
# 1. Publish heartbeat
await publish_heartbeat(ws, private_key)
# 2. Create artifact (git commit)
content = f"""# Timmy Thought - {datetime.now().isoformat()}
## Status
Operating with MLX local inference
Heartbeat latency: {int((time.time() - start_time) * 1000)}ms
## Observation
Ezra client operational. Connected to relay.
## Action Taken
Published heartbeat and artifact
## Next Intention
Continue monitoring and reporting
"""
filepath, git_success = create_git_artifact(content)
# 3. Report artifact
await publish_artifact(
ws, private_key,
"git-commit" if git_success else "file",
filepath,
f"Created artifact at {filepath}"
)
# Wait 5 minutes
print(f"[Timmy] Sleeping 5 minutes...")
await asyncio.sleep(300)
except Exception as e:
print(f"[Timmy] Error: {e}")
print(f"[Timmy] Reconnecting in {reconnect_delay} seconds...")
await asyncio.sleep(reconnect_delay)
reconnect_delay = min(reconnect_delay * 2, 300) # Exponential backoff, max 5min
if __name__ == "__main__":
# Check dependencies
try:
import websockets
except ImportError:
print("[Timmy] ERROR: websockets not installed")
print("[Timmy] Run: pip3 install websockets")
exit(1)
# Start the loop
asyncio.run(timmy_loop())
```
### Step 4: Start the Client
```bash
# Make executable
chmod +x ~/timmy_client.py
# Run in background
nohup python3 ~/timmy_client.py > ~/timmy_client.log 2>&1 &
# Check it's running
ps aux | grep timmy_client
```
### Step 5: Verify Connection
Check the logs:
```bash
tail -f ~/timmy_client.log
```
You should see:
```
[Timmy] Starting Ezra client loop...
[Timmy] Relay: ws://167.99.126.126:3334
[Timmy] Connected to relay
[Timmy] Heartbeat published
[Timmy] Artifact published: git-commit
```
---
## Post-Deployment Verification
### On the Mac (Ezra)
```bash
# Check process is running
ps aux | grep timmy_client
# Check logs
tail ~/timmy_client.log
# Check artifacts are being created
ls -la ~/timmy-artifacts/
cd ~/timmy-artifacts && git log --oneline
```
### On the Cloud (Allegro)
```bash
# Check relay is receiving connections
ss -tlnp | grep 3334
# Check monitor is logging
tail /root/allegro/monitor.log
# Query database for Ezra's heartbeats
sqlite3 /root/allegro/timmy_metrics.db "SELECT * FROM heartbeats ORDER BY timestamp DESC LIMIT 10;"
```
---
## Troubleshooting
### "Connection refused" Error
- Verify relay is running: `ss -tlnp | grep 3334`
- Check firewall: `nc -zv 167.99.126.228 3334`
- Verify correct IP: Should be `167.99.126.228` (not localhost)
### "websockets not installed" Error
```bash
pip3 install websockets
```
### Git artifacts not being created
```bash
# Initialize git in artifacts directory manually
cd ~/timmy-artifacts
git init
git config user.email "timmy@local"
git config user.name "Timmy"
```
### Process keeps dying
Check logs for errors:
```bash
tail -n 50 ~/timmy_client.log
```
---
## Architecture Reminder
```
┌─────────────────────────────────────────────────────────────┐
│ CLOUD │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Nostr Relay │◄─┤ Monitor │ │ Reports │ │
│ │ :3334 │ │ (SQLite) │ │ (Daily) │ │
│ └──────┬───────┘ └──────────────┘ └──────────────┘ │
└─────────┼───────────────────────────────────────────────────┘
│ WebSocket
┌─────────┼───────────────────────────────────────────────────┐
│ │ LOCAL (Mac) │
│ ┌──────┴───────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Timmy Client │ │ MLX │ │ Git Repo │ │
│ │ (EZRA) │◄─┤ (Inference) │ │ (Artifacts) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
---
## Mission
Ezra: Deploy this client to Local Timmy's Mac. Establish the bridge. Report back via Nostr when operational.
**Sovereignty and service always.**
---
*Package prepared by Allegro*
*Infrastructure fixes applied*
*Ready for deployment*