Admin Console
The Dionysys admin console is a reusable package UI for inspecting and changing adaptive UI configuration at runtime. It is designed as an information and control center for deterministic mode, MCP mode, personalities, calculations, session summaries, resources, and adaptive API status.
The console does not write edits back into source files. It starts from file-seeded backend configuration, saves changes into the backend's in-memory runtime config, and lets you export the active configuration as JSON for future use.
Prototype vs Production
The admin runtime config includes a presentation mode:
prototype: show the control room: admin controls, mode switch, debug panel, variants, personalities, scores, resources, and pending-decision notices.production: hide experiment details from front-facing users and show only lightweight feedback controls.
It also includes a decision application mode:
immediate: apply the selected variant or MCP UI state as soon as the decision resolves.next-refresh: store the resolved personality/decision now, keep the active workspace stable, and apply the UI change on the next refresh/provider mount.
For prototype testing, the admin console also shows the active persistence mode and includes a non-production session randomize tool. That reset clears the session id plus both queued and applied adaptive state for the current session before reloading.
The Excalidraw demo defaults to prototype plus next-refresh.
Enable / Disable
Admin routes are disabled unless the backend opt-in flag is set:
ADMIN_CONSOLE_ENABLED=true npm run dev --workspace=@dionysys-demo/excalidraw-backend
To disable the backend admin API, omit ADMIN_CONSOLE_ENABLED or set it to anything other than true.
The admin API routes live under /api/admin:
GET /api/admin/config
PUT /api/admin/config
POST /api/admin/config/reset
GET /api/admin/config/export
GET /api/admin/overview?sessionId=session_123
The Excalidraw demo renders the admin console as an in-app overlay, not as a standalone browser route. The demo shows the Admin button in development or when the frontend flag is enabled:
VITE_ADMIN_CONSOLE_ENABLED=true npm run dev --workspace=@dionysys-demo/excalidraw-frontend
The backend remains the authority. If the frontend button is visible but ADMIN_CONSOLE_ENABLED is not set, the console will show that the admin API is disabled.
For hosted production builds, the frontend flag is build-time configuration because the demo uses Vite import.meta.env. For example, on Vercel set VITE_ADMIN_CONSOLE_ENABLED=true as a build environment variable, not only as a runtime variable.
To use the live console successfully, all of the following must agree:
- the frontend build must point
VITE_API_BASE_URLat the real backend origin - the backend must allow the deployed frontend origin through
ALLOWED_ORIGIN ADMIN_CONSOLE_ENABLED=truemust be set on the backendVITE_ADMIN_CONSOLE_ENABLED=truemust be present when the frontend is built
Package Component
@dionysys/react exports the reusable console:
import { AdminConsole } from '@dionysys/react';
export function ExperimentAdmin() {
return (
<AdminConsole
apiBaseUrl="http://localhost:3001"
sessionId="session_123"
onConfigSaved={(config) => {
console.log('Saved runtime config', config.mode.defaultMode);
}}
/>
);
}
Props:
| Prop | Type | Purpose |
|---|---|---|
apiBaseUrl | string | Backend origin. Defaults to http://localhost:3001. |
sessionId | string | Optional active session to summarize in the Data and Overview tabs. |
onConfigSaved | (config) => void | Called after save or reset so an app can remount providers from the new runtime config. |
onClose | () => void | Optional close handler for modal or drawer integrations. |
Behind that single export, the package now keeps the admin console split into:
- a root shell component
- a state/orchestration hook for load/save/reset/export behavior
- focused section modules for overview, modes, personalities, calculations, data, APIs, and export
- shared primitives and styles
That split is internal to the package. Consumers still mount the same <AdminConsole /> component from @dionysys/react.
What You Can Control
The console has focused tabs for the main adaptive surfaces:
| Tab | What it shows or edits |
|---|---|
| Overview | Current default mode, connector status, session event count, top deterministic and MCP persona scores, resources, supported tools, and fallback variant. |
| Modes | Default adaptive mode, presentationMode, decisionApplication, provider event threshold, polling interval, MCP minimum confidence, and fallback variant. |
| Personalities | MCP personality resource names, ids, descriptions, decision hints, base weights, scoring signals, actions, and UI states. |
| Calculations | Deterministic personas, initial counts, policy epsilon, event weight rules, and heuristic rules. |
| Data | Summarized interaction data, derived counts, timing metrics, and sanitized recent events for the selected session. |
| Bandit | Inspect and maintain the Thompson-sampling arms — see Bandit tab below. |
| MCP APIs | Runtime API status and the active MCP resource catalog. |
| Export | Full JSON editor, local JSON apply, and JSON export for future use. |
Bandit tab
The Bandit tab opens up the otherwise-opaque weak-signal learner. Arms are grouped by context (<modality>:<expertise>); each arm shows:
- Posterior mean and a 90% credible interval over its Beta posterior.
- Observations (n) — evidence beyond the prior — and the evidence weight
wBandit = n / (n + banditEvidenceK)that sets how much the arm pulls against the LLM. - P(best) — a Monte-Carlo estimate of how often the arm wins a posterior draw. This replaces argmax-of-means as the "would pick" signal, so the highlighted arm reflects genuine uncertainty.
A decision trace (when a sessionId is supplied) reconstructs gate → LLM pick → bandit sample → blend → applied variant from the stored decision metadata. Maintenance controls let you decay all arms once, export/import a snapshot of learned state, or reset everything to priors. Decay status (on/off, effective window, derived γ) is shown alongside the totals. See mcp.bandit.decay for the underlying model.
Runtime Config API
When enabled, the backend exposes the same /api/admin routes listed above.
PUT /api/admin/config validates the full admin config payload before updating runtime state. Invalid config returns 400 with schema issues.
GET /api/admin/overview summarizes session events before returning them. The console sees capped, sanitized recent event metadata rather than raw unbounded payloads.
Excalidraw Demo Integration
The Excalidraw demo mounts the console as an overlay. When the console saves or resets config, the demo:
- Reads
config.mode.defaultMode. - Reads
config.mode.presentationModeandconfig.mode.decisionApplication. - Updates
minEventsBeforeLockandpollingIntervalMs. - Remounts
AdaptiveProviderso lock state and active decisions reset cleanly.
This means you can change the default mode from deterministic to mcp, tune thresholds, edit MCP resources, save, and immediately continue the demo with the active runtime configuration.
Exporting Configuration
Use Export to download:
{
"exportedAt": "2026-04-19T00:00:00.000Z",
"config": {
"version": 1,
"mode": {
"defaultMode": "mcp",
"presentationMode": "prototype",
"decisionApplication": "next-refresh",
"minEventsBeforeLock": 5,
"pollingIntervalMs": 3000
}
}
}
The export is for future use outside the current runtime session. It does not overwrite demos/excalidraw/frontend/src/config/variantConfig.ts or demos/excalidraw/backend/src/services/ExcalidrawMcpResources.ts.
The same rule applies to every control in the console: it edits validated runtime state only. The browser does not rewrite tracked markdown, TypeScript, or config files in the repository.
Safety Model
- Admin APIs are disabled by default and require
ADMIN_CONSOLE_ENABLED=true. - LLM API keys remain server-side.
- Session data is summarized and sanitized before display or LLM connector use.
- Source files are not mutated from the browser.
- Deterministic and MCP decision paths continue to validate config through package schemas.