Lumiverse

Lumiverse 0.9.0 — Gearing Up for 1.0!

April 16, 2026
lumiverseupdates

Lumiverse 0.9 — 2026-04-16

Everything between main (0.7.6) and staging (0.9). 150 commits, rolled into one document because the in-between releases were already covered at lucid.cards/posts/lumiverse-0-8-0 and lumiverse-0-8-5. This is the consolidated view.

Breaking

  • Runner now requires Bun ≥ 1.3.3. Older versions were silently producing the wrong spawn behavior on Linux and Termux. The runner refuses to start otherwise.
  • Embedding configuration is owner-gated on multi-user installs. LanceDB stores all embeddings in one shared table whose vector dimension is locked at table creation. If the server owner enables embeddingConfig, every other user inherits it (config + API key) and can no longer set their own. Toggling the gate or changing the owner's fingerprint nukes vectors for every user — by design, so the shared table can be rebuilt at the new dimension.
  • Queue-message keybind moved to Ctrl+Enter / Ctrl+LClick. Plain Enter was being intercepted by the newline combo and the "press enter to send" setting. Hold-modifier semantics fix it.
  • Username normalization with retroactive backfill. BetterAuth was accepting usernames that broke account lookup. Setup wizard input is now sanitized; existing accounts get normalized in migration 054.
  • Regex script ownership. Migrations 049, 057, 059 add id, pack_id, and preset_id columns. Regex scripts imported as part of a preset or pack are now linked to that owner; deleting the parent cascades. If you were relying on regex scripts surviving preset deletion, they don't anymore.

Memory Cortex

The headline of 0.7.7. Entity graph, salience scoring, relationship extraction, and contextual retrieval per chat. Migrations 038–048, plus 050 (vaults) and 052 (perf indexes).

  • Entity extractor uses a sidecar LLM with a strict tool schema. Discovered nicknames are registered as aliases on the canonical entity, so "call me Mel" maps back to Melina on the next turn. Five-stage canonical resolution: direct ID → exact name → alias → normalized fuzzy → diminutive prefix (≥60% match, character entities only).
  • Salience scoring split into a heuristic pass (cheap, in-process) and a sidecar pass (expensive, configurable timeout). Both can run; the heuristic gates whether the sidecar fires.
  • Relationship extraction runs after entity extraction with a separate prompt. Self-referencing relations are filtered post-hoc.
  • Consolidation, GC, font-attribution, emotional context, NP chunker, shadow formatter — all live under src/services/memory-cortex/. Tests included for font attribution and NP chunking.
  • Vaults: frozen snapshots of a chat's cortex state, attachable to other chats. Read-only.
  • Interlinks: live bidirectional connections between two chats' cortex data. Optional bidirectional flag creates two link rows.
  • Diagnostics UI in settings exposes the full retrieval trace, vector shortlist, and probe connectivity.
  • Cortex processing moved fully off the main generation thread. Two stabs at the decoupling — the second one stuck.
  • Operator config preset modes: simple, standard, advanced. Tunes thresholds without exposing the full surface.

Dream Weaver

Character creation studio. Migration 048 (dream_weaver_sessions).

  • Soul, World, Visuals tabs. Soul writes character identity fields; World handles scenario and lorebook scaffolding; Visuals drives portrait generation through an attached image-gen connection.
  • Visual Studio: provider-aware param renderer, ComfyUI workflow graph editor with mapped fields, source settings ribbon, voice guidance editor, additive generation for individual fields.
  • Sidecar prompts in src/services/dream-weaver/prompts.ts. Saved prompts API (/saved-prompts) lets users keep templates between sessions.
  • Portrait reference handling: stage component, asset hint row, prompt resolution that respects character fields when generating.
  • ComfyUI workflow patching, storage, field-options resolution all under src/services/dream-weaver/visual-studio/.

Databank

Document knowledge banks with chunking and vector retrieval. Migration 055.

  • Three scopes: global, character-bound, chat-bound. Cross-references via character.extensions.databank_ids, chat.metadata.chat_databank_ids, and the globalDatabanks setting. Mirrors the world-books attachment pattern.
  • Supported: .txt, .md, .csv, .json, .xml, .html, .yaml, .log, .rst, .rtf, max 10MB.
  • Web scraper with wiki/standard auto-detection. MediaWiki API for Wikipedia/Fandom; Mozilla Readability + JSDOM for everything else. SSRF-protected via safeFetch.
  • #mention autocomplete and resolution. Tags get stripped from all user messages in context, content appended to the last user message as # Additional Context.
  • Chat input file picker accepts documents alongside images/audio. Documents auto-route to a chat-scoped databank (auto-created, named after the character). Images and audio remain inline one-shot attachments.
  • Macros: {{databank}}, {{databankRaw}}, {{databankActive}}, {{databankCount}}.

MCP Servers

Connect to external MCP tool servers. Migration 053.

  • Three transports: streamable_http (modern), sse (legacy HTTP+SSE), stdio (subprocess).
  • HTTP headers and stdio env stored encrypted in secrets. SSRF-blocked unless ALLOW_MCP_PRIVATE_NETWORKS=true.
  • Discovered tools registered as council tools with namespaced names (mcp:{serverIdPrefix8}:{toolName}), lowest priority below extension/DLC/built-in.
  • Auto-connect on startup for is_enabled=1 AND auto_connect=1. Graceful shutdown disconnects all clients.
  • Status exposed via GET /mcp-servers/:id/status and GET /mcp-servers/status (all servers for user).

TTS / STT

Migration 051 for TTS connections.

  • TTS providers: openai_tts, elevenlabs, kokoro. Same CRUD shape as image-gen connections — list providers, list models, list voices, test, manage API key, duplicate.
  • Synthesis endpoints: /tts/synthesize (binary), /tts/synthesize/stream (chunked), /tts/detect-segments (classifies roleplay text by delimiter — *asterisks* → narration, "quotes" → speech).
  • Speech detection config is configurable per-character via the segments endpoint.
  • STT proxies audio to OpenAI's transcription endpoint, reusing an existing LLM connection's API key. No separate credential surface.
  • Auto-playback for fresh assistant messages (with the silent-MP3 unlock trick for browser autoplay policies). Manual playback button on every message. HTML stripped before synthesis.

Operator Panel

Owner-only server management UI. Routes under /operator/.

  • IPC architecture: runner spawns server with Bun.spawn({ ipc }). Server detects LUMIVERSE_RUNNER_IPC=1 and routes git/restart operations through the parent process. UUID-correlated request/response with mutex-protected critical sections.
  • Status, logs (buffered + WS-streamed), database stats, update check/apply, branch switch, remote-mode toggle, restart, shutdown, cache clear, rebuild, deps install.
  • Real-time log subscription via POST /operator/logs/subscribe + WebSocket.
  • Database maintenance exposed through the panel: optimize, analyze, vacuum, refresh tuning, WAL checkpoint. Vacuum requests are rejected when filesystem headroom is insufficient for a safe rewrite.

Database & Infrastructure

  • Adaptive SQLite tuning at startup: cache_size and mmap_size sized against host RAM, configurable via the databaseTuning setting (cacheMemoryPercent, mmapSizeBytes). Windows keeps mmap disabled.
  • Periodic maintenance scheduler with operator-configurable intervals (databaseMaintenance setting). Vacuum only runs when the interval, hidden/idle timer, reclaim thresholds, and active-generation/visibility gates are all satisfied.
  • Hourly stats probe logs DB growth.
  • LanceDB compaction fix and indexing strategy switch. Big speedup on retrieval.
  • Generation pool service (src/services/generation-pool.service.ts) caches token state for 5 minutes. GET /generate/status/:chatId returns pooled content for mid-stream recovery on WS reconnect. Token events carry seq for dedup.
  • Compress middleware and rate-limit middleware added.
  • Homebrew UUIDv7 generator replaces the previous UUIDv4 calls in hot paths.

File Connections

Used by the SillyTavern migrator to pull data from remote storage.

  • Providers: local, sftp, smb, google-drive, dropbox. Each implements the same interface in src/file-connections/providers/.
  • Remote-fetch cap on bytes per request (remote-fetch-cap.ts).
  • OAuth flows for Google Drive and Dropbox via /google-drive and /dropbox route files.

Image Generation

  • New providers: comfyui (with discovery, import, workflow parser), swarmui, pollinations. pollinations-text provider also added on the LLM side. BYOP support for Pollinations.
  • ComfyUI workflow graph editing surface in the frontend (Dream Weaver Visual Studio).
  • SwarmUI: resolution parameter passthrough fixed; steps parameter actually applies now.
  • Background image-gen handling and interrupt fixed.

OpenRouter First-Party

Routes under /openrouter/. Service in src/services/openrouter.service.ts.

  • PKCE OAuth flow. Server stores code_verifier in-memory (5min TTL). Frontend pops a window, OpenRouter redirects to /api/v1/openrouter/oauth-landing (unauthenticated), popup writes the code to sessionStorage, parent exchanges via POST /openrouter/auth/callback. Key lands in encrypted secrets as the connection's API key.
  • Provider routing config (order, allow_fallbacks, require_parameters, data_collection, ignore, only, quantizations, sort) injected as provider on the request body.
  • Plugins (web, response-healing, context-compression) injected as plugins[].
  • Credit balance, generation stats, rich model metadata (pricing, context length, supported parameters) — all proxied with a 5-minute in-memory cache.
  • App attribution headers (HTTP-Referer, X-Title, X-OpenRouter-Categories) on every request.

Vertex AI

Three rounds of fixes before this stuck. JWT signing, region mapping, endpoint URL — all corrected. Vertex now handles the same cases the standard google provider does, including embeddings (separate google_vertex embeddings provider added).

Default safety settings inject BLOCK_NONE for all five harm categories on google and google_vertex unless the user provides custom safetySettings. The frontend has stopped silently filtering responses.

Generation Pipeline

  • Streaming toggle in generation settings. Some providers don't stream cleanly; this lets users opt out per-connection.
  • Generation recovery on reconnect. The token pool (above) lets the frontend resume mid-stream after a dropped WS.
  • Council error recovery. When some tools succeed and others fail, the server emits COUNCIL_TOOLS_FAILED and pauses for up to 60s. Frontend modal: "Retry Failed" or "Continue Anyway". Retry re-runs only the failed tools (executeCouncil with retryToolNames filter, dice rolls skipped) and re-formats deliberation from the full merged set.
  • Council retain-results-for-regens. toolsSettings.retainResultsForRegens skips tool execution on regenerate/swipe and reuses the last successful results from chat.metadata.last_council_results.
  • True streaming tool calls in Cortex mode.
  • Reasoning: streaming CoT detection re-enters reasoning mode when tags appear mid-response, not just at the start. Post-parse safety net extracts any leftover tags from content before saving. Provider mapping refreshed for Anthropic (thinking), Google (thinkingConfig), OpenRouter (reasoning: { effort }), and toggle-only for Moonshot/Z.AI.
  • Loom summarization prompt customization. Settings summarization.systemPromptOverride and summarization.userPromptOverride accept user-edited templates with full token substitution. Defaults exposed via GET /generate/summarize/prompt-defaults.
  • Sidecar tier-2 calls now wired to AbortControllers — they actually cancel.
  • Top-K added to generation settings.
  • Provider list grew to 20: openai, anthropic, google, google_vertex, openrouter, deepseek, chutes, nanogpt, zai, moonshot, mistral, ai21, perplexity, groq, xai, electronhub, fireworks, pollinations, siliconflow, custom.

Prompt Assembly

  • Atomic chat metadata merge. PATCH /chats/:id/metadata and the chatsSvc.mergeChatMetadata() helper re-read the row inside the call so concurrent writers (post-generation expression detection, council result caching, deferred WI/chat-var persistence) can't clobber each other's keys.
  • Chat-scoped variables (@ prefix). {{@hp = 100}}, {{@hp -= 15}}, {{@turn++}}. Persisted to chat.metadata.chat_variables after generation. Mutation macros set a dirty flag; the generate service merges into the deferred metadata write.
  • Persona pronouns: explicit subjective_pronoun, objective_pronoun, possessive_pronoun fields on personas. JanitorAI-compatible aliases {{sub}}, {{obj}}, {{poss}} plus the explicit forms.
  • Persona add-ons. persona.metadata.addons[] — toggleable content blocks appended to {{persona}}. Global add-ons API (/global-addons) for add-ons not bound to a single persona. Migration 056.
  • Linked preset profiles. PUT /chat/:chatId with { preset_id, linked_to_defaults: true } delegates resolution to the current defaults instead of snapshotting block states.
  • Multi-character expression mapping for CharX imports. When ≥3 first-underscore-split prefixes share matching suffix counts, expressions stored as character.extensions.expression_groups: Record<characterName, Record<cleanLabel, imageId>>. Two-stage detection at runtime: heuristic name scan → cheap LLM steering call → scoped expression detection against only that character's labels.
  • Aho-Corasick keyword matching for lorebook activation. Replaces the old per-entry scan.
  • World-info smart de-dupe. Catches near-duplicate entries that bad lorebooks were firing in parallel.
  • Author's Note moved to atomic metadata writes.
  • Macro additions: chat-utils, cortex, databank, formatting, logic, math, regex-ref, strings. Macros tests under src/macros/macros.test.ts (1088 lines).
  • ST-compatibility: dot-prefix resolution for core macros. Boolean if-check resolution fix. Truthiness fix for string comparators in if.

Spindle (Extension API)

  • Bulk update: POST /spindle/update-all schedules git-pull + rebuild for every extension the caller can manage. Owner/admin gets all; regular users get their own user-scoped installs. Returns 202 with { started: true, total }. Sequential background execution. Process-wide mutex prevents overlap (re-entry returns 409). Disabled extensions are updated but stay disabled. Per-extension failures collected into errors[]. Progress streams via SPINDLE_BULK_UPDATE_PROGRESS; completion via SPINDLE_BULK_UPDATE_COMPLETE.
  • spawnAsync: git-pull, bun install, bun build no longer block the JS event loop. Single-extension POST /spindle/:id/update benefits from the same migration.
  • Theme APIs: spindle.theme.apply() (raw CSS var overrides, mode-aware), applyPalette() (palette-driven theming that preserves Lumiverse-owned alpha/glass/shadow presentation), extractColors(), generateVariables() (full theme variable map). Full theme-sized payloads replace prior scope overrides to avoid stale tokens.
  • Commands API: spindle.commands.register() / unregister() / onInvoked(). Custom commands appear in the command palette (Cmd/Ctrl+K).
  • Version API: spindle.version.getBackend() / getFrontend(). Reads cached semver from each package.json.
  • Chat mutation API: spindle.chat.getMessages(), appendMessage(), updateMessage(), deleteMessage(), setMessageHidden(), setMessagesHidden() (≤500 ids/call), isMessageHidden(). Hidden flag excludes from chat memory embeddings only; messages remain visible to prompt assembly.
  • Swipe DTOs: getMessage() exposes the swipe array. Action-based emission on MESSAGE_SWIPED (added, updated, deleted, navigated) with swipeId and previousSwipeId.
  • World book DTOs: full CRUD on books and entries plus getActivated().
  • Character DTO: surfaces world_book_ids from the internal extensions blob. Writes via update({ world_book_ids }) replace the attached set, sanitized for non-string/duplicate IDs.
  • Generation progress DTOs: streaming progress visible to extensions.
  • Interceptor parameter injection: interceptors with the generation_parameters permission can return { messages, parameters? }. Parameters merge into the outgoing LLM request: assembledParams < interceptorParameters < inputParameters. Without the permission, returned params are silently stripped.
  • Confirm modal: SPINDLE_CONFIRM_RESULT wired from WebSocket to the event bus.
  • User-scoping: event emission to extensions properly scoped per-user.

UI

  • Bubble + Minimal chat styles rebuilt with the same meta-pill features. Token counter on messages (optional display). Generation stats on hover (TTFT, tokens/sec, etc.).
  • Swipe controls in chat view for desktop and mobile. Long-press unified across mobile and desktop via synthetic contextmenu dispatch.
  • Chat heads dismiss gracefully when re-entering chat. Race condition with deleted chats persisting fixed. Embedding phase now counts as assembly for the chat heads.
  • Floating avatar viewer: click avatar to pop out. Resizable on mobile. Touch events no longer bleed through the underlying input.
  • Custom CSS modal for theming overrides.
  • UI scaling controls.
  • Settings drawers centrally registered and added to the command palette.
  • Generation parameter sliders normalized for touch.
  • Queued user messages system. Send while generating; queue dispatches after.
  • Input bar: HTML rendering fixes for non-styled divs in message contents.
  • Mobile: dock panel fix, multi-select alignment fix on iPhones, popover constraint fix for world-book selectors so they fit the parent.
  • PWA: manifest fix for Chrome Android, multiple iOS PWA tab-scrolling fixes, scroll-to-interrupt for bubble pinning.

Frontend Tooling

  • Virtualized + lazy-loaded chat messages in dry-run view. Long chats no longer choke the prompt breakdown.
  • Lazy presentation above the input bar for the last message.
  • Code block copy works at every call site now.
  • Streaming indicator fixed.

Provider / Connection Surface

  • Connection cards UI revamp.
  • Embedding model URLs auto-fill the necessary connection details.
  • Cortex model can override the connection default (settings reassignment was being ignored).
  • Ollama compatibility layer for users who insist on Ollama. Stop using Ollama.

Migrations

038–048 cortex, 048 (dream weaver sessions), 049 (regex script id), 050 (cortex vaults), 051 (TTS connections), 052 (cortex perf indexes), 053 (mcp servers), 054 (normalize usernames), 055 (databank), 056 (global addons), 056 (saved prompts), 057 (regex script pack_id), 058 (persona pronouns), 059 (regex script preset_id).

Notable Fixes

  • Stream errors no longer delete the entire message if content is present.
  • Abort requests now bubble up to provider request layer.
  • Risu card image display fixed (asset map + <img="AssetName"> resolution).
  • JPEG+ZIP polyglot import for RisuAI cards (JPEG avatar prepended to ZIP archive). Detected via findJpegZipBoundary(). JPEG portion used as fallback avatar.
  • CHARX module support: lumiverse_modules.json for lossless round-trips of expressions, alternate fields/avatars, world books.
  • Character book firing in pipeline fixed.
  • Character book add/remove no longer leaves stale references.
  • Alternate fields trigger correctly.
  • Reasoning timer stops desyncing when user leaves chat.
  • TTFT and generation speed stats calculation corrected.
  • Greeting messages no longer show swipe controls.
  • Defense-in-depth on aborted generations.
  • WI smart de-dupe.
  • Macro if boolean and string comparator fixes.
  • PHI block insertion when block isn't present but content is in card.
  • Persona pronouns display in editor.
  • Tokenization speed regression fix.
  • LanceDB reindex status reflected in UI.
  • ID-to-UUID assignment bug fixed.
  • Regex application to chat history fixed.
  • Mobile expanded editor modal fixes.
  • ST migration WS messaging timing fixes.
  • ST JSONL chat file imports fixed.
  • ST preset export data matching.
  • Race condition on display preference set loading after server shutdown fixed.
  • World book recursion options were wired backwards.
  • Server now starts even if LumiHub is down.
  • Docker CA certificates bundle renewal.
  • lru-cache pinned to a version without the Windows TLA regression.
  • Frontend messaging scope bug.
  • Floating widget context menu ownership for Spindle (cross-wired contexts fixed by state tracking).
  • Auto-playback for fresh generations (twice; second one stuck).
  • Council deliberation re-formats from full merged set on retry.
  • Performance regression rendering long-running chats.

Misc

  • LICENSE updated.
  • User and developer docs added under user-docs/ and developer-docs/. Macros reference, prompt block execution order, sovereign hand, preset profiles, glossary, troubleshooting, world books, personas, presets, settings, packs.

If you're upgrading from 0.7.6 directly: read the Breaking section before you run migrations. Everything else can wait until you hit it.