File size: 12,988 Bytes
3fb5a36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
<!--
SPDX-License-Identifier: Apache-2.0
(c) 2026 Lutar, Stephen P. - SZL Holdings - ORCID 0009-0001-0110-4173 - Doctrine v11
-->

# Sovereign Mesh Runbook — harness the 2-box GPU mesh behind ONE endpoint

**You are at the LAPTOP (`betterwithage`, RTX 5050) right now.** These are your hands —
the cloud agent cannot reach your LAN. Follow the PowerShell baby-steps in order.
Copy-paste one block at a time and read the "you should see" line before moving on.

**What we are building:** the cloud a11oy Space calls **ONE** endpoint
(`gateway.a-11-oy.com`, model `sovereign-llm`); a **LiteLLM** gateway load-balances
your two Windows GPU boxes (tower `omen` RTX 4060 Ti + this laptop `betterwithage`
RTX 5050), both running **Ollama**. Everything is durable (boot-persistent tasks) and
self-healing (restart policies + LiteLLM node cooldown). Cloudflare = public ingress,
Tailscale = private transport, Docker = the stateless sidecars only.

```
a11oy Space (cloud)
   |  HTTPS + Bearer + CF-Access-Client-*    (ONE endpoint)
   v
Cloudflare edge (Access service token)  ->  gateway.a-11-oy.com
   v  (cloudflared, outbound-only tunnel)
LiteLLM :4000  (model "sovereign-llm")
   |  Tailscale (private, tailnet-only :11434)
   +--> omen         Ollama  (llama3.1:8b)
   +--> betterwithage Ollama (glm-4.7-flash + the #789 energy probe)
```

> **HONESTY (Doctrine v11).** Nothing below "goes green" on faith. A node is only
> `wired`/`live` when a **real** call to it succeeds THIS request. Joules are
> **MEASURED** only from a real NVML delta (the #789 probe); otherwise the honest
> `MEASURED_SHARED_BOUNDED` / `UNAVAILABLE` empty-state stands. A truthful BLOCKED
> beats a fake green. **Ollama's `:11434` is never public.**

---

## 0. Prerequisites (one-time, on the laptop)

```powershell
# Confirm the driver + GPU are visible (native, no Docker).
nvidia-smi
# you should see: your RTX 5050 listed, a driver version (want 535+), and power draw.

# Confirm Ollama, Tailscale, cloudflared, python are installed.
ollama --version
tailscale version
cloudflared --version
python --version    # or: py --version
```

If `nvidia-smi` shows the GPU but `power.draw` is `N/A` (some laptop GPUs do), the
#789 probe will honestly emit `UNAVAILABLE` rather than a fake joule — that is fine,
the mesh still works, you just do not get MEASURED joules from this box.

---

## Step (a) — pull glm-4.7-flash + start the #789 energy probe on the laptop

```powershell
# 1. Pull the laptop's model.
ollama pull glm-4.7-flash

# 2. Make sure Ollama accepts the tunneled Host header + binds for the tailnet.
#    (These are the machine-level env the persist script sets; safe to set now.)
[System.Environment]::SetEnvironmentVariable("OLLAMA_ORIGINS","*","Machine")
[System.Environment]::SetEnvironmentVariable("OLLAMA_HOST","0.0.0.0:11434","Machine")

# 3. Start the #789 per-inference energy probe in a LOOP (refreshes every 60s).
#    Writes ~/.a11oy_ollama_energy.json which omen_joule_exporter.py merges as models[].
$env:OLLAMA_MODEL = "glm-4.7-flash:latest"
python box-scripts\ollama_energy_probe.py --loop 60
# you should see: a line per cycle with joules + a VERBATIM label
#   (MEASURED_SHARED_BOUNDED by default; MEASURED only if you assert exclusivity;
#    UNAVAILABLE if NVML/power.draw cannot be read — never a fabricated number).
```

Leave that window running. (For the durable version, `box-scripts\laptop_persist.ps1`
registers Ollama + the exporter + the `laptop-szl` tunnel as AtStartup tasks — run it
**as Administrator** once you have verified the manual path works.)

> **Clean MEASURED (optional):** only if *nothing else* uses the GPU during the window:
> `$env:OLLAMA_GPU_EXCLUSIVE = "1"` before launching the probe. Otherwise keep the
> honest `MEASURED_SHARED_BOUNDED` upper bound — do not upgrade the label.

---

## Step (b) — start LiteLLM (the unified gateway)

Run LiteLLM on the **always-on** box. If the laptop is your always-on box for now,
run it here; normally it lives on `omen`. Two ways — pick ONE.

### (b-native) Native Python — simplest, no Docker/WSL2 (RECOMMENDED to start)

```powershell
pip install "litellm[proxy]"

# Bearer the Space must send (generate a real random key; keep it secret).
$env:LITELLM_MASTER_KEY   = "sk-REPLACE-with-a-real-random-key"
# The shared pool model (must fit BOTH cards for true load-balancing).
$env:SOVEREIGN_POOL_MODEL = "llama3.1:8b"
# Tailscale MagicDNS names (or 100.x IPs from `tailscale ip -4` on each box).
$env:OMEN_OLLAMA_URL      = "http://omen:11434"
$env:BWA_OLLAMA_URL       = "http://betterwithage:11434"
$env:OMEN_MODEL           = "llama3.1:8b"
$env:BWA_MODEL            = "glm-4.7-flash:latest"

litellm --config box-scripts\litellm_config.yaml --port 4000
# you should see: "Uvicorn running on http://0.0.0.0:4000".
```

Verify locally (new PowerShell window):

```powershell
curl.exe -s http://localhost:4000/health/liveliness
# you should see: {"status":"healthy"...}

curl.exe -s http://localhost:4000/v1/models -H "Authorization: Bearer $env:LITELLM_MASTER_KEY"
# you should see: sovereign-llm, omen-llama, betterwithage-glm in the list.

curl.exe -s http://localhost:4000/v1/chat/completions `
  -H "Authorization: Bearer $env:LITELLM_MASTER_KEY" `
  -H "Content-Type: application/json" `
  -d '{"model":"sovereign-llm","messages":[{"role":"user","content":"say ok"}]}'
# you should see: a real completion (proves LiteLLM reached a live Ollama node).
```

### (b-docker) Containerized sidecars — Ollama STILL native

> **WSL2 GPU passthrough is fragile.** Only the *sidecars* go in Docker; Ollama and
> the #789 probe stay native (Step a). If `dcgm-exporter` cannot get the GPU, comment
> it out and rely on the native probe for joules — the meter path does not need it.

```powershell
# .env next to the compose file (NEVER commit it):
#   LITELLM_MASTER_KEY=sk-...      CF_TUNNEL_TOKEN_GPU=...(if using token mode)
#   OMEN_OLLAMA_URL=http://host.docker.internal:11434   (native Ollama on THIS box)
#   BWA_OLLAMA_URL=http://betterwithage:11434            (tailnet)
docker compose -f box-scripts\docker-compose.yml up -d litellm prometheus grafana
docker compose -f box-scripts\docker-compose.yml ps
# you should see: litellm (healthy). On the laptop, use docker-compose.laptop.yml
# which is telemetry-only (dcgm-exporter).
```

---

## Step (c) — verify meter2 `models[]` appears

The #789 probe (Step a) writes energy JSON; `omen_joule_exporter.py` (engine name
`betterwithage` on the laptop) merges it as top-level `models[]` and serves it on
`:9471`, tunneled as `meter2.a-11-oy.com`.

```powershell
# Local exporter (if not already running via laptop_persist.ps1):
$env:OMEN_ENGINE_NAME = "betterwithage"
python box-scripts\omen_joule_exporter.py     # serves 0.0.0.0:9471

# Local check:
curl.exe -s http://localhost:9471/ | python -m json.tool
# you should see: engines[] with engine "betterwithage" AND a top-level models[]
#   entry for glm-4.7-flash with joules_per_token + a VERBATIM label
#   (or an UNAVAILABLE null if NVML/power.draw is not readable — honest, not fake).

# Public check (through the laptop-szl tunnel):
curl.exe -s https://meter2.a-11-oy.com/ | python -m json.tool
# you should see: the same models[] payload.
```

If `models[]` is missing: the probe is not running (Step a) or the energy JSON is
stale (>300s, `OLLAMA_ENERGY_MAX_AGE_S`) → it is intentionally surfaced as
`UNAVAILABLE`, never a stale/fake number.

---

## Step (d) — point the Space at the LiteLLM gateway

Expose LiteLLM publicly as `gateway.a-11-oy.com` via cloudflared (see
`box-scripts/cloudflared_ingress.example.yml` — the real `~/.cloudflared/config.yml`
is on-box, not committed). Then set the **Space secrets**:

| Space secret | Value | Effect |
|---|---|---|
| `SZL_LOCAL_LLM_URL` | `https://gateway.a-11-oy.com` | Points the sovereign-local path at the gateway (single endpoint). |
| `A11OY_SOVEREIGN_GATEWAY_URL` | `https://gateway.a-11-oy.com` | *Preferred.* Takes precedence over `SZL_LOCAL_LLM_URL`; the brain/anatomy use the unified LiteLLM endpoint. **Unset ⇒ falls back to `SZL_LOCAL_LLM_URL` (unchanged).** |
| `A11OY_SOVEREIGN_GATEWAY_KEY` | your `LITELLM_MASTER_KEY` | Bearer sent to the gateway. Secret is never logged/returned. (Fallback name: `SZL_LOCAL_LLM_KEY`.) |
| `SZL_LOCAL_LLM_MODEL` | `sovereign-llm` | The model name LiteLLM load-balances across both nodes. |

> Only **one** of `A11OY_SOVEREIGN_GATEWAY_URL` / `SZL_LOCAL_LLM_URL` is required.
> Set the gateway one to prefer the unified endpoint; both unset ⇒ honest stub.
> If Cloudflare Access is in front, also set the Space's `CF-Access-Client-Id` /
> `CF-Access-Client-Secret` (service token) — layered auth (bearer **and** Access).

---

## Step (e) — verify the Space wired to the mesh

```powershell
# 1. Registry wired_count should increment (sovereign_local now wired).
curl.exe -s "https://szlholdings-a11oy.hf.space/api/a11oy/v1/llm/registry?probe=1" | python -m json.tool
# you should see: wired_count >= 1, "sovereign_local" in wired_model_ids, and its
#   badge {wired:true, base_url: the gateway}. local_live:true ONLY if the node
#   answered THIS request.

# 2. Sovereign health: live + served models THIS request.
curl.exe -s "https://szlholdings-a11oy.hf.space/api/a11oy/v1/llm/sovereign/health" | python -m json.tool
# you should see: env_present:true, live:true, served_models includes sovereign-llm.

# 3. Route a real prompt to the mesh.
curl.exe -s -X POST "https://szlholdings-a11oy.hf.space/api/a11oy/v1/llm/route" `
  -H "Content-Type: application/json" `
  -d '{"prompt":"one sentence: why sovereign inference matters","task_hint":"sovereign"}'
# you should see: routed_via "sovereign_local (...)", a REAL response, and a
#   lambda_receipt (Λ = Conjecture 1, advisory). If the node is down you get an
#   HONEST STUB — the tier selection + Λ + receipt are still real.
```

`/brain/ask` (Wave 1/2) then routes its grounded prompt to `sovereign-llm` through the
same gateway when `A11OY_SOVEREIGN_GATEWAY_URL` (or `SZL_LOCAL_LLM_URL`) is set;
otherwise it honestly returns the retrieved subgraph with "no local model wired".

---

## Security (Doctrine v11 — non-negotiable)

1. **Ollama is NEVER public.** `:11434` is served over the tailnet only. It is not in
   any cloudflared ingress rule. Ollama has no built-in auth — the network IS its auth.
2. **Layered auth on the ONE public endpoint** (`gateway.a-11-oy.com`):
   - **LiteLLM bearer** (`master_key`) required on every request, **and**
   - **Cloudflare Access service token** in front of the tunnel hostname, **and**
   - **Tailnet ACL** (`box-scripts/tailscale_acl.json`, deny-by-default): only
     `tag:llm-gateway` may reach `tag:llm-gpu:11434`. A leaked bearer alone, or a
     leaked Access token alone, is insufficient.
3. **Never use Tailscale Funnel** for Ollama (no funnel grant exists in the ACL).
4. **Pin image tags** on GPU-facing containers; do not auto-update them unattended.
5. **Never commit a key.** `LITELLM_MASTER_KEY`, tunnel tokens, and the gateway bearer
   live only in the shell/`.env`/Space secrets — never in the tree.

## Self-healing / durability

| Layer | Mechanism |
|---|---|
| Ollama (native Win) | `laptop_persist.ps1` / `omen_boot_persist.ps1` — AtStartup task, `RestartCount 999`, `-AllowStartIfOnBatteries`. |
| #789 probe + exporter | Same persist scripts (AtStartup, auto-restart). |
| Tailscale (Win) | "Run unattended" mode; Startup Type = Automatic. |
| cloudflared / litellm / prometheus / grafana / dcgm-exporter | `restart: unless-stopped` + healthchecks (docker-compose). |
| LiteLLM ↔ node failure | `cooldown_time: 30`, `num_retries: 2`, least-busy routing auto-skips a down node. |

## Native-Windows fallback (the honest default)

WSL2 GPU-in-Docker is fragile (driver-version sensitivity, "restart Docker Desktop
fully" gotchas, silent CPU fallback). So the **model-serving path stays native**:
run Ollama + the #789 probe natively (Steps a, c), and containerize only the
stateless sidecars (LiteLLM / Prometheus / Grafana / cloudflared / dcgm-exporter).
If `dcgm-exporter` cannot acquire the GPU in its container, drop it and rely on the
native NVML probe for MEASURED joules — the mesh and the meter both still work.

## Troubleshooting

- **`gpu2`/tunnel 403** → set `OLLAMA_ORIGINS=*` and `OLLAMA_HOST=0.0.0.0:11434` at
  machine level (Step a), then restart Ollama.
- **LiteLLM 401 from the Space** → the Space's `A11OY_SOVEREIGN_GATEWAY_KEY` (bearer)
  must equal `LITELLM_MASTER_KEY`; if Access is on, also send the CF service token.
- **`wired_count` did not increment** → `SZL_LOCAL_LLM_URL` / `A11OY_SOVEREIGN_GATEWAY_URL`
  not set as a Space secret, or the gateway is unreachable (honest stub — not a bug).
- **`models[]` missing on meter2** → the #789 probe is not looping, or the reading is
  stale/`UNAVAILABLE` (NVML/power.draw not readable). Honest empty-state, never faked.
</content>