v1.1.0 - Spectra
Release Notes - 1.1.0
Release Date: March 6, 2026
Code Name: "Spectra"
🔮 Overview
"Spectra" delivers Lucia's largest entity-intelligence upgrade to date and folds in post-cut stabilization work across Home Assistant conversation flow, model-provider support, setup/plugins UX, and CI reliability. This release unifies entity modeling, introduces multi-signal matching, fixes semantic prompt-cache persistence and thresholding, and hardens the platform for day-to-day operation.
🚀 Highlights
- Unified Entity Model — All Home Assistant entity types now share a common
HomeAssistantEntitybase with domain-specific subtypes. - HybridEntityMatcher — Multi-weighted search combines Levenshtein, Jaro-Winkler, phonetic matching, aliases, and token overlap.
- Prompt Cache Overhaul — Embeddings now persist correctly, routing/chat thresholds are split, and cache settings hot-reload without restart.
- Embedding Resiliency + Live Progress — Entity-location embeddings now generate in throttled background batches, expose SSE progress, and support per-item evict/regenerate controls.
- Home Assistant Multi-turn Continuity — Follow-up conversation flow restored and HA commit validation tightened.
- OpenRouter + Discovery — OpenRouter added as a first-class provider with model discovery support.
- Plugin/Setup/Dashboard Stabilization — Headless setup and HA setup-step UX improvements, plugin installation reliability fixes, and dashboard/tooling cleanup.
- Brave Search API Plugin — New privacy-respecting web search plugin using the Brave Search API, with full plugin config GUI for managing API keys from the dashboard.
- CI Hardening — HACS validation workflow corrected, deployment docs lint cleanup, and release pipeline reliability improvements.
✨ What's New
🔍 HybridEntityMatcher
- Multi-signal scoring — Combines normalized Levenshtein, Jaro-Winkler, token overlap, phonetic matching, and exact/prefix bonuses into a weighted composite score.
- Configurable via
HybridMatchOptions— Tune weights, minimum thresholds, and phonetic algorithm (Soundex vs Double Metaphone) per search context. IMatchableEntityinterface — Any entity type can participate in hybrid search by implementing this lightweight interface.EntityMatchResult— Rich result type carrying the matched entity, composite score, individual signal scores, and match metadata.
🏠 Unified Entity Architecture
HomeAssistantEntitybase class — Shared properties (entity ID, friendly name, area, floor, aliases, state, supported features asSupportedFeaturesbitflag enum) for all HA entity types.- Domain subtypes —
LightEntity,ClimateEntity,FanEntity,MusicPlayerEntityextend the base with domain-specific attributes (color modes, HVAC modes, fan speeds, media metadata). EntityLocationServicerefactor — Centralized entity resolution service replaces per-skillFindLightsByAreaAsync/FindLightAsyncmethods. Skills now delegate entity lookup to the location service.AreaInfocaching — Areas now pre-build and cache entity collections, floor associations, and phonetic data for fast hierarchical search.FloorInfomodel — First-class floor representation with area containment for multi-level home topologies.
👁️ Entity Visibility
EntityVisibilityConfig— Per-entity visibility settings stored in MongoDB, letting users hide entities from Lucia without removing them from Home Assistant.EntityVisibilityApi— REST endpoints for bulk visibility management with area/domain filtering.- HA Exposed Entity List — Support for pulling the pre-filtered exposed entity list from Home Assistant via WebSocket (
homeassistant/expose_entity/list).
📡 Entity Embedding Resiliency + Live Progress
- Name fallback for embedding safety — When an entity/floor/area has no name or alias, matchable names now fall back to IDs (entity IDs strip domain and replace
_with spaces) to avoid invalid empty embedding inputs. - Non-blocking embedding generation —
EntityLocationServicenow loads/cache location data first, then generates embeddings asynchronously in throttled batches with retry/backoff. - Batch embedding pipeline — Uses provider batch generation (
GenerateAsync(IEnumerable<string>)) to reduce request pressure and better handle provider-side limits. - Progress API + SSE stream — Added
/api/entity-location/embedding-progressand/api/entity-location/embedding-progress/livefor real-time generation status. - Per-item cache controls — Added embedding eviction/regeneration endpoints for floors, areas, and entities.
- Dashboard live status — Entity Location page now shows a live generation progress bar, missing-embedding count, and updates without manual refresh.
🧠 Prompt Cache Overhaul
- Embedding persistence fixed — Removed
[JsonIgnore]fromCachedPromptEntry.EmbeddingandCachedChatResponseData.Embeddingthat prevented embeddings from ever being serialized to Redis. - Split thresholds —
SemanticSimilarityThreshold(routing, default 0.95) andChatCacheSemanticThreshold(chat, default 0.98) are independently configurable. - Hot-reload via
IOptionsMonitor— Cache thresholds update within seconds of dashboard config changes, no restart required. - Hit count tracking fix — Routing cache exact-match hits now correctly persist the incremented
HitCountback to Redis. - Normalized prompt keys —
NormalizePromptappliesTrim().ToLowerInvariant()for stable, case-insensitive cache keys. - User-text-only embedding — Chat cache embeddings are computed from the user's request text only.
🏠 Home Assistant Conversation Flow
- Restored multi-turn continuity behavior for follow-up requests.
- Enforced stricter HA-side commit validation in automation and tool flows.
- Addressed follow-up review feedback for the multi-turn flow fix set.
🤖 Model Providers
- Added OpenRouter as a provider option in model-provider interactions.
- Expanded model discovery flow and post-review provider hardening.
🔌 Setup, Plugins, and Dashboard
- Improved headless setup and Home Assistant setup-step UX.
- Fixed plugin tooling/integration issues that blocked reliable plugin installation.
- Resolved setup/plugin/dashboard review and lint issues.
🌐 Brave Search API Plugin
- New web search provider —
plugins/brave-search/plugin.csimplementsIWebSearchSkillusing the Brave Search API as an alternative to SearXNG. - API key authentication — Configurable via
BraveSearch:ApiKey,BRAVE_SEARCH_API_KEYenv var, or the new plugin config GUI. - Full telemetry — OpenTelemetry
ActivitySourceandMeterinstrumentation for request counts, failure counts, and search duration. - Provider-agnostic agent — General Agent skill description no longer references SearXNG; works with whichever search plugin is active.
⚙️ Plugin Configuration GUI
- Schema-driven config — Plugins can now declare configurable properties via
ConfigSection,ConfigDescription, andConfigPropertieson theILuciaPlugininterface (default interface members — non-breaking). PluginConfigPropertyrecord — Defines name, type, description, default value, and sensitivity for each config field.GET /api/plugins/config/schemas— New endpoint aggregates config schemas from all loaded plugins.- Dashboard Configuration tab — New tab on the Plugins page renders dynamic forms from plugin schemas, with sensitive-field masking, save/discard, and toast notifications.
- SearXNG retrofitted — SearXNG plugin now declares its
BaseUrlin the config schema so it can also be configured from the UI.
🐛 Matcher Debug API
/api/matcher/debug— Interactive endpoint for testingHybridEntityMatcherqueries against live entity data with per-signal score breakdowns.- Dashboard page —
MatcherDebugPage.tsxprovides a UI for experimenting with matcher queries and score distributions.
🔧 Skill Optimizer Migration
GetCachedEntitiesAsyncremoved fromIOptimizableSkill— Entity resolution now flows throughEntityLocationService.- Legacy skill methods retired —
LightControlSkill.FindLightsByAreaAsync,FindLightAsync,GetLightStateAsync, andSetLightStateAsyncnow throwNotSupportedException. - Device cache dependencies removed —
LightAgentno longer depends directly on embedding provider or device cache.
🎯 Skill Optimizer Enhancements
- Import from Traces — Fixed and operational. Extracts search terms from traced tool calls for the skill's owning agent, using skill-declared
SearchToolNamesandAgentIdinstead of hardcoded values. - Multi-entity expected results — Test cases now support multiple expected entities (e.g., "kitchen lights" → 2 light entities). New
EntityMultiSelectcomponent with chip display, searchable dropdown, and keyboard navigation (↑/↓/Enter/Tab/Escape/Backspace). - Partial scoring — Recall (3.0 max) goes negative when expected entities are missed or when results exceed the max count. Precision (1.0 max) rewards exact count matches with partial credit for extras within limits.
- Export test dataset — New "Export Dataset" button downloads a JSON file containing test cases + entity location data for offline replay and issue reporting.
🕵️ Agent Impersonation & Entity Debugging
- Impersonate Agent filter — New dropdown on Entity Locations page (Entities + Search tabs) filters the entity view to what a specific agent can see. Auto-applies the agent's configured entity domains and visibility restrictions.
- Agent domain metadata —
available-agentsAPI returns{name, domains}objects by aggregatingEntityDomainsfromIOptimizableSkillregistrations. Domainless agents are filtered out. - Server-side domain+agent filtering — Entity and search endpoints accept comma-separated
domainandagentquery parameters for combined filtering. - Entity removal — Delete button on Entity Locations page now fully removes entities from the cache (not just embeddings), fixing issues with stale/duplicate entity IDs.
⚙️ Configurable Skill Domains & Agent Definitions
ISkillConfigProviderinterface — Agents expose their skill config sections withOptionsTypefor schema generation. Implemented by LightAgent, ClimateAgent, SceneAgent, and MusicAgent.- Dynamic skill config editor — Agent Definitions page renders a schema-driven form for each agent's skill options (EntityDomains, matcher thresholds, etc.). Controls: tag picker for string arrays (backed by available HA domains), range sliders for numbers, integer inputs.
EntityDomainsviaIOptionsMonitor— All skill options classes (LightControlSkillOptions,ClimateControlSkillOptions,FanControlSkillOptions,SceneControlSkillOptions,MusicPlaybackSkillOptions) now includeEntityDomainswith hot-reload from MongoDB config.IAgentSkill.EntityDomains— All agent skills declare their operating domains.SearchHierarchyAsynccalls use the options-backed value instead of hardcoded arrays.- Config seeder upgrade — Seeds missing config sections on restart (not just when collection is empty), handling upgrades gracefully.
- Skill sections hidden from raw Config page — Skill config is managed exclusively through the Agent Definitions page.
🎵 Music Agent Consolidation
- In-process execution — Music Agent moved from a separate A2A container to always running in-process with AgentHost. Enables
IOptimizableSkillandISkillConfigProvidervisibility in the AgentHost DI container. IEntityLocationServicemigration — Replaced ~300 lines of custom entity resolution (Redis cache, embeddings, Music Assistant-specific filtering, cosine similarity) with the sharedSearchHierarchyAsyncpipeline.MusicPlaybackSkillOptions— New options class withEntityDomainsdefaulting to["media_player"]plus standard matcher params, hot-reloaded viaIOptionsMonitor.- Kubernetes cleanup — Removed music-agent Service, Deployment, and image overrides from helm chart and raw manifests. Only timer-agent remains as an external A2A pod.
🐳 CI/CD and Delivery
- Added support for pre-release Docker tags without moving
latest. - Fixed CI workflow ordering to check out repository contents before HACS validation.
- Fixed deployment markdownlint issues and removed defunct documentation.
🐛 Bug Fixes
- Prompt cache embeddings never persisted — Fixed serialization of embedding fields.
- Chat cache replayed incorrect actions — Prevented cross-action semantic collisions by splitting routing/chat thresholds.
- Routing cache hit count not persisted — Exact-hit
HitCountnow writes back to Redis. - Cache config changes required restart — Migrated to
IOptionsMonitor<T>for hot-reload. - Embedding provider concurrency issue — Replaced unsafe dictionary usage with concurrency-safe coordination.
- Tracing duration always reported 0ms — Routing completion timing now measures elapsed request duration correctly.
- Unsupported tool-chain config caused provider errors — Removed invalid configuration path.
- Dashboard dependency vulnerabilities — Patched minimatch (CVE-2026-27903) and rollup (CVE-2026-27606).
- Home Assistant follow-up flow regression — Fixed continuity and follow-up behavior for multi-turn requests.
- Plugin install regressions — Fixed install path/tooling issues affecting plugin usability.
- HACS validation workflow failure — Corrected CI step order to ensure repository content is present.
- Startup embedding failures from blank input — Prevented invalid embedding calls caused by empty match names.
- Embedding request bursts during cache reloads — Moved generation to throttled background batching to reduce provider rate-limit pressure.
- Presence sensor refresh duplicate-key crashes — Fixed MongoDB duplicate key failures on re-scan by deduplicating auto-detected sensor IDs and skipping IDs already reserved by user overrides (issue #41).
- Skill Optimizer "Import from Traces" broken — Fixed hardcoded tool names (used deprecated
FindLightAsyncinstead ofGetLightsState), missing agent filter on trace queries, and parameter name mismatch (searchTermvssearchTermsarray). Trace import now uses skill-declaredSearchToolNamesandAgentId. - Music Agent playback regression — Removed unnecessary
?return_responsequery parameter fromplay_mediaservice calls. Migrated Music Agent from custom entity resolution (Redis cache, embeddings, MA-specific filtering) to sharedIEntityLocationService. - Stale entities in location cache — Added full entity removal (not just embedding eviction) so duplicate/orphaned entities can be deleted from the cache.
- Kubernetes HPA for single-instance app — Removed HorizontalPodAutoscaler from helm chart and raw manifests since Lucia doesn't support multi-instance yet.
🧪 Testing
- Playwright e2e test —
PromptCacheRoutingTestsvalidates prompt-cache embedding round-trip and semantic route matching behavior. - Embedding diagnostics —
EmbeddingMatchingTestsmeasure similarity behavior across synonym/opposite/cross-domain prompt variants. - Plugin/install regression coverage — Added and updated tests around plugin installability and related dashboard/setup flows.
- Name fallback tests —
EntityMatchNameFormatterTestsvalidates alias sanitization and ID-based fallback behavior used by embedding inputs. - Brave Search contract tests —
BraveSearchWebSearchSkillTestsvalidates HTTP request format, auth headers, JSON deserialization, empty results, and error handling. - Plugin config schema tests —
PluginConfigSchemaTestsvalidates default interface members, schema declaration, property equality, and filtering logic. - Skill Optimizer trace import e2e —
03-skill-optimizer-traces.spec.tsvalidates traces API returns Light Agent data, skill traces API extracts search terms, and UI "Import from Traces" populates test cases. - Agent impersonation e2e —
04-entity-location-impersonate.spec.tsvalidates agent domain metadata, entity filtering by domain+agent (22 light/switch entities for light-agent), and search scoping ("zack's light" returns 1 result as light-agent). - Dashboard port pinned — Vite dashboard pinned to port 7233 via Aspire
WithEndpointfor stable Playwright test URLs.
📋 New Files
| Path | Purpose |
|---|---|
lucia.Agents/Abstractions/IEntityLocationService.cs |
Centralized entity resolution interface |
lucia.Agents/Abstractions/IHybridEntityMatcher.cs |
Multi-signal entity search interface |
lucia.Agents/Abstractions/IMatchableEntity.cs |
Entity search participation contract |
lucia.Agents/Models/HomeAssistant/HomeAssistantEntity.cs |
Unified HA entity base class |
lucia.Agents/Models/HomeAssistant/SupportedColorModes.cs |
Light color mode bitflag enum |
lucia.Agents/Models/HomeAssistant/FloorInfo.cs |
Floor model with area containment |
lucia.Agents/Models/HomeAssistant/OccupiedArea.cs |
Area occupancy tracking |
lucia.Agents/Models/HomeAssistant/EntityVisibilityConfig.cs |
Per-entity visibility settings |
lucia.Agents/Models/HybridEntityMatcher.cs |
Multi-weighted entity matching engine |
lucia.Agents/Models/HybridMatchOptions.cs |
Matcher configuration (weights, thresholds) |
lucia.Agents/Models/MatchableEntityInfo.cs |
Searchable entity wrapper |
lucia.Agents/Models/EntityMatchResult.cs |
Scored match result with signal breakdown |
lucia.Agents/Models/HierarchicalSearchResult.cs |
Floor→Area→Entity search result |
lucia.Agents/Models/ResolutionStrategy.cs |
Entity resolution strategy enum |
lucia.Agents/Integration/SearchTermCache.cs |
Cached search term normalization |
lucia.Agents/Integration/SearchTermNormalizer.cs |
Query normalization pipeline |
lucia.HomeAssistant/Models/ExposedEntityListResponse.cs |
HA WebSocket exposed entity response |
lucia.AgentHost/Apis/EntityVisibilityApi.cs |
Entity visibility REST endpoints |
lucia.AgentHost/Apis/MatcherDebugApi.cs |
Matcher debug/testing REST endpoints |
lucia.Agents/Models/HomeAssistant/EntityLocationEmbeddingProgress.cs |
Embedding coverage/progress snapshot model |
lucia.Agents/Services/EntityMatchNameFormatter.cs |
Safe name/alias formatter with ID fallback |
lucia-dashboard/src/pages/MatcherDebugPage.tsx |
Matcher debug dashboard page |
lucia-dashboard/src/pages/EntityLocationPage.tsx |
Live embedding progress UI + embedding actions |
lucia.PlaywrightTests/Agents/PromptCacheRoutingTests.cs |
Cache embedding e2e test |
plugins/brave-search/plugin.cs |
Brave Search API web search plugin |
lucia.Agents/Abstractions/PluginConfigProperty.cs |
Plugin config property record type |
lucia.AgentHost/PluginFramework/Models/PluginConfigSchemaDto.cs |
Plugin config schema API DTO |
lucia.AgentHost/PluginFramework/Models/PluginConfigPropertyDto.cs |
Plugin config property API DTO |
lucia-dashboard/src/components/PluginConfigTab.tsx |
Plugin configuration tab component |
lucia.Tests/BraveSearchWebSearchSkillTests.cs |
Brave Search HTTP contract tests |
lucia.Tests/PluginConfigSchemaTests.cs |
Plugin config schema infrastructure tests |
lucia.Agents/Abstractions/ISkillConfigProvider.cs |
Agent skill config section exposure interface |
lucia.Agents/Abstractions/SkillConfigSection.cs |
Skill config section descriptor with OptionsType |
lucia.Agents/Configuration/SceneControlSkillOptions.cs |
Scene skill configurable options |
lucia.MusicAgent/MusicPlaybackSkillOptions.cs |
Music skill configurable options |
lucia.AgentHost/Apis/AgentInfo.cs |
Agent info DTO with domain metadata |
lucia-dashboard/src/components/EntityMultiSelect.tsx |
Multi-select with chips, search, keyboard nav |
lucia-dashboard/src/components/SkillConfigEditor.tsx |
Schema-driven skill config form editor |
lucia-playwright/e2e/03-skill-optimizer-traces.spec.ts |
Skill optimizer trace import e2e tests |
lucia-playwright/e2e/04-entity-location-impersonate.spec.ts |
Agent impersonation filter e2e tests |
🗑️ Removed / Deprecated
| Path | Reason |
|---|---|
lucia.Agents/Services/IEntityLocationService.cs |
Moved to Abstractions/ namespace |
lucia.Agents/Models/FloorInfo.cs |
Moved to Models/HomeAssistant/ |
lucia.Agents/Models/OccupiedArea.cs |
Moved to Models/HomeAssistant/ |
lucia.Agents/Agents/DiagnosticChatClientWrapper.cs |
Replaced by TracingChatClientFactory |
lucia.Agents/Configuration/AgentConfiguration.cs |
Replaced by AgentDefinition |
LightControlSkill.FindLightsByAreaAsync |
Throws NotSupportedException — use entity tools |
LightControlSkill.FindLightAsync |
Throws NotSupportedException — use entity tools |
IOptimizableSkill.GetCachedEntitiesAsync |
Removed — optimizer uses location service |
infra/kubernetes/manifests/07-hpa.yaml |
Removed — single-instance constraint, no HPA needed |
MusicPlaybackSkill custom resolution |
Replaced by IEntityLocationService.SearchHierarchyAsync |
| Music Agent A2A container | Moved in-process with AgentHost |
⬆️ Upgrade Notes
- Cache eviction recommended — Evict routing and chat caches via dashboard (or
DELETE /api/prompt-cacheandDELETE /api/chat-cache) to clear stale entries. - New cache config properties —
RouterExecutor:SemanticSimilarityThreshold(0.95) andRouterExecutor:ChatCacheSemanticThreshold(0.98) can be tuned in dashboard settings. - Skill API breaking changes — Skills calling
FindLightsByAreaAsync,FindLightAsync, orGetCachedEntitiesAsyncmust migrate to unified entity tools viaEntityLocationService. - Music Agent now in-process — The music-agent container is no longer deployed separately. Remove the
music-agentDeployment/Service from your Kubernetes cluster if upgrading from mesh mode. - HPA removed — If you had a HorizontalPodAutoscaler for the
luciadeployment, remove it. Lucia requires a single replica until HA support is implemented. - Skill config auto-seeded — New skill option sections (
LightControlSkill,ClimateControlSkill,FanControlSkill,SceneControlSkill,MusicPlaybackSkill) are auto-seeded to MongoDB on first startup. Edit via Agent Definitions page, not the raw Configuration page. - Entity cleanup — Use the new delete button on Entity Locations to remove stale/duplicate entities that may cause service call failures.