Skip to content
Fusion

Sandbox

The sandbox is a gallery of small, self-contained pages at /sandbox/<name> — one per capability — that each exercise a single package or AI feature in isolation. It's where you see a piece of the stack actually run before wiring it into a real feature, and where you confirm a backing service is configured.

It is deliberately separate from the product app. The sandbox lives outside the _authed shell: no sidebar, no product nav — its own minimal chrome (a brand link back to the hub, a "PulsN ↗" escape link to the app, and the language / theme / AI-provider toggles). It still requires a session (the layout redirects to /login), and every server call re-checks auth. You reach it by URL, not from the app menu.

Graceful degradation is the point

Most sandboxes talk to an external service (Valkey, Centrifugo, an LLM, …). None of them require it to load. The recurring pattern: a server function calls the package's is<Thing>Enabled() and returns a discriminated union — { enabled: false } or { enabled: true, … }. The page then shows either a green "on" badge with live data, or an amber alert naming the exact env var to set.

Loading diagram...

So you can run the whole sandbox area with nothing but Postgres, and switch each capability on by adding one variable. (This mirrors the package graceful-degradation contract.)

Switching the AI provider

The shell carries a provider toggle (a segmented control) that writes an ai_provider cookie — openrouter (hosted, default) or ollama (local). fusion-ai reads that cookie per request, so every AI sandbox switches backend with no reload. See AI.

Package sandboxes

One per package. Those with no "Needs" run with zero setup (just Postgres).

SandboxDemonstratesNeeds
/sandbox/cacheset a key in Valkey, read it back, show the value + remaining TTLVALKEY_URL
/sandbox/metricsfetch the live Prometheus exposition document from the in-process registryMETRICS_ENABLED=1
/sandbox/jobsthe always-safe enqueue seam (the heavy Hatchet client stays lazy)HATCHET_CLIENT_TOKEN
/sandbox/realtimemint a Centrifugo connection token, connect a WebSocket, see publicationsCENTRIFUGO_*
/sandbox/collaba collaborative editor on a shared Yjs doc (local-only without a server)COLLAB_WS_URL (optional)
/sandbox/edge-ssoresolve an SSO identity across authenticated / spoofed / anonymous headers
/sandbox/ldapfilter builder, DN→CN, AD-group→project sync diff, in-memory search
/sandbox/import-exportlive CSV import plan (new / update / skip / error), preview, download
/sandbox/gisa MapLibre map of Swedish cities; click → WGS84 → SWEREF 99 coordinates
/sandbox/settingsedit runtime app config (name, language, sign-ups, …) stored in app_config
/sandbox/auditrecord a change-history row and see the audit feed, newest first
/sandbox/mailertrigger an email recorded to the mailbox outbox (real delivery optional)SMTP_HOST (optional)

The last three are backed by fusion-db foundation tables (app_config, audit_log, mailbox), so they need only Postgres — no external service to switch on.

AI-feature sandboxes

Each demos one @tanstack/ai capability through fusion-ai, using the production fusion-ui chat components. All need an AI provider configured (OPENROUTER_API_KEY or OLLAMA_BASE_URL).

SandboxDemonstratesFeature
/sandbox/aione-shot prompt → answer (PromptInput + AiResponse)generateText
/sandbox/streamingtoken-by-token chatstreamChat + useChat / SSE
/sandbox/toolsa tool-calling agent loop (roll_dice, get_current_time)server tools + maxIterations
/sandbox/reasoninga reasoning model streaming its "thinking" separately from the answerreasoning model + collapsible
/sandbox/persistencea chat thread that survives reload (localStorage)Chat threadId + persistence
/sandbox/generative-uia tool call renders a live bar chart inline instead of a tool linecustom renderToolPart
/sandbox/assistanta floating assistant whose client tool flips the app's themeclient tool + ChatWidget

The AI sandboxes call API route handlers under src/routes/api/sandbox/ that delegate to fusion-ai's streamChat — see AI for that side.

The proactive-agent sandbox

/sandbox/agent is the operator console for the proactive agent: run a tick on demand, watch the run state and the findings it proposes, see what's delivered vs. suppressed, toggle the global kill switch, and check per-user consent. It runs with a deterministic demo model when no AI provider is set (so it works with zero config), and produces real findings once a provider is configured. The agent's conversational side is the chat-first home.

SSR safety

Some packages are browser-only (ProseKit/Yjs in collab, MapLibre in gis, centrifuge in realtime). Those components are loaded with lazy() and rendered only after mount, or imported dynamically inside the click handler — so a browser-only dependency never reaches the server render.

Adding a sandbox

Add one entry to the sandboxes array in src/routes/sandbox.index.tsx (kept inside the component so its labels follow the active locale) and a matching src/routes/sandbox.<name>.tsx route. Follow the is<X>Enabled() → badge-or-alert pattern so it degrades like the rest.