# ORACLE-OS-SETTINGS-GOAL.md — the Oracle OS control + Settings + multi-tenant plan

| | |
|---|---|
| **Version** | v1 (2026-07-12) |
| **Owner** | Ryan (nastermodx) |
| **Status** | Phase 0 STARTED — control-area bugs 1 & 3 fixed in code; bug 2 (restart) specced, pending owner test. Settings + multi-tenant = designed, not built. |
| **Companion docs** | `RELEASE-READINESS.md` (multi-USER phases), `The KAI Codex.md` (source of truth), `CLAUDE-CODE-HANDOFF.md` |
| **⚠️ SPLIT (2026-07-16)** | **User + workspace Spaces/Settings** = `KAI-SPACES-AND-USER-SETTINGS-GOAL.md` (product). **This file** = **host industrial** Oracle OS control (fleet, providers, rebuild). Do not mix UIs. |

This doc exists so the work survives context loss / truncation. **Anyone picking this
up: read §7 "RESUME HERE" first.** Everything below has file:line refs so you never
re-investigate from scratch.

---

## 1. The vision (owner's intent, reflected)

The Oracle OS dashboard must actually *work as a control surface*, then grow into a
full settings/OS:

1. **Control basics must work** — online/offline status must be accurate; restart must
   restart; rebuild/compile must recompile the engine and come back.
2. **Config → "Oracle OS Settings"** — one settings surface that consolidates everything:
   OpenJarvis/provider settings, per-section/department/sector controls, per-AI settings,
   human settings, and the connections between Discord and the Oracle-OS.
3. **Multi-tenant** — server-side, so instances can be *rented*: each tenant gets their
   own isolated ecosystem (their own bots/agents, settings, Discord connections) for work
   or personal use.

---

## 2. Current reality (verified 2026-07-12)

- The **fleet IS running** — `state/ecosystem-manager.json` was fresh (updatedAt within
  seconds of now, 12 children, all `connected:true` except a sleeping Gemini). So the
  control area is broken on the **read/consume** side, not because nothing's alive.
- Auth wall is **ON** (`CC_CONTROL_TOKEN` is set) — every control POST needs an owner
  session cookie or `x-cc-token`. Relevant when a button "does nothing": check for 401/403
  in the browser Network tab.
- The system is **single-ecosystem with RBAC** — one engine (:3334), one `.env`, one fleet,
  one `cc_users.json`; many people differentiated only by *role*, all sharing one world.
  "Rent your own ecosystem" is a different architecture that does not exist yet.

---

## 3. Control-area bugs — diagnosis, fixes, status

### BUG 1 — online/offline status wrong  ✅ FIXED IN CODE (pending owner refresh/restart)
- **Cause:** `_buildBotListUncached()` in `command-center-server.mjs` read a schema that
  doesn't exist. It did `eco.processes || eco.bots || eco.agents || eco` (no such keys —
  real file uses a **`children` array**), and `ecoAlive` checked `status/alive/running`
  fields that the manager never emits (real fields: **`connected`/`killed`/`sleeping`**,
  see `ecosystem-manager.mjs` `writeManagerState`). Net: the manager-state fallback was
  dead, so online status depended solely on per-bot IPC `/health` pings — any running bot
  without a live `/health` listener showed DOWN.
- **Fix applied** (`command-center-server.mjs`, ~L1314 + ~L1326): index `eco.children` by
  name (legacy object-map kept as fallback); `ecoAlive = (eRec.connected===true &&
  eRec.killed!==true) || <legacy checks>`.
- **Apply:** restart the dashboard (`.\Start-Dashboard.ps1`) — it's a server change.

### BUG 2 — restart does nothing  ✅ IMPLEMENTED (pending owner live-test)
**Fix applied (2026-07-12):** new re-parented worker `restart-ecosystem-worker.bat`
(does the stop targets of KAI-Stop but with **no `pause`**, then `Start-KAI.ps1`), and
`spawnEcosystemRestart` (`command-center-server.mjs` ~L2551) now launches it **via Task
Scheduler** (`schtasks /create … /sc once /f` + `/run`) instead of as a child `cmd`. The
worker is owned by the Scheduler service, so `taskkill /IM node.exe /T` no longer kills the
relauncher. Also fixes Bug 3's success path (it reuses `spawnEcosystemRestart`). Apply:
`.\Start-Dashboard.ps1`, then click Restart and confirm the fleet comes back (watch Task
Manager). If windows don't appear, the schtasks-run session context may need a tweak
(that's the one thing to verify live).

<details><summary>original diagnosis (kept for reference)</summary>
- **Cause (high confidence):** `/api/control/restart` → `spawnEcosystemRestart(scope)`
  runs `KAI-Stop.bat & timeout 5 & powershell Start-KAI.ps1` via `spawn('cmd', …,
  {detached:true})`. **`KAI-Stop.bat` runs `taskkill /F /IM node.exe /T`** — which kills
  the command-center's own `node.exe` AND the hosting `cmd` (its child) before `timeout`
  and `Start-KAI.ps1` ever run. `detached/unref` does not save it (taskkill `/T` walks the
  parent-PID tree). Result: everything dies, nothing relaunches. Evidence: empty
  `state/last_restart_error.json` + empty `logs/restart-errors.log` (spawn didn't throw; it
  self-killed). Compounding: `KAI-Stop.bat` ends with `pause` (a detached cmd with
  `stdio:'ignore'` can hang there).
- **Fix (to implement + owner-test):** make the restart worker survive the node kill —
  it must NOT be a descendant of the killed node. Options, pick one:
  1. A standalone `restart.bat` that does `timeout` FIRST, then calls `KAI-Stop.bat` (with
     `pause` removed for the automated path), then `Start-KAI.ps1`; launch it re-parented
     via `powershell -Command "Start-Process -WindowStyle Hidden restart.bat"` OR a one-shot
     `schtasks /create /sc once /tn kai_restart …` so Task Scheduler (not the dying node) owns it.
  2. Change `KAI-Stop.bat` to kill node **by PID excluding the command-center + restart
     worker** instead of `/IM node.exe /T`.
- **Files:** `command-center-server.mjs` `spawnEcosystemRestart` (~L2550), `KAI-Stop.bat`,
  `Start-KAI.ps1`. **Test on the live box** (watch Task Manager: today all node/kai/python
  die and Start-KAI never launches).
</details>

### BUG 3 — rebuild/compile does nothing  ✅ PARTIALLY FIXED (cargo scope), shares Bug 2
- **Cause A (fixed):** `REBUILD_CARGO_ARGS` defaulted to `build --release` — no `--bin kai`
  — so it compiled EVERY `[[bin]]` in `Cargo.toml` (test_gguf, kai-bench, kai-shell,
  **kaiverse**). A broken sibling (e.g. the in-progress `kaiverse`) fails the whole build,
  so a perfectly good engine "won't rebuild"; also much slower (near the 20-min timeout).
  **Fixed** (`command-center-server.mjs` ~L2581): default is now `build --release --bin kai`
  (override via `CC_REBUILD_CARGO_ARGS`).
- **Cause B (blocked on Bug 2):** on a successful build the success path calls the SAME
  broken `spawnEcosystemRestart`, so even a green build never brings the fleet back. Fixing
  Bug 2 fixes this too.

**Verification note:** the Linux mount serves stale/truncated snapshots of large files
(`command-center-server.mjs`, `oracle.html`, `The KAI Codex.md`). `node --check` over the
mount reports a false "Unexpected end of input" at the truncation point — the edits above
were confirmed to parse cleanly *before* that point. Always verify on the real Windows file.

---

## 4. Settings inventory (what exists today → what a unified panel must add)

**The entire current "Config" view** = `oracle.html` `renderGlobalConfig()` (~L6382) with
only TWO sections: (1) AI Agent Configuration (per-AI provider/model/voice/port + Edit via
`openAIConfigEditor` ~L6204), (2) Channel Settings (per-channel status + allowed-speaker
chips via `openChannelSettingsEditor` ~L6327). Everything else is `.env`/JSON hand-edit.

**Reusable safe write mechanism already exists:** `updateEnvKeys()`
(`command-center-server.mjs` ~L915) + the `requireControl` + `CC_CONTROL_TOKEN` gate +
`queueBotRestart()` — used by `POST /api/ai/<name>/config` (~L4966) and owner-bio. A unified
Settings panel builds on THIS for the currently-UI-less keys.

**What has UI today:** per-AI provider/model/voice (+ Leo/Groq "extra" fields from
`extraConfigSchema()` ~L1059), owner bio (`POST /api/owner-profile`), channel
enabled/muted/speakerOverride (→ `state/channel_settings.json`), dashboard user accounts +
roles (`/api/users*`), sleep/wake at boot (rewrites `ORACLE_START_SLEEP_BOTS`).

**Gaps — settings with NO UI (hand-edit only), grouped (these are what the panel adds):**
1. **Humans** — add/edit people, roles, voice slots, transcript-channel mapping
   (`identities.mjs` `HUMAN_REGISTRY` L6, `channel-rules.mjs` `USER_TRANSCRIPT_MAP` L29).
2. **Channels / Sectors** — create channels, set groups, edit the *default* speaker rule set
   (`channel-rules.mjs` `CHANNEL_SPEAKER_RULES` L44 — only per-channel overlay is exposed).
   No first-class "department/sector" object exists; nearest analog = channel groups
   (WORK/PUBLIC/GAME/SOCIAL/DREAMS/RADIO lanes).
3. **Provider API keys & per-bot Discord tokens** — raw `.env` (`*_API_KEY`,
   `ORACLE_DISCORD_TOKEN_*`).
4. **Behavior flags** — the whole `KAI_*` rate/ingest/timeout set, un-exposed `LEO_*` voice
   tuning (`LEO_NEURAL_VAD`, `LEO_UTTERANCE_*`, `LEO_JITTER_MS`, …), `PIPELINE_STOP_*`,
   `ANTIGRAV_*`.
5. **Provider routing / failover** — `openjarvis.mjs` `PER_BOT_PRIMARY_MODEL` (L141),
   `GEMINI_TEXT_MODELS` + cooldown (L180-208), failover order/cooldowns
   (`failure-tracker.mjs`).
6. **Discord ↔ Oracle wiring** — `ORACLE_GUILD_ID`, `ENGINE_HOST/PORT`, proxy URLs.
7. **AI registry** — ids/ports (`identities.mjs` `AI_REGISTRY` L40).

---

## 5. Multi-tenant assessment (from RELEASE-READINESS + auth code)

**What exists (genuinely rentable-ready in *shape*):** a well-built RBAC/session layer —
roles `owner>admin>member>viewer>guest` (`command-center-server.mjs` L577-590), timing-safe
token login → server-side session cookie (`/api/login` L4147), gates
`requireControl/Owner/Member` (L715-733), user store `state/cc_users.json` (sha256 token
hashes, never plaintext), owner-only user mint/role/disable/revoke (`/api/users*`), and a
guest "cloud wall" that denies all but 4 read routes (L4191-4216).

**Why it's single-tenant by construction (the load-bearing singletons):**
- One engine (`:3334`), one dashboard (`:3001`), one `.env`, one `STATE_DIR`, one
  `cc_users.json`, one `OWNER_ID`.
- One shared Discord fleet with hardcoded names + one token set.
- One shared lattice/brain — per-user `user_id` cells mix into ONE global brain
  (RELEASE-READINESS notes this as cross-talk/pollution + a privacy exposure).
- User records have `role` but **no `tenantId`**; the guest wall is deny-only, not
  scope-to-your-own-data.

**RELEASE-READINESS.md is a *different axis*** (many people → ONE KAI with clearance;
composite readiness ~1.5–2.5 / 5). Completing it yields a hardened *single-tenant multi-user*
KAI — it does NOT deliver per-tenant isolation.

**Phase ordering today → multi-tenant (cheap → hard):**
1. `tenantId` as a first-class field on user records + a tenant registry. *Cheap schema,
   medium call-site sweep.*
2. Data partitioning — scope `cc_users.json`, warehouse, lattice cells by tenant; make the
   wall filter to own-tenant data. *Hard — core data-separation + privacy lift.*
3. Config/secret isolation — per-tenant `.env`/secret namespace. *Medium.*
4. Engine isolation — per-tenant engine process + tenant→port router, OR one engine with
   enforced `tenantId` on every read/write. *Hard — biggest architectural fork.*
5. Per-tenant Discord fleet + verified identity — self-serve bot-token onboarding, Discord
   OAuth (replace owner-asserted `discordVerified:false`), per-tenant bot processes.
   *Hardest / most net-new.*
6. Per-tenant settings + billing/lifecycle (provision, teardown, quotas). *Net-new.*

---

## 6. The build plan (phases)

**PHASE 0 — make control work (in progress).** Bug 1 ✅, Bug 3 (cargo) ✅, Bug 2 restart ⛔
(spec in §3, implement + owner-test). Acceptance: status shows accurate LIVE/DOWN; Restart
brings the fleet back; Rebuild recompiles `kai` and relaunches on success.

**PHASE 1 — "Oracle OS Settings" shell.** Rename/reframe the Config view as "Oracle OS
Settings"; restructure into sections (Departments/Sectors · AIs · Humans · Discord↔Oracle ·
Providers/Models · Channels · System/Flags). Reuse `renderGlobalConfig` + `updateEnvKeys` +
the gated write pattern. Additive, surgical edits to `oracle.html` only.

**PHASE 2 — fill the gaps (§4).** Add UI + gated `/api/*` writers for the currently-UI-less
settings, one group at a time (safest first: behavior flags & provider routing that already
map to `.env` keys; hardest last: humans/channels that live in code `identities.mjs` /
`channel-rules.mjs` — those need a JSON overlay layer like `channel_settings.json`).

**PHASE 3 — multi-tenant (per §5).** Start at `tenantId` + tenant registry; do NOT attempt
engine/lattice/fleet isolation until data partitioning + config isolation land. Ties into
RELEASE-READINESS Phase B (verified identity / OAuth).

---

## 7. RESUME HERE (continuation checklist — read this first)

**Done in code (2026-07-12), pending owner apply/verify:**
- [x] Bug 1 status read-side fix — `command-center-server.mjs` ~L1314 (`eco.children`) +
      ~L1326 (`connected/killed`). → restart dashboard, confirm bots show LIVE.
- [x] Bug 3 cargo scope — `REBUILD_CARGO_ARGS` default `build --release --bin kai` ~L2581.
- [x] Bug 2 restart re-parenting — new `restart-ecosystem-worker.bat` + `spawnEcosystemRestart`
      now launches it via `schtasks` (Scheduler-owned, survives the node kill). ~L2551.

**Next actions, in order:**
1. **Owner live-test the restart** — `.\Start-Dashboard.ps1`, click Restart, watch Task
   Manager: the fleet should stop then come back via Start-KAI. If Start-KAI's windows don't
   appear, the schtasks-run session context needs a tweak (`/ru` or run-as-current-session).
   Also test Rebuild (owner-only) end-to-end now that both the cargo scope + restart are fixed.
2. Owner confirm Bug 1: does status now read accurately? If some bots still show DOWN while
   `connected:true` in `ecosystem-manager.json`, check their IPC `/health` ports
   (`BOT_ROSTER` 3400-3420) with `curl 127.0.0.1:3401/health`.
3. Phase 1 Settings shell (oracle.html, surgical).
4. Phase 2 gap UIs (start with `.env`-backed flags via `updateEnvKeys`).
5. Phase 3 `tenantId` groundwork.

**Hard rules carried from CLAUDE.md:** never wholesale-rewrite `oracle.html` /
`command-center-server.mjs` (surgical only); verify against the REAL Windows file (mount
lies/truncates); never print `.env` secret VALUES; keep the Codex + `Cargo.toml` version in
sync after meaningful changes.

**Key files:** `command-center-server.mjs` (control routes, `_buildBotListUncached`,
`spawnEcosystemRestart`, `startRebuildRestart`, `updateEnvKeys`, auth gates),
`ecosystem-manager.mjs` (`writeManagerState`), `KAI-Stop.bat`, `Start-KAI.ps1`,
`oracle.html` (`renderGlobalConfig` ~L6382), `shared/openjarvis.mjs`, `shared/identities.mjs`,
`shared/channel-rules.mjs`, `state/ecosystem-manager.json`, `state/cc_users.json`,
`RELEASE-READINESS.md`.
