docs(roadmap): add Ollama Cloud provider + backend switch as the next item

A laptop-dev enabler (planned, not specced): extend the proxy's M1 model-call
pipeline with an Ollama Cloud backend reachable via API key, plus a switch to
flip local-ollama <-> ollama-cloud, so AI works off the homelab.

Reconciles against §4: the API key and provider choice stay server-side in the
proxy (the client never holds a key, never picks the backend). The title
Settings-button "config file" splits — the client may hold only the proxy
base URL / profile (folds into M9); the provider/key switch is proxy config.

Filed under a renamed "Landed / planned out of band" section and pointed to
from the sequencing table as the next task before M5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-15 05:27:04 -05:00
parent 7f155b8de2
commit f5e6c59f2a

View File

@@ -37,17 +37,24 @@ M0M2 built the **engine** (the contract, the client, the server loop, bounded
| **M2 — Prove aliveness** ✅ | **Does bounded AI dialogue feel alive?** — answered; bounded NPC dialogue + DM loop live-proven. |
| **M3 — Visual foundation & shell** ✅ | The `Theme` + the exploration HUD; every screen inherits the look and lives in the shell. |
| **M4 — Character creation** ✅ | The player enters the world; the proven stat/Luck model gets its UI. |
| **M5 — Tactical combat (gridless)***here* | Real stakes: the Combat HUD turn manager. |
| **M5 — Tactical combat (gridless)** | Real stakes: the Combat HUD turn manager. |
| **M6 — Dialogue screen** | The proven NPC free-text loop inside the mock's conversation UI. |
| **M7 — Inventory & character sheet** | State the player can see and manage. |
| **M8 — World systems** | World-map travel, a shop economy, the quest log. |
| **M9 — Framing, AI-flavor & persistence** | Title/pause, save/load, and the Improviser/Banter/Luck-drift roles + fallback sweep. |
### Landed out of band
**▶ Next (before M5):** *Provider flexibility — Ollama Cloud + a backend switch* (in **Landed / planned out of band**, below). A laptop-dev enabler: it lets the proxy serve the same Ollama-hosted models over an API key from any machine, so development continues away from the homelab. Not a game-screen milestone — a cross-cutting infra item taken now because the alternative is a laptop with no AI.
Not every item is a milestone. These shipped on their own because a later milestone
would have been more expensive to build on top of the old shape.
### Landed / planned out of band
Not every item is a milestone. Some shipped on their own because a later milestone
would have been more expensive to build on top of the old shape; some are planned
cross-cutting work that does not belong to a single screen.
-**Provider flexibility — Ollama Cloud + a backend switch** *(next; not yet specced — a future session builds it).* Development spans two machines: a desktop with the homelab Ollama, and a laptop with no homelab reach. Today the proxy's model-call pipeline (M1) only knows a **local** Ollama, so the laptop has no AI at all. This adds **Ollama Cloud** as a backend so the same Ollama-hosted models are reachable over an **API key** from anywhere, and a **switch** to flip between `local-ollama` (desktop, free/offline) and `ollama-cloud` (laptop) — and the door stays open for prod's Replicate (§4) as a third backend.
- **§4 is load-bearing — the key and the provider choice live server-side, in the proxy.** The client never holds an API key and never learns which backend serves a role (§4). Concretely: extend the proxy's Ollama httpx client (M1) to target an **Ollama-compatible cloud endpoint** with an **`Authorization: Bearer <key>`** header, the key read from the proxy's environment / `.env`, never a client binary. The "flip a switch" is a **proxy config/env** value selecting the backend (endpoint + key + per-role model ids) — this is the M1 role→model routing config growing a *backend* axis, a deploy/config change, not a client patch, exactly as §4 intends.
- **The client's Settings-button angle (reconcile, don't silently adopt):** the "config file surfaced by the title **Settings** button" is a real feature, but under §4 it splits in two. **Legit client setting:** the **proxy base URL / profile** (§4 lets the client know *one base URL*) — a persisted client config choosing "laptop proxy" vs "desktop proxy," editable via the M9 Settings screen. **NOT a client setting:** the AI **provider and API key** — those stay in the proxy; the Settings screen must never hold the key or pick the backend, or the §4 boundary leaks into a shippable binary. So the honest "flip a switch" is *two* switches — a proxy-side provider/key config (this item, the immediate laptop-dev enabler) and a client-side base-URL/profile that **folds into M9's settings + persistence**. For laptop work right now, only the proxy switch is needed.
- *§2: text (the provider serves text; the client stays provider-agnostic) · depends on the M1 pipeline · goal: AI on any machine, switchable — and a proxy that is already multi-backend before Replicate (§4) arrives.*
-**Currency — copper with real denominations** ([spec](superpowers/specs/2026-07-12-currency-copper-design.md)). `1g = 100s = 10,000c`, **stored entirely in copper** as one `GameState.purse_copper` int, formatted only at the display edge (`◈ 3s 47c`). `coin.json``copper`/`silver`/`gold`. Money is **not** an inventory item: `give_item`/`accept_item` carry no quantity and `gifts_given` is a global one-shot, so a lone `copper` id would have been givable once, for one copper, per campaign — the denominations are **move tokens** instead (`give_item(gold)` = +10,000c), routed to the purse and never into `inventory`, so money cannot surface in an inventory grid by construction. Taken before M7 while `content/world/items/` held two files. **Prices remain M8's content BOM — nothing is priced yet.** *§2: state · goal: money that means something.*
-**A move applies at most once per reply** — found by the review of the above. `TagExtractor` returns *every* tag occurrence and `MoveValidator` is a membership test, so a model repeating a tag N times picked an amount **in unary** (§2 breach: the AI choosing a number). Now deduped by (name, id) across a reply, and `adjust_disposition`'s `MAX_DELTA` caps the reply's **net** swing rather than each tag — it was per-tag, so three `+15`s moved standing by 45, the exact "wholesale swing" the constant forbids. *§2: state · goal: the bounded vocabulary stays bounded.*