Architecture Overview
Dionysys is organized around one public path through the system:
app UI
-> @dionysys/client
-> /api/dionysys/*
-> @dionysys/server
-> storage adapter + decision connector
-> @dionysys/core contracts and logic
Package graph
@dionysys/core
^-- @dionysys/client
^-- @dionysys/react
^-- @dionysys/server
^-- @dionysys/storage-mongodb
^-- @dionysys/connector-openai
^-- @dionysys/connector-gemini
^-- @dionysys/connector-anthropic
(also: mockConnector, customHttpConnector — built into @dionysys/server)
Package roles
@dionysys/core
Framework-neutral contracts and adaptive logic:
- Event, session, decision, and admin schemas (Zod)
- Deterministic inference and policy logic
- MCP resource schemas and decision-support contracts
- Shared validation and contract boundaries
- Re-exports
zfromzodfor downstream consumers
@dionysys/server
Self-hosted backend SDK:
- Mounts the primary
/api/dionysys/*routes (sessions, events, decisions, feedback, admin) - Coordinates session, event, decision, feedback, and admin services
- Depends on a storage implementation and a decision connector
- Includes built-in
mockConnectorandcustomHttpConnector
@dionysys/client
Framework-agnostic API client:
- Session CRUD and current-session persistence
- Buffered event tracking with explicit flush
- Decision resolution
- Feedback submission and passive evaluation
- Admin config and overview access
@dionysys/react
React-facing runtime:
AdaptiveProvider— wraps the app and drives adaptive stateuseAdaptiveUI— reads current variant, UI state, and pending decisionsAdaptiveFeedback— connected feedback widgetAdminConsole— runtime config and session overview UI
The preferred React integration is client={dionysysClient}.
@dionysys/storage-mongodb
MongoDB-backed implementation of the server storage contract.
@dionysys/connector-openai
OpenAI-backed implementation of the decision connector contract.
@dionysys/connector-gemini
Gemini-backed implementation of the decision connector contract.
@dionysys/connector-anthropic
Anthropic-backed implementation of the decision connector contract.
Request flow
1. Session bootstrap
The app creates or restores a current session through @dionysys/client.
2. Event collection
App code translates local interaction events into DionysysEvent envelopes and sends them through client.events.track(...).
3. Decision resolution
The client calls:
POST /api/dionysys/decisions:resolve
The server reads recent events, computes the deterministic context, always consults the configured connector, and resolves the decision through a confidence gate:
- Strong signal (enough modality events and a clear score margin) — deterministic rules decide; the connector's answer is honored only when it agrees with the locked modality and clears
minConfidence. - Weak / ambiguous signal — the connector's choice is blended with a per-context Thompson-sampling bandit. Each candidate modality scores
(1 - wBandit)·llmConfidence + wBandit·thompsonSample, wherewBandit = n / (n + banditEvidenceK). With no bandit history the blend reduces to the model's free choice; as evidence accrues the bandit dominates. A quiet arm is discounted toward its prior on read (γ^(days idle), in memory only) so a context that has gone stale re-opens to exploration.
Invalid or low-confidence output falls back to a configured safe action. The stored decision carries metadata.signalStrength, metadata.resolvedBy (deterministic | blended | fallback), and metadata.blend for observability. Feedback then updates the (stateId, modality) bandit arm — discounting it toward its prior first (discounted Thompson sampling) so old evidence fades — so later weak-signal decisions in the same context shift toward what worked — see Feedback Loop. The learned arms are inspectable and maintainable (posterior mean, credible interval, P(best), decay, snapshot/reset) through the admin console's Bandit tab and the GET/POST /api/dionysys/admin/bandit* routes. The gate, bandit, and decay are tunable via mcp.gate / mcp.bandit in Configuration.
4. React application
AdaptiveProvider stores the active and pending adaptive state and exposes it through useAdaptiveUI().
5. Feedback and admin
Feedback and admin operations use the same /api/dionysys/* route family rather than separate ad hoc endpoints.
OpenAPI document
The full REST API surface is described in docs/openapi/dionysys-api.yaml.
To regenerate after schema or route changes:
npm run openapi:build --workspace=packages/server
The generated YAML is checked in and deterministic — running the command twice on a clean tree produces no git diff. Hand-edits to the file are not allowed; corrections go in the source schemas or route registrations.
Excalidraw as reference app
The Excalidraw demo is intentionally app-specific at the edges:
- It translates Excalidraw events in frontend-only adapter code
- It keeps demo UX decisions in app code
- It serves as the living example of the public SDK APIs
That split is important. Public packages stay generic; demo behavior stays local.