RELEASE-READINESS.md (multi-USER phases), The KAI Codex.md (source of truth), CLAUDE-CODE-HANDOFF.md |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.
---
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.
---
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.
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.
.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.
---
_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.
command-center-server.mjs, ~L1314 + ~L1326): index eco.children byname (legacy object-map kept as fallback); `ecoAlive = (eRec.connected===true &&
eRec.killed!==true) || <legacy checks>`.
.\Start-Dashboard.ps1) — it's a server change.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>
/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).
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.
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>
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).
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.
---
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).
---
**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):
:3334), one dashboard (:3001), one .env, one STATE_DIR, one cc_users.json, one OWNER_ID.
user_id cells mix into ONE global brain(RELEASE-READINESS notes this as cross-talk/pollution + a privacy exposure).
role but no tenantId; the guest wall is deny-only, notscope-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.*
---
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).
---
Done in code (2026-07-12), pending owner apply/verify:
command-center-server.mjs ~L1314 (eco.children) + ~L1326 (connected/killed). → restart dashboard, confirm bots show LIVE.
REBUILD_CARGO_ARGS default build --release --bin kai ~L2581.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.