Lumiverse

Lumiverse 1.0 on Main — We finally made it.

May 22, 2026
Updated May 22, 2026
lumiverseupdates

~650 commits between 0.7.6 on main and now. Thanks to one of our dear Illiterates, main appeared to be 0.9.0 in the diag panel, instead. If you're upgrading from main directly, read Breaking before you run migrations. Everything else can wait until you hit it. If you were already on staging, you can stay on staging.

Join our Discord here, and help shape the future of Lumiverse.

Breaking

  • Runner requires Bun ≥ 1.3.3. Older versions silently misbehaved 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 creation. If the 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 table can be rebuilt at the new dimension.
  • Queue-message keybind moved to Ctrl+Enter / Ctrl+LClick. Plain Enter collided with the newline combo and the "press enter to send" setting.
  • Username normalization with retroactive backfill. Migration 054 normalizes existing accounts. BetterAuth was accepting usernames that broke account lookup.
  • Regex script ownership. Migrations 049, 057, 059 add id, pack_id, and preset_id. Regex scripts imported as part of a preset or pack are linked to that owner and cascade on deletion. If you were relying on regex scripts surviving preset deletion, they don't.
  • Spindle extensions run sandboxed. Per-process isolation, frozen native primitives, capability-gated APIs. Extensions that imported dangerous modules directly will fail to load. This is intentional.

Memory Cortex

Hybrid memory: entity graph, salience scoring, relationship extraction, 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 register 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 (configurable timeout). The heuristic gates whether the sidecar fires.
  • Relationship extraction runs after entity extraction with a separate prompt. Self-referencing relations filtered post-hoc.
  • Consolidation, GC, font-attribution, emotional context, NP chunker, shadow formatter — all under src/services/memory-cortex/. Tests 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.
  • Cortex processing fully off the main generation thread. Took two stabs at the decoupling. The second one stuck.
  • Operator config preset modes: simple, standard, advanced.
  • Diagnostics UI exposes the full retrieval trace, vector shortlist, and probe connectivity.
  • Entities and relationships can be modified by the user. Edited entries will be marked and avoid clobbering by the sidecar LLM arbitrator. Font colors can be remapped if the arbitrator got the association wrong or undefined.
  • Late in the cycle: bulk entity delete, sidecar arbiter for heuristics processing, retry configuration for Cortex, per-provider RPM gating on sidecar calls, cooldown and telemetry for staleness, salience records resilient to message editing and entity removal. Macros now resolve inside chunk content and the memory query before vectorization. Chat switching no longer kills warmed salience records. Bulk rebuild sanitization strengthened.

Dream Weaver 2.0

Character creation studio. Soul, World, Visuals. Migration 048 (dream_weaver_sessions).

  • 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 per field. Workflow patching, storage, field-options resolution under src/services/dream-weaver/visual-studio/.
  • Sidecar prompts in src/services/dream-weaver/prompts.ts. Saved prompts API (/saved-prompts) keeps templates between sessions.
  • Portrait reference handling: stage component, asset hint row, prompt resolution that respects character fields when generating.
  • Scenario card generation re-integrated. Persona visible to the LLM in both modes.
  • ComfyUI parameters unified across Dream Weaver and core image generation.

The 2.0 rebuild took two structural rewrites before it stuck. Sounds about right.

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. 10MB max.
  • 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 strip from user messages in context; content appends 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.
  • Macros: {{databank}}, {{databankRaw}}, {{databankActive}}, {{databankCount}}.
  • Folder organization, document editing/viewing, databank fusing. Combined embedding calls for documents during prompt assembly. Document label highlighting (group-chat-mention style).

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 register 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 via GET /mcp-servers/:id/status and GET /mcp-servers/status.

TTS / STT

Migration 051.

  • TTS providers: openai_tts, elevenlabs, kokoro. Same CRUD shape as image-gen connections — providers, models, voices, test, key, duplicate.
  • Synthesis endpoints: /tts/synthesize (binary), /tts/synthesize/stream (chunked), /tts/detect-segments (classifies roleplay text by delimiter — *asterisks* → narration, "quotes" → speech).
  • STT proxies audio to OpenAI's transcription endpoint, reusing an existing LLM connection's API key. No separate credential surface.
  • Group-chat multi-speaker. Character voice selection. Separate narrator + character speech. Narrator speed slider. Per-character speech detection.
  • Auto-playback for fresh assistant messages (silent-MP3 unlock to satisfy autoplay policy). Manual playback on every message. HTML stripped before synthesis.
  • Visual waveform + amplitude bar during recording. ISO country stamps for Whisper. Improved command detection and continuous-mode normalization.

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 through the parent. 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: optimize, analyze, vacuum, refresh tuning, WAL checkpoint. Vacuum requests are rejected when filesystem headroom is insufficient for a safe rewrite.
  • Trusted host and origin config in the panel. SFTP gated behind explicit enablement. Sharp config exposed.

Spindle Extensions

Extensions now run sandboxed per-process with capability-gated APIs. The surface grew accordingly.

  • Sandboxing: per-process isolation, frozen native primitives, env proxy mask, subprocess isolation, safe React proxy and factory for custom themes, dangerous-module imports blocked. Effective permissions grant for shared RPC pool. Host-side fixes for confused-deputy concerns with the shared bridge.
  • 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-sized payloads replace prior scope overrides to avoid stale tokens.
  • Commands API: register(), unregister(), onInvoked(). Custom commands appear in the command palette (Cmd/Ctrl+K).
  • Chat mutation API: getMessages(), appendMessage(), updateMessage(), deleteMessage(), setMessageHidden(), setMessagesHidden() (≤500 ids/call), isMessageHidden(). Hidden flag excludes from chat memory embeddings only; messages remain visible to prompt assembly. New: insert-and-generate, swipe-edit handler.
  • Swipe DTOs: 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(). WORLD_BOOK_CHANGED/DELETED and WORLD_BOOK_ENTRY_CHANGED/DELETED events on mutation.
  • Regex script DTOs: full CRUD + REGEX_SCRIPT events.
  • Preset CRUD for Spindle extensions.
  • Databank API: surface for managing chat-scoped knowledge.
  • Native tool calling: inline function calling for extension tools, independent of Council.
  • Interceptor parameter injection: interceptors with the generation_parameters permission can return { messages, parameters? }. Merge order: assembledParams < interceptorParameters < inputParameters. Without permission, returned params are silently stripped.
  • Macro interceptor hook, message content processor hook with render-mcp origin and /display-preprocess endpoint, world info interceptor.
  • Per-call dynamic_macros pass-through for display-regex + interceptor env. Role info threaded through.
  • Bulk update: POST /spindle/update-all schedules git-pull + rebuild for every extension the caller can manage. 202 + { started: true, total }. Sequential, process-wide mutex (re-entry returns 409). Disabled extensions update but stay disabled. Per-extension failures collected. Progress streams via SPINDLE_BULK_UPDATE_PROGRESS/COMPLETE.
  • spawnAsync: git-pull, bun install, bun build no longer block the event loop.
  • fetchFont sandbox API for web font loading.
  • Image upload: images.uploadMany batch API. Deferred sharp + thumbnail generation in batch uploads. Batch INSERT in transaction.
  • WS frame limit bumped to 1MB default.
  • App-overlay mountApp position: in-app chrome occludes extension overlays.
  • Confirm modal: SPINDLE_CONFIRM_RESULT wired from WS to event bus.
  • User-scoped event emission. Streaming support. CHAT_SWITCHED event split out of SETTINGS_UPDATED.
  • Council DTOs: item and config DTOs, generationType on GENERATION_STARTED/ENDED.
  • Version API: spindle.version.getBackend() / getFrontend() reads cached semver from each package.json.
  • Tokenizer API: surface for message tokenization.
  • Storage shapes fixed for userStorage and storage across the API. Regex input macro resolution fixed.

HTML Islands

The streamed-content + sandboxed-DOM surface that's been the source of more bugs and bones-thrown than anything else this cycle.

  • Island walker tracks depth across multi-line opening tags.
  • Markdown is not reparsed inside widget elements. Text inside button/headings/select/etc. uses parseInline so widget labels don't get reparsed as block markdown.
  • data-no-island opt-out and class-based opt-out for ISLAND_BASE_CSS.
  • Style tag pairing with trailing <style> blocks. Full-document islands with leading doctype or head captured properly.
  • Streamed-content fault-tolerance: lax sanitation when alignment slips mid-stream.
  • IMG element identity preserved across content re-renders.
  • Spindle widget audio retrieval and playback supported under sandbox.
  • Transparent CORS proxy for sandboxed widgets via safeFetch.
  • Copy button in HTML islands within messages fixed.
  • JS-Slash-Runner cards script explicitly blocked. Then blocked again. Then blocked once more for good measure. All JS-Slash-Runner dreams are now dead, yippee.

Image Generation

  • New providers: comfyui (with discovery, import, workflow parser), swarmui, pollinations, BananaBread, Infermatic/TotalGPT. pollinations-text on the LLM side. BYOP for Pollinations. Nano-GPT specific routing and cache options.
  • ComfyUI workflow graph editing in the frontend (Dream Weaver Visual Studio). Comfy workflows now supported in SwarmUI passthrough.
  • SwarmUI: resolution parameter passthrough fixed; steps parameter actually applies.
  • Character-bound LoRAs through ComfyUI and SwarmUI. Bound via the character editor modal based on the active image-gen connection.
  • Comfy seed of -1 converts to UInt32 at gen time. -1 blocked from being sent to any other provider.
  • Generation prompt preview. Generated image to gallery. Custom prompt add-ins and presets bound to persona, character, and main. Auto-add background generations to character gallery.
  • Background image-gen interrupt fixed. Abort calls interrupt endpoints for Comfy and Swarm. API key auth for gated endpoints. WS error helpers.
  • Workflow custom field mapping fixed. Image-gen timeout exposed and adjustable. Sidecar and image gen wrapped in separate timeouts.
  • Image gens no longer recycle into context by default.
  • Bulk NPC and world book tools.

Generation Pipeline

  • Token pool caches mid-stream state for 5 minutes. GET /generate/status/:chatId returns pooled content for mid-stream recovery on WS reconnect. Token events carry seq for dedup.
  • 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 (dice rolls skipped, enrichment reused) 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. Now correctly retains when a tool destroys and recreates results within the same step.
  • 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 leftover tags from content before saving. Provider mapping refreshed for Anthropic (thinking), Google (thinkingConfig), OpenRouter (reasoning: { effort }), toggle-only for Moonshot/Z.AI. Auto-normalization when switching to a model that doesn't support that level. DeepSeek thinking parameters wired.
  • Loom summarization prompt customization. summarization.systemPromptOverride and summarization.userPromptOverride accept user-edited templates with full token substitution. Defaults exposed via GET /generate/summarize/prompt-defaults. Backgrounded summary generation. Summary timeout configuration.
  • Sidecar tier-2 calls wired to AbortControllers. They actually cancel now.
  • Streaming toggle per-connection for providers that don't stream cleanly.
  • Top-K added. Top-K toggle for OpenAI/OAI-compatible.
  • Generation abort threaded through the entire prompt assembly process. AbortController plumbed into provider request layer twice (second one stuck).
  • Provider list grew: openai, anthropic, google, google_vertex, openrouter, deepseek, chutes, nanogpt, zai, moonshot, mistral, ai21, perplexity, groq, xai, electronhub, fireworks, pollinations, siliconflow, infermatic, custom.
  • Web search functionality. Owner-side SearXNG with private-IP block and safeFetch gating.
  • Empty send nudge preset field for proactive prompts.
  • Shared error handler for all providers. Cleaner provider error attribution so Lumiverse stops getting blamed for upstream socket drops.

Anthropic

The Anthropic native-thinking saga had its own folder of suffering. Resolution, in order of arrival:

  • Native thinking explicitly disabled unless requested.
  • Final-pass sweep strips reasoning tokens when reasoning is off.
  • Hard-enforce no-reasoning when API reasoning disabled.
  • System prompt blocks no longer leak into the messages array.
  • Sanitization pass on text blocks inserted into the provider.
  • Canonicalization of the system string. Multi-part content handling repaired.
  • Reasoning display description label wrapping fix.
  • CoT regression in OAI-compatible flows fixed.
  • Prompt caching plumbed through the UI with deeper cache config.
  • Opus 4.7 XHigh reasoning parameter pushed through.
  • Reasoning timer stops desyncing when the user leaves the chat.

If you saw the message "Yet even MORE hardening for Anthropic reasoning (I am suffering)" in the commit log, that wasn't a typo.

Prompt Assembly

  • Atomic chat metadata merge: PATCH /chats/:id/metadata and chatsSvc.mergeChatMetadata() re-read the row inside the call so concurrent writers can't clobber each other's keys. Council results, expression detection, deferred WI/chat-var persistence, author's note all route through this.
  • 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 folds writes into the deferred metadata merge.
  • Persona pronouns: explicit subjective_pronoun, objective_pronoun, possessive_pronoun. JanitorAI-compatible aliases {{sub}}, {{obj}}, {{poss}} plus the explicit forms. Defaults to they/them/their.
  • 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. Reorderable. Per-chat persona add-on selection. Tag-based persona binds. Migration 056.
  • Linked preset profiles: PUT /chat/:chatId with { preset_id, linked_to_defaults: true } delegates resolution to current defaults instead of snapshotting block states. Regex enablement bound to owner preset IDs; tracked per preset.
  • Multi-character expression mapping for CharX imports. When ≥3 first-underscore-split prefixes share matching suffix counts, expressions store 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 per-entry scan.
  • World-info smart de-dupe. Catches near-duplicate entries that badly-authored lorebooks fired in parallel.
  • Cooperative cancellation: yieldAndCheckAbort(signal) during prompt assembly yields to the Bun event loop on setTimeout(0) so POST /generate/stop and WS pings don't hang on CPU-bound assembly.
  • Assembly prefetch: prompt-assembly-prefetch.ts batch-loads everything the pipeline needs — chat, messages, character, persona, connection, preset, all settings, WI entries, group members, embedding config, cortex config. ~7 queries instead of ~35-40.
  • DB fetches decoupled from prompt assembly. Performance profiler added for assembly steps to identify the slowest stages. Repeat keys and vectors cached during dry runs.
  • Display regex: per-message frontend cv counters + selective WS invalidation routing. Per-resolution var fingerprint + changedFields diff. after substitute_macros mode for whole-body post-substitution evaluation. Refetch pre-resolved templates when vars change. udvy flag support.
  • Macro additions: chat-utils, cortex, databank, formatting, logic, math, regex-ref, strings. Tests under src/macros/macros.test.ts (1088 lines).
  • ST-compat: dot-prefix resolution for core macros. Boolean if-check resolution fix. Truthiness for string comparators in if. Conditional, switch, and other path evaluators fixed. Setter macros stripped from chat output before generation ends, even when introduced via regex.
  • Context clipping evaluated before regex evaluation. Regex moved before context clip. Greeting messages run through macro evaluation. Persona resolution on display paths uses activePersonaId.

Chat Heads and Recovery

  • Floating indicators track background generations. Draggable avatar bubble shows status (assembling, council, reasoning, streaming, completed, error). Click to jump back.
  • Audio ping when a backgrounded chat finishes. Unlocks on first send to satisfy autoplay policy.
  • Configurable: toggle, size (32–64px), layout direction, opacity. Completion pings gated behind settings.
  • Race condition fixed where chat heads didn't update properly when Lumiverse was open on multiple machines.
  • Server-close persistence fixed. Dismiss gracefully on chat re-entry. Embedding phase now counts as assembly. Gravity affects the selected head. TTFT and reasoning content recovered correctly through the pool.

UI

  • Bubble + Minimal chat styles rebuilt with the same meta-pill features. Token counter on messages (optional). Generation stats on hover (TTFT, tokens/sec, provider, model).
  • Swipe controls in chat view on desktop and mobile. Long-press unified across mobile and desktop via synthetic contextmenu dispatch.
  • Floating avatar viewer: click an avatar to pop it out. Resizable on mobile. Touch events no longer bleed through the underlying input.
  • UI scaling: CSS zoom moved from body to body > * so React portals (modals, toasts, context menus) scale correctly. DNDkit tables made scale-aware via a helper module. Font scale and UI scale sliders commit on pointer release.
  • Range input normalization: 44px minimum touch target across all sliders. Sliders no longer interrupt scroll. Real-time visual adjustment with debounced commit.
  • Settings drawers centrally registered and added to the command palette.
  • Queued user messages: send while generating; queue dispatches after.
  • Tab reordering in sidebar configuration. Tab hiding. Per-tab context menu. Spindle Dock repositioning.
  • Character gallery rework. Core settings moved into initial bootstrap for faster retrieval. Some settings pulled out of localStorage.
  • Theme editor: AST-based CSS/TSX prop resolution for references that compile dynamically at build time. Asset uploads for fonts/images/SVGs. Export as .lumitheme. Import LumiTheme bundles. Web-compression for raster assets.
  • LumiHub preset and theme install. Update notification toast. Visual preset info in Loom tab.
  • Color extraction with luminance weights and luminous-aware bucket extraction.
  • Searchable popovers for world books and Dream Weaver. Searchable dropdown for data fields. Avatar images in searchable selects.
  • PWA: manifest fix for Chrome Android. Multiple iOS PWA tab-scrolling fixes. Scroll-to-interrupt for bubble pinning.
  • Mobile: dock panel fix, multi-select on iPhones, popover constraints for world-book selectors, range select, input bar cursor and newline fixes, mobile MIME type fix on character card uploads.
  • Right-click/hold context menu for messages is now optional. Copy selection when highlighting message items. Markdown + copy for council feedback.
  • Tilt effect on landing page. Logout button in device session.

Streaming and Virtualization

  • Full message list virtualization instead of per-row. Width-gate measurement cache wipe so the mobile keyboard doesn't thrash virtualized rows.
  • Streaming render stability: stable text-block anchor, continuous reflow anchoring, stable identity key, hardened scroll layer.
  • Snap-down on stream end suppressed. Auto-pin breaks on the first scroll-up.
  • Preserve IMG element identity across chat content re-renders.
  • Background message prefetch during scroll and chat entrance.
  • Performance regression on long-running chats fixed.
  • Mutation observer added to greeting messages for Android layout reliability.

Working around "absolutely god awful React virtualization logic" got its own commit. Reader can guess the message.

Database & Infrastructure

  • Adaptive SQLite tuning at startup. cache_size and mmap_size sized against host RAM, configurable via databaseTuning (cacheMemoryPercent, mmapSizeBytes). Windows keeps mmap disabled.
  • Periodic maintenance scheduler with operator-configurable intervals (databaseMaintenance). Vacuum only runs when interval, hidden/idle timer, reclaim thresholds, and active-generation/visibility gates all line up.
  • LanceDB: compaction fix. Indexing strategy switch — big speedup on retrieval. World book split from general tables for performance. IVF_PQ recovery for <256 partitions on rebuild. Recovery path for partial vector stores. Adaptive batch halving for llama.cpp to recover from 413/500 max-batch-size errors gracefully.
  • Vector retrieval moved off the main loop. Profiling exposed. Pre-process HTML/tags from embedding query strings.
  • FTS5 / Trigram: characters_fts, world_book_entries_fts, persona search use tokenize='trigram' for CJK/substring (min 3 chars). 1-2 char queries fall back to a LIKE scan.
  • UUIDv7 generator replaces UUIDv4 in hot paths.
  • Compress and rate-limit middleware added.
  • idleTimeout set to 255s to mitigate slowloris.
  • WS frame size guard before JSON.parse. Default inbound WS frame limit bumped to 1MB.
  • Password length cap (128) on all password endpoints.
  • SQLite resilience: harden and recover against malformed VTAB and FTS indexes during a sudden shutdown/restart before WAL write lock. Stmt cache invalidation hardened. Recovery for "bad DB disk image."
  • Bun crash defense when chat memories grow very large.
  • Tokenizers added: Qwen3, Qwen3.5, Kimi K2/K2.5, Mistral V7 Tekken, Grok (OSS, estimated).

Security

  • Spindle sandboxing (above). Capability relaxation flags stripped from app shipping. Backend capabilities now declared in extension manifests.
  • HTML island hardening, image source restrictions, theme export hardening, multi-tenancy authority leak fixes.
  • Nonce consumer prevents creation-window hijack race. Sign-up endpoint blocked outside setup.
  • CORS proxy routes through safeFetch. Defense-in-depth against unsafe module usage in extensions.
  • MCP path tightened. Unit tests for SMB/MCP escape vectors.
  • Service worker openWindow() sanitized. Arbitrary URL pass through push notifications blocked. GitHub URLs sanitized in update flow.
  • app_manipulation moved to privileged perm enum.
  • Navigation safety middleware for Spindle API.
  • OpenRouter OAuth forwards properly from non-host origins.
  • CloudFlare ZT tunnel origin resolution fixed.
  • Idempotent Chrome push subscriptions fix gap with notification 403s.
  • SFTP gated behind explicit owner enablement.

Providers and Connections

  • Connection cards revamped. Reasoning bind snapshots on connection items. Per-item start-reply-with binds.
  • Embedding model URLs auto-fill connection details. Cortex model can override the connection default (settings reassignment was being ignored). Stop auto-filling embedding models to avoid model-dropdown confusion.
  • OpenRouter first-party: PKCE OAuth (server stores code_verifier in-memory, 5min TTL; frontend pops window, popup writes code to sessionStorage, parent exchanges via POST /openrouter/auth/callback). 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). Credit balance, generation stats, rich model metadata, 5-minute in-memory cache. App attribution headers.
  • Vertex AI: three rounds of fixes before it stuck. JWT signing, region mapping, endpoint URL — all corrected. Separate google_vertex embeddings provider. 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.
  • Z.AI: coding plan and standard endpoints, statically mapped (no documented models endpoint).
  • Google (Gemini): strip additionalProperties from tool schemas for the OpenAPI subset. Capture and echo thoughtSignature on functionCall parts. Switched sanitizer to the official Schema-field allowlist. Fall back to docs-sanctioned dummy thoughtSignature when capture misses.
  • Ollama compatibility layer for users who insist on Ollama. Stop using Ollama.
  • File connections for the SillyTavern migrator: local, sftp, smb, google-drive, dropbox. Remote-fetch cap on bytes per request. OAuth flows for Google Drive and Dropbox.

Notable Fixes

  • Stream errors no longer delete the entire message if content is present.
  • Abort requests bubble all the way to the provider request layer.
  • Risu card image display (asset map + <img="AssetName"> resolution).
  • JPEG+ZIP polyglot import for RisuAI cards. JPEG portion used as fallback avatar; detected via findJpegZipBoundary().
  • CHARX module support: lumiverse_modules.json for lossless round-trips of expressions, alternate fields/avatars, world books.
  • Character book firing in the pipeline. Imported character lorebooks make it to resolution.
  • Character book add/remove no longer leaves stale references.
  • Alternate fields trigger correctly. Stale alternate fields no longer poison group chats.
  • Group chat alternate fields selection, character merge option, multi-speaker, locked-character behavior with swipes/regenerations, ST avatar attribution, fork display.
  • Token counts swipe-aware. TTFT and generation-speed stats corrected.
  • Greeting messages no longer show swipe controls.
  • Macro if boolean and string comparator fixes. PHI block insertion when block isn't present but content is in the card.
  • Persona pronouns display in editor. Persona resolution on display paths.
  • Tokenization speed regression fixed.
  • LanceDB reindex status reflected in UI. World book recursion options were wired backwards.
  • ID-to-UUID assignment bug. Regex application to chat history.
  • Mobile expanded editor modal. ST migration WS messaging timing. ST JSONL chat file imports. ST preset export data matching. ST chat imports on Chromium.
  • Display preference set loading after server shutdown race.
  • Server starts even if LumiHub is down.
  • Docker CA certificates bundle renewal.
  • lru-cache pinned to a version without the Windows TLA regression.
  • Floating widget context menu ownership for Spindle (cross-wired contexts fixed by state tracking).
  • Council deliberation re-formats from full merged set on retry. Council results survive create-then-destroy within a single step.
  • Streaming impersonation lost-content when tabbing out or browser unfocus.
  • Bun crash with large chat memories defended against.
  • Author's note panel GET-then-PUT.
  • Auto-summaries fire even when the tab is inactive. Auto-summaries no longer fire on impersonate generations.
  • Inline tool injection skipped on impersonate generations.
  • LumiEngine dead IDs no longer persist.
  • Empty send behavior. Strikethrough rendering when any double tilde is present.
  • Gender identity mapping in Lumia editor/pack imports. Legacy group chat imports. JannyAI import mapping.
  • Vectorization and worldbook queues no longer fire before DB init.
  • Salience records protected from unsafe merge and cascade.
  • Group chat fork display. Group chat exporting/importing.
  • Form name requirement that froze browsers.
  • User ban renders correctly in the operator users panel (was rendering as a literal 0).
  • Mobile range select. Native text selection preserved without swipe override interference.
  • Snap scroll no longer repositions during streaming.
  • DeepSeek thinking parameters resolve. Anthropic native thinking (see its own section).
  • CoT content duplication when entire message is inside thinking tags.
  • CoT reinit during inline tool call continuation rounds.
  • Reasoning timer stops desyncing when the user leaves the chat.
  • Generation pool: TTFT and reasoning content recovery wired correctly into chat heads.
  • HTML island walker, full-document islands, trailing <style> blocks, multi-line opening tags.
  • Strict context clipping to chat history only.
  • Searchable selection auto-dismissal on Android.
  • Theme color picker race condition producing a hue of 0.
  • Mobile keyboard line removal shifting cursor position and focus.

Misc

  • LICENSE updated. SECURITY.md added.
  • User and developer docs under user-docs/ and developer-docs/: macros reference, prompt block execution order, sovereign hand, preset profiles, glossary, troubleshooting, world books, personas, presets, settings, packs, Cortex + LTCM Spindle surface, prompt assembly, batch image uploads, html-island markdown rules.
  • Discord invite in README. Hugging Face Spaces setup section in README.
  • start.sh / start.ps1: --kill-pkgs (-k) nukes lockfiles + node_modules and reinstalls. --auto-open (-a) opens the browser. Bun quick-upgrade flag. Identity/credential file pre-checks before setup. Tightened Windows rename behavior (falls back to cpSync + rmSync on failure).
  • Switched to esbuild for Vite. Vite dependencies added for Android Termux. Patched Termux-compatible LanceDB binary to defeat hardlinking issues.
  • Docker staging builds can optionally rebuild frontend bundles. Daily staging Docker image workflow.
  • Migrations: 038–048 cortex, 049 regex id, 050 cortex vaults, 051 TTS, 052 cortex perf indexes, 053 mcp, 054 username normalization, 055 databank, 056 global addons + saved prompts, 057 regex pack_id, 058 persona pronouns, 059 regex preset_id. Fresh DBs now bootstrap from src/db/baseline.sql instead of replaying the full stack. Squashed migrations auto-prune on non-git installs.
  • lumiverse-spindle-types: 0.3.9 → 0.5.x.
  • New dependencies: @opentelemetry/api, apache-arrow.
  • Many, many bones thrown at Termux and Docker users. They know who they are.

That's 1.0. The rest is upstream's problem now.