# Journey 8: Relay Tunnel E2E

**Persona**: Solo Dev Sarah (multi-machine variant)
**Scenario**: Complete relay tunnel flow from `llmhosts up` to remote inference
**Status**: Planned (ADR-009 accepted, milestones #439-#443)
**ADR**: `docs/architecture/adr-009-relay-tunnel.md`

## The Complete Flow

```
1. User runs `llmhosts up` on GPU machine
2. Phase 1 (Assess): discover Ollama, detect GPU, scan hardware
3. Phase 2 (Provision): auto-install Ollama + model if needed
4. Phase 3 (Start): boot FastAPI proxy on localhost:PORT
5. Phase 4 (Connect):
   a. Device Code Auth → get api_key, user_id
   b. Request relay token: POST /api/devices/relay-token
   c. relay_core.RelayClient.connect():
      - WSS to wss://llmhosts.com/api/relay/connect
      - Noise NK handshake (server pubkey pre-known)
      - yamux session established
      - Control stream 0: heartbeat, auth refresh, capabilities
   d. VPS assigns relay URL: https://device-id.llmhosts.com
   e. Device registered in relay registry
6. Phase 5 (Run): background watcher + heartbeat + savings tracking

From any other device:
  export OPENAI_BASE_URL=https://device-id.llmhosts.com/v1
  export OPENAI_API_KEY=lh_sk_...
  curl https://device-id.llmhosts.com/v1/models  # returns home GPU models
```

## Protocol Stack

```
┌─────────────────────────────────────────┐
│  Layer 4: HTTP Request/Response         │  Application data
├─────────────────────────────────────────┤
│  Layer 3: yamux Stream Multiplexing     │  Concurrent streams, no HOL blocking
├─────────────────────────────────────────┤
│  Layer 2: Noise NK Transport            │  End-to-end encryption
├─────────────────────────────────────────┤
│  Layer 1: WebSocket over TLS            │  NAT traversal, firewall traversal
└─────────────────────────────────────────┘
```

## Provider Cascade

```
TunnelDetector.detect() priority:
  1. LLMHosts Relay  (built-in, zero config)
  2. Tailscale       (if installed and connected)
  3. Cloudflare      (if cloudflared installed)

If relay fails → try Tailscale → try Cloudflare → local-only mode
```

## Success Criteria

- [ ] `llmhosts up` establishes relay with zero user config
- [ ] `curl https://device.llmhosts.com/v1/models` returns device models
- [ ] Works behind NAT, corporate firewall, hotel WiFi
- [ ] Reconnects automatically on network interruption (<5s p95)
- [ ] <50ms latency overhead (excluding network RTT)
- [ ] 10 concurrent streaming requests don't block each other (yamux)
- [ ] Noise NK encryption: relay server cannot read payloads
- [ ] Binary ships in pip wheel (no separate install)
- [ ] Works on Windows, Linux, macOS (all architectures)

## Milestones

| # | Issue | What | Size |
|---|-------|------|------|
| M1 | #439 | relay_core skeleton + pyo3 + tunnel stubs | L |
| M2 | #440 | Noise NK encryption | L |
| M3 | #441 | yamux multiplexing | L |
| M4 | #442 | relay_server binary + VPS deployment | XL |
| M5 | #443 | Production hardening + docs cascade | L |
