All notable changes to this project will be documented in this file.
- OpenChamber ingress survives abandoned browser streams (issue #98) — disconnecting during an HTTP or WebSocket response now tears down that request instead of crashing the ingress proxy and restarting the add-on.
- OpenCode V2 readiness tracking — maintainers now have a root-level compatibility checklist covering the upstream beta's migration work, current blockers, and release gates.
- OpenCode V1 improvement roadmap — maintainers now have a Home Assistant-focused plan for a certified runtime, on-demand skills, read-only diagnostics, and regression coverage.
The 2.4.2 beta cycle, promoted: a current OpenChamber web UI, resilient service supervision, safer timestamps, and clearer Home Assistant operations diagnostics.
- OpenChamber stays available after an add-on restart (issue #95) — the server and Home Assistant Ingress proxy are independently supervised, so restarting either cannot strand a port-holding orphan process on 3010 or 8099.
- OpenChamber 1.18.1 with working browser OAuth — browser providers whose callback is container-local now show a paste-code flow, allowing the add-on to replay the failed localhost redirect inside the container instead of waiting for an unreachable browser callback.
- Firefox terminal sizing — high-DPI Firefox sessions reconcile their pixel ratio with the rendered terminal canvas, restoring the full terminal width without affecting other browsers.
- Reliable Supervisor app discovery (issue #90) — update checks, app changelogs, ESPHome discovery, and startup service discovery prefer the feature-gated Supervisor V2 apps API while retaining V1 support.
- Supervisor operations diagnostics — six read-only tools provide bounded health, Resolution, backup posture, support-log, store-audit, and metrics evidence without exposing sensitive configuration or log secrets.
- Unambiguous history timestamps (issue #94) — history, logbook, and calendar queries now require timestamps with
Zor a UTC offset, preventing local-time interpretation from silently shifting requested windows.
- Startup hooks (issue #66) — an opt-in, persistent
startup.dfolder is now the supported place for your own shell scripts that need to run at add-on startup. Hooks run as root in filename order;ha-hooks list,ha-hooks run, andha-hooks loglet you inspect and test them. They are off by default, are bounded against hangs and restart loops, and their credential-bearing logs are excluded from backups. - LAN custom agents can write their allowed files (issue #92) — scoped absolute edit rules now work in headless server sessions, while unapproved writes are denied instead of hanging indefinitely.
- Sharper Home Assistant agent tools — choose a compact, configuration, or full MCP tool profile to reduce irrelevant tool definitions; capability status now says whether the native MCP bridge is actually usable; and
ha-agent-evalcan score a real OpenAI-compatible model against safe synthetic tool-call scenarios without touching your Home Assistant instance. - Smaller installed image — production images no longer include unused platform binaries, development artifacts, build toolchains, or the standalone PPQ proxy's optional OpenClaw peer tree; runtime features are unchanged.
The 2.3.9 beta cycle, promoted. A native MCP bridge that finally meets the Home Assistant release it was written for, two Core log errors that made your logs lie about your setup, a class of services that could not be called at all, and a first pass at what every request costs you.
- The native Home Assistant MCP bridge works, on 2026.8 and before it — Home Assistant's native LLM platform arrives in 2026.8: the
llmintegration, the per-domain tool platforms, and the keyed/api/mcp/<API ID>endpoints all first ship there. The bridge was written against that platform before it existed and targeted/api/mcp/assistunconditionally, so on every shipping Home Assistant it hit a 404 and did nothing. It now prefers the keyed endpoint and falls back to the configured/api/mcpwhen the keyed one is not served, retrying periodically so upgrading Home Assistant under a running add-on is picked up on its own. Tool schemas that Home Assistant could not serve correctly before 2026.8 are repaired in transit (home-assistant/core#176762), and every message is validated as JSON-RPC 2.0 before being forwarded, because malformed POSTs to/api/mcphave been reported to crash Core (#176734) — that one is not fixed in 2026.8, so the guard applies on every version.get_agent_capabilitiesreports the minimum version, whether this instance meets it, and each upstream limitation against the release that fixes it, so a stalled bridge reads as a known upstream gap rather than a broken configuration. Two one-time steps are required to use it: add the Model Context Protocol Server integration in Home Assistant, then turn the bridge on and restart the add-on. See Native Home Assistant MCP Bridge. - Any registered LLM API is reachable, not just Assist — Home Assistant requires admin access for keyed
/api/mcp/<API ID>endpoints other than Assist, which reads as a wall for an add-on and is not one: the Supervisor calls Core as its own system user, which Home Assistant creates in the admin group. A custom LLM API from your own integration is testable over/api/mcp/<your API ID>with no token, and an unknown-API-ID error means the ID does not exist rather than that access was refused. Relatedly,/api/mcpserves every API selected in the MCP Server integration — that setting is a multi-select — so leaving the API ID empty gives you all of them. - Services that answer with data now work through
call_service(issue #82, reported by @GuiPoM) —recorder.get_statistics,weather.get_forecasts,calendar.get_events,todo.get_itemsand every other response-capable service were unreachable. Home Assistant requires?return_responsefor them,call_servicenever sent it, and its schema rejected the argument outright. The flag cannot simply always be sent — Home Assistant answers 400 in both directions — so it is now decided from Home Assistant's own service catalog, where a description carries aresponsekey only when the service supports one.get_servicesmarks which services answer with data, so the set is discoverable rather than guessed at. - Two Core log errors, both reported with accurate root-cause analysis by @JayMansel — the screenshot tool sent a second WebSocket authentication frame on every capture, logging
Received invalid command: {'type': 'auth', ...}(issue #74); the frontend now owns authentication and the interceptor is a genuine fallback. The YAML language server called a Jinja global that does not exist, loggingTemplate variable error: 'devices' is undefinedand never offering device ID completions (issue #75); the device list is now derived from the entities instates. Neither broke the feature it belonged to, which is why both went unnoticed for so long. - Direct file edits ask before writing (issue #81) — this add-on points an AI agent at a live Home Assistant installation, and until now a newly installed add-on would edit configuration files without confirming anything first. Editing a file now asks for approval, as do in-place shell edits (
yq -i,sed -i,tee) and removing or renaming files. Read-only commands are unaffected. Writes throughwrite_config_safestill do not prompt — they already validate, back up, and roll back. Both directions stay configurable through Custom OpenCode config. - Less of your context spent on the add-on's own plumbing — recording a decision no longer rewrites the system prompt mid-conversation (it was discarding the cached prefix, and the whole conversation with it); MCP tool responses are no longer pretty-printed, since indentation is whitespace only the model reads and is paid for again on every request it stays in history; and an undomained
get_statesis capped at 150 entities rather than 500. Together the last two take a 500-entity response from roughly 69,000 characters to about 15,500. Domain-filtered calls keep the 500 ceiling. This matters most on local models, where the whole prompt is re-read on your own hardware rather than absorbed by a provider's cache. - A CPU too old for OpenCode says so instead of crashing (issue #86, reported by @deanhalllincoln) —
opencode --versiondied withIllegal instruction (core dumped)and nothing explained why. OpenCode ships as a Bun-compiled binary, so Bun's CPU floor is OpenCode's: even the x64 baseline build requires SSE4.2. The add-on now checks for it at start-up and names the CPU and the requirement in the log. Note that thebaselineCPU mode does not currently do what it promised — upstream is publishing the AVX2 binary inside that package (anomalyco/opencode#33595) — so machines with SSE4.2 but no AVX2 hit the same fault the option exists to avoid. The option is kept rather than removed, because it starts working the moment upstream publishes a genuine baseline build. Minimum hardware is now documented up front. - The beta add-on no longer writes over this one — if you run both channels, they shared your configuration directory and interfered in three ways: decision notes were written to the same file, so a note recorded while trying something in beta was injected into every stable session afterwards; both deployed
AGENTS.md, and only one file there can carry the name OpenCode looks for, so whichever started last owned it — and beta's copy tells the model things that are true of beta's build and false of this one; and each recorded "this is the copy I wrote" in its own private/data, so each kept concluding you had hand-edited the other's file and stopped updating it. This add-on now ownsAGENTS.mdoutright and keeps its ownership marker beside the file, which also means reinstalling no longer looks like a hand edit.
Home context, promoted from the 2.3.8 beta cycle: OpenCode now starts each session already knowing what your installation looks like and why it is the way it is, instead of rediscovering both from scratch every time.
- Sessions start knowing your installation (issue #63) — a compact install briefing describing your areas, integrations, configuration layout and add-on capabilities is generated once and refreshed on demand, so the first question of a session no longer has to be spent on discovery. Where the briefing cannot fit everything, it names what it left out rather than staying silent, so a gap in OpenCode's context can never read as an absence in your setup.
- Your own instructions survive add-on updates — rules you write now live in
AGENTS.local.md, which the add-on never overwrites. The previous guidance pointed at/config/AGENTS.md, which was replaced on every update; the one-time migration backs up an existing file rather than clobbering it. - Decision notes carry reasoning between sessions — your YAML records what your setup does but not why, so a deliberate choice looks identical to an oversight and gets "fixed". Notes are recorded only with your explicit approval, are screened for credentials both when written and when read back, are dated by your local clock, and can be pinned so the constraints that matter most are the last to be dropped. Three MCP tools (
remember_decision,recall_decisions,supersede_decision) and a newha-contextcommand manage them; recall matches a plain question rather than a single substring, and an empty result says how many notes exist instead of implying nothing was ever decided. - Screenshot tool fixes (issue #72) — it reported "captured successfully" while writing nothing to disk, so models advised users to go and find a file that did not exist; the PNG only ever exists inside the tool result, and the tool now says so. The add-on's own vision model for PPQ private mode could not receive images at all because its
modalitiesfield was missing, the 10-second MCP call deadline could cut a screenshot off on slower hardware (now 60), and the tool is now hidden unless the feature is on and an access token is set. Whether a screenshot is usable still depends on the model you select — the documentation and option description now say so.
Both channels are now built from separate branches: stable from main, beta from dev. See RELEASING.md.
- Optional OpenChamber LAN web UI — a new
enable_openchamber_lanoption (only active wheninterface_mode: openchamber) publishes the OpenChamber UI on a mappable network port (4097/tcp), mirroring the existing OpenCode LAN server on4096/tcp. It runs a second instance of the ingress proxy bound to0.0.0.0with the remote-address allowlist relaxed (viaOPENCHAMBER_ALLOW_ANY_REMOTE) and serves the UI at the root path/, so reverse proxies and tunnels (e.g. Cloudflare Tunnel) can point straight at a backend without an ingress-path redirect/rewrite. Off by default; requires both enabling the option and mapping4097/tcpin Network settings. No Home Assistant Ingress auth sits in front of the mapped port, so it is intended for trusted networks or behind a reverse proxy / access control. - Configuration page promoted from beta — reorganized the Configuration tab into clear presentation, Home Assistant integration, access-control, runtime, network, provider, hardware, and advanced groups; aligned labels and descriptions with the actual option order; and promoted the opt-in focus-friendly responses, native Home Assistant MCP bridge, and LAN CORS settings while keeping experimental features explicitly marked beta.
- Browser provider sign-in no longer hangs on "Saving..." (issue #54) — connecting a provider from the OpenChamber UI with a browser OAuth method (for example ChatGPT Pro/Plus (browser)) never finished. OpenCode's browser methods start a callback listener on a loopback port inside the add-on container and send the browser to
http://localhost:<port>/auth/callback; behind Home Assistant Ingress the browser runs on your own device, so that redirect lands nowhere and the pending sign-in request waits on the listener indefinitely — the pasted code is ignored for these methods. The ingress proxy now remembers the loopback redirect from the authorization step and replays it to the in-container listener when you paste the code, so the exchange completes and the provider is saved. Paste either the authorization code or the wholehttp://localhost:...URL your browser failed to open; the on-screen instructions now describe what actually happens instead of promising the window will close by itself. Providers that do not use a loopback callback are unaffected. Thanks to @DennisSDUSA for the detailed report and to @matrix2669 for the headless workaround. - Quieter add-on log — ttyd logged every accepted HTTP connection at libwebsockets NOTICE level, so the container health check (which probes
http://127.0.0.1:8099/every 30 seconds) produced a repeating three-line burst — roughly 4,300 lines a day of noise that buried real messages. ttyd now runs at log levelERR|WARN(-d 3), so genuine errors and warnings still surface while the per-probe chatter is gone. - Terminal now fits the Home Assistant iframe (issue #56) — the ingress terminal kept its initial oversized dimensions and overflowed on the right and top (for example,
Ctrl+P's "Session" header sat above the visible area), and toggling the HA sidebar did not reflow it. ttyd re-fits the terminal only from a windowresizeevent, but Home Assistant resizes the add-on iframe from its own JavaScript without ever firing one. A small injected browser-side script now watches the viewport with aResizeObserverand calls ttyd'swindow.term.fit()on the iframe-driven size changes thatresizemisses, so the terminal reflows to the available space on load and when the sidebar toggles. Thanks to @fmjensen for the detailed report and root-cause analysis. - Home Assistant configuration access — OpenCode now persistently allows the mounted
/homeassistantconfiguration directory, so normal configuration work no longer asks for external-directory permission in every session while sensitive-file read protection remains in effect. - Supervisor-safe Home Assistant logs (issue #57) —
ha-logs errorand the MCPget_error_lognow fall back to Core journal logs when Supervisor disables the file-backed error-log endpoint. Thanks to @GuiPoM for reporting it. - Beta: optional focus-friendly response mode — added action-first, concise, progress-aware response guidance that preserves Home Assistant approval and safety requirements. Inspired by @ayghri's
i-have-adhdresponse-style skill. - OpenChamber updated to 1.16.2 — bumped the pinned
@openchamber/webfrom 1.14.0 to the latest 1.16.2, and reworked the Home Assistant Ingress bundle patcher (patch-ingress.js) so it no longer breaks on OpenChamber's minified-name drift. The four required patches (runtime URL builder, API URL builder, API path classifier, service-worker) now match the bundle structurally and reuse the captured minifier names instead of hardcoding them, so the patch is validated to apply cleanly across 1.14.x through 1.16.2 and is more resilient to future version bumps. The bundle still binds to127.0.0.1behind the first-party ingress proxy as before. - Stop OpenChamber's built-in updater from hanging the UI — OpenChamber ships a self-update check ("update available", plus an Update button in Settings → About), but OpenChamber is pinned and patched for Home Assistant Ingress at image build time, so an in-app update cannot persist across restarts or stay Ingress-patched — it just hung the UI on "Waiting for server...". The add-on now points OpenChamber's update-check API (
OPENCHAMBER_UPDATE_API_URL) at a local canned "no update" endpoint served by the ingress proxy, so the update notification no longer appears and the update action reports "No update available" instead of hanging. OpenChamber is updated by updating the add-on.
- OpenCode attribution and license notices - added a clear upstream credit, MIT notice, non-affiliation statement, and in-image notice for the OpenCode software distributed by this add-on.
- Hardened file access: sensitive files are read-protected by default (#53) — a new Restrict access to sensitive files option (default on) adds an OpenCode
permission.readdeny rule forsecrets.yaml, the.storage/and.cloud/directories, thessl/directory, and*.key/*.pemfiles, so their contents cannot be read into the model's context. Everything else stays readable and normal!secret-based config editing is unaffected. Set the option tofalseto restore the previous fully-permissive behavior. Note: this guards OpenCode's file-read tool, not shell commands. Thanks @ChristopherBull for the suggestion. - Fixed PPQ Private (TEE) proxy failing to start (#34) — the
ppq-private-proxyservice resolved its entrypoint withnpm root -gafter sourcingNPM_CONFIG_PREFIX=/data/.npm-global, so it looked forppq-private-modein the persistent OpenCode prefix instead of the image's global modules and crashed withERR_MODULE_NOT_FOUND. The lookup is now isolated from that override, and a missing package logs a clear error instead of a raw Node stack trace. The PPQ provider's models also carry explicitidfields now so OpenCode addresses them correctly. Thanks to @iBobik for diagnosing and fixing this. - Fixed the low-memory start-up crash loop (issue #51) — on 4 GB devices (for example a Home Assistant Green) the boot-time
npm install -g opencode-ai@latestcould exhaust RAM, make Supervisor unresponsive, and leave the add-on in a watchdog crash loop (repeated exit code 137). Two changes remove this. The default OpenCode update policy is nowbundled, so a fresh install runs entirely on the OpenCode shipped in the image with no start-up download. When you opt intolatest, the ingress terminal now comes up immediately on the bundled (or an existing healthy persistent) binary while the update runs in a detached background process — off the health-check critical path — that is skipped automatically when free memory is below ~1.5 GB, so the npm spike can no longer push a low-memory host into swap-thrash. An interrupted or non-working update is now discarded instead of shadowing the working bundled binary, which also fixes the related/data/.npm-global/bin/opencode: cannot execute: required file not foundfailure. - Native Home Assistant MCP readiness —
get_agent_capabilitiesnow probes Home Assistant Core's native MCP endpoints, including/api/mcp/<API ID>, and reports whether OpenCode should use regular MCP only or a hybrid native-LLM-API/OpenCode-MCP mode. The opt-in native MCP bridge is being validated in the beta channel first and does not replace OpenCode's built-in MCP tools. - Better Home Assistant context and native LLM development support — added
get_home_contextfor compact area/domain/entity-scoped understanding with registry-derived area/device metadata, plusget_ha_llm_development_guidefor upstream references, checklist, and a starter template for native<integration>/llm.pytool providers.
- Bundled
yqfor Home Assistant-aware YAML on the command line — the add-on image now shipsyq(mikefarah's static Go build, pinnedv4.53.3), fetched per-architecture likettyd. It gives the agent a YAML reader/query tool that understands Home Assistant's custom tags —!include,!secret,!env_var,!input, and the!include_dir_*family — which standardpython3/PyYAML and Ruby's YAML (neither of which is installed) cannot parse: they abort on the first!include.AGENTS.mdnow directs the agent toyqfor reading, querying, and converting configuration, while writes stay on the existing safe-write path (write_config_safe) and note the twoyq -icaveats (a replaced value keeps its old tag; blank separator lines are dropped).
- OpenChamber updated to 1.14.0 — bumped the pinned
@openchamber/webpackage and promoted the Home Assistant ingress patch updates validated in beta 2.3.2b0-2.3.2b1. The ingress patcher now also handles OpenChamber 1.14.0's newer Vite modulepreload helper, preventing dynamic asset and stylesheet requests from escaping to root/assets/...under Home Assistant Ingress.
- Configuration UI polish — options in the Configuration tab are now grouped and ordered by how you use them: interface mode first, then terminal appearance, Home Assistant integration, OpenCode runtime, Zigbee2MQTT/serial devices, PPQ private mode, LAN server, and advanced options last. Labels follow Home Assistant's sentence-case convention with consistent naming for toggles, and descriptions use one consistent style for quoting and punctuation. The previously undocumented Home Assistant access token option now has a proper entry in the documentation. No option keys or default values changed — existing configurations are unaffected.
- OpenChamber web UI — new Interface Mode option (
terminal/openchamber). The defaultterminalkeeps the existing ttyd terminal unchanged;openchamberserves the OpenChamber web UI (pinned@openchamber/web1.13.9) through Home Assistant Ingress on the same sidebar entry. OpenChamber binds to127.0.0.1inside the container behind a first-party ingress proxy, no LAN port is exposed, and Home Assistant Ingress provides the browser authentication layer. The bundle is patched at image build time so assets, API calls, SSE, and websockets resolve correctly under/api/hassio_ingress/.... Promoted from the beta channel after validation through beta 2.3.0b0–2.3.0b8.
- Home Assistant native LLM readiness — added a read-only
get_agent_capabilitiesMCP tool andha://agent/capabilitiesresource that report OpenCode's MCP surface, current HA version, and whether the running Home Assistant instance exposes the emerging nativellmcomponent. Documentation now explains the long-term plan: follow HA's LLM platform closely, prefer native capabilities when they become stable and accessible, and keep MCP for add-on/admin/dev/safety workflows. - MCP 2025-11-25 alignment — updated the MCP TypeScript SDK target to the current
1.29.xline, added server implementation description metadata, and tightened tool schemas withadditionalProperties: falseper current MCP guidance. - Compact MCP outputs — added server-local compatibility helpers that keep newer MCP fields out of tool responses while returning machine-readable
summary/data/metaJSON as text for OpenCode. Large state, history, logbook, docs, changelog, CLI, and ESPHome log responses are capped with truncation metadata instead of unbounded dumps. - Terminal and runtime hardening —
SUPERVISOR_TOKENis no longer persisted asHA_TOKENin/data/.env_vars, OpenCode uses an app-managed executable temp directory for native TUI files, and the web terminal now translates one-finger touch drags into scroll events for mobile/tablet use. - OpenCode runtime update policy — added a
latest/bundledupdate policy. By default the add-on installsopencode-ai@latestinto persistent add-on data and uses that before the bundled fallback, whilebundleddisables OpenCode self-update and uses the image version only. Baseline CPU mode now logs VM CPU passthrough guidance and the known upstream baseline OOM issue.
- PPQ private TEE models (beta) — added an opt-in internal PPQ private-mode proxy, pinned at image build time, with a masked PPQ API key option and an OpenCode custom provider for PPQ private models. This feature ships in the stable add-on, but should still be considered beta while provider behavior and proxy integration are validated.
- Faster startup and lower resource use — OpenCode service startup no longer waits on ESPHome/Zigbee2MQTT discovery, AGENTS.md guidance only refreshes after add-on updates, environment variables are processed in a single pass, the baseline x64 OpenCode binary is preinstalled for non-AVX2 systems, and
puppeteer-coreloads only when screenshots are used. - More responsive MCP and YAML LSP — added API/documentation fetch timeouts, short-lived caches, failed-fetch backoff, concurrent template validation, WebSocket registry calls, compact large responses, lazy YAML completion docs, debounced diagnostics, and stale diagnostic cancellation.
- Web terminal clipboard fixes — copying inside OpenCode now reaches the browser clipboard through OSC 52/tmux/ttyd support, plain HTTP shows a one-click copy fallback, plain
Ctrl+Vpaste works, and macOS users can useOption+dragto select text while full-screen terminal apps capture the mouse. - Multi-arch release and CI improvements — stable/beta images now use Home Assistant's generic multi-arch image style and Debian base image, release image assets are attached to GitHub releases, GitHub Actions are Node 24-ready, and aarch64 builds run on native ARM runners.
- Fixes — corrected the
get_error_logAPI path, restored YAML LSP service hover, prevented edits in one file from cancelling another file's diagnostics, and fixed release image asset uploads.
- Optional LAN server mode — added an opt-in setting that starts an OpenCode server on fixed internal port
4096, with Home Assistant Network settings controlling any host port mapping. This allows remote clients to connect withopencode attachwhen the port is explicitly mapped. Thanks to @benwestrate for contributing this feature. - Masked access token field — the Home Assistant access token option now uses a password-style configuration field in the add-on UI.
- Opt-in serial device access — added a
serial_devicesoption that lets users map selected host UART/serial devices into the add-on for USB flashing and adapter inspection workflows. Supervisoruartandudevmanifest flags remain disabled by default because they are static permissions, not runtime user options.
- Reduce memory and disk pressure by disabling OpenCode snapshots by default and ignoring noisy Home Assistant internal paths in OpenCode's file watcher.
- Improve Zigbee2MQTT URL configuration by documenting the required
http://orhttps://scheme and automatically treating host/IP-onlyz2m_urlvalues ashttp://. - Add Home Assistant add-on development folder access by mounting
/addonsand/addon_configs, with an opt-in guidance setting and security warnings.
- Pin hab CLI to
1.6.4— the add-on image previously built thehabCLI from whatever commit happened to be onmainat build time, which made builds non-reproducible and exposed users to unreviewed upstream changes. The Dockerfile now clones a specific release tag via a newHAB_VERSIONbuild arg. - Update monitoring workflow —
.github/workflows/check-hab-update.yamlnow compares the pinnedHAB_VERSIONagainst the latest upstream GitHub release and flags drift in the job summary, instead of reporting the latestmaincommit.
- New zigporter integration - adds zigporter CLI tooling to the add-on for Zigbee migration and device management workflows, including a new
zigporter_runMCP tool - Z2M discovery and configuration support - startup now supports Zigbee2MQTT discovery plus optional
z2m_urlandz2m_mqtt_topicconfiguration for zigporter commands - Fix
screenshot_urltimeouts - switched navigation wait strategy fromnetworkidle0toloadto avoid Home Assistant's persistent WebSocket causing guaranteed timeouts - Fix optional Z2M URL handling -
z2m_urlnow allows empty values so users are not blocked by validation when Zigbee2MQTT is not configured - Zigporter build behavior update - zigporter is now installed as latest at image build time rather than pinning a fixed version
Improved LLM context documentation to cover all hab CLI commands added in 1.7.1.
- Fixed JSON/text flag documentation —
--jsonenables structured JSON output; text is the default. The previous docs had this inverted, which would cause errors for any agent following them. - Added missing command groups to AGENTS.md, INSTRUCTIONS.md, and the
hab_runtool description:scene,person,category,todo,notification,integration,repairs,event,template,entity logbook, andoverview— none of which were previously visible to the LLM - Added concrete examples for every new command group in INSTRUCTIONS.md so agents know how to invoke them correctly
This release rebuilds the container to pick up significant upstream improvements to the hab CLI (balloob/home-assistant-build-cli).
New command groups
todo— manage to-do lists and items (list, add, complete, uncomplete, update, remove)notification— list, create, and dismiss persistent notificationscalendar— create and delete timed or all-day calendar eventsintegration— list, get, reload, enable, and disable config entriesevent— list event types and fire custom events (JSON/YAML/file input supported)repairs— list HA repair issues with severity filtering; ignore/unignorescene— full CRUD plusactivatewith--transitionsupportperson— full CRUD with device tracker and user ID supportcategory— full CRUD with scope inference from entity ID prefix; assign/removetemplate— render Jinja2 templates inline, from--file, or stdinentity logbook— read logbook entries with--start/--endfilters
Performance improvements
- Entity list, overview, and automation list
--extendednow fire all API calls concurrently, reducing wall-clock time from multiple sequential round-trips to approximately one - ESPHome
GetDevicesandGetPingcalls parallelised - CLI internals optimised: cached auth with
sync.Once, atomic WebSocket message IDs, pre-allocated slices, zero-copy format detection
ESPHome ingress fix
- New
HAB_ESPHOME_TOKEN,HAB_ESPHOME_SESSION, andHA_ACCESS_TOKENenv var overrides for ESPHome access through HA Core's ingress proxy (required since ESPHome ~2026.2.x in addon containers)
- New
screenshot_urlMCP tool — takes screenshots of any Home Assistant frontend page using headless Chromium, enabling AI models with vision capabilities to visually verify dashboard changes, card layouts, and UI modifications - Three-layer authentication — uses localStorage token injection, WebSocket auth interception, and HTTP request header injection to reliably authenticate with the HA frontend regardless of version
- Opt-in via configuration — disabled by default to keep resource usage minimal. Enable via the
screenshot_enabledoption in the add-on Configuration tab - Requires Long-Lived Access Token — uses the same
access_tokenoption already available for ESPHome tools to authenticate with the HA frontend - Configurable viewport — supports custom width, height, render wait time, and full-page capture
- HA Core URL auto-discovery — extracted into a reusable
discoverHACoreUrl()function shared with the ESPHome ingress discovery logic - Chromium and puppeteer-core added to the container image
- 34 tools (was 33) —
screenshot_urladded to the tool set - MCP server version bumped to v2.7.0
- New
createImageContenthelper inlib/helpers.jsfor building MCP image content objects
- New
devbranch for beta development — beta releases are now tagged and built fromdev, stable releases frommain - Beta release workflow now syncs the entire
ha_opencode_beta/directory (config, translations, changelog, docs) from dev to main automatically
- Clear error when ESPHome tools are used without an access token — previously produced a cryptic 500 error; now shows step-by-step setup instructions in the MCP tools, the
hab_rungateway, and the shell (#16)
Addresses #14 — configuration.yaml could be overwritten when the AI wrote only a single integration without reading the existing file.
- Top-level key preservation — for mapping-based YAML files (e.g.
configuration.yaml),write_config_safenow blocks any write that would remove existing top-level keys - Significant size reduction guard — writes that would reduce any config file by more than 50% (by line count) are blocked
- List-entry reduction (existing) — protection for
automations.yaml,scripts.yaml, andscenes.yamlremains, now integrated into the unified content protection system - All three checks can be bypassed with
confirm_deletions: truefor intentional removals .bakfiles are now retained after successful writes as a recovery point
- 102 unit tests added across MCP server (66 tests) and LSP server (36 tests) using vitest
- Pure functions extracted into testable
lib/modules:- MCP:
intelligence.js,validation.js,html-parser.js,helpers.js - LSP:
yaml-analyzer.js,completions.js
- MCP:
- Test files excluded from Docker image via
.dockerignore
- watch_firmware_update:
callApi()→callHA()— was calling a non-existent function, causing firmware update monitoring to crash at runtime - LSP YAML context analyzer:
currentIndent === prevIndent→currentIndent = prevIndent— no-op comparison fixed to assignment, restoring correct parent key detection in nested YAML
- Removed: Web UI mode — the experimental
ui_mode: weboption has been removed (never promoted to stable). TUI mode remains the only UI - nginx removed from container image (reduces image size)
ESPHome Connectivity Fix + hab CLI Shell Support
ESPHome 2026.2+ moved its dashboard to a Unix socket behind nginx with IP-based access rules, breaking direct connections from addon containers. This release routes all ESPHome communication through HA Core's ingress proxy, restoring full functionality for both MCP tools and the hab CLI.
- All ESPHome MCP tools working again —
esphome_list_devices,esphome_compile, andesphome_uploadnow route through HA Core's ingress proxy instead of connecting directly to the ESPHome container - hab CLI ESPHome commands working from shell —
hab esphome list,hab esphome logs, etc. now work when run directly from the terminal, not just through the MCPhab_runtool - New
access_tokenconfiguration option — a long-lived HA Core access token is required for ESPHome ingress authentication. Create one at Profile → Long-Lived Access Tokens in the HA UI and paste it into the addon's Configuration tab. Only needed if you use ESPHome tools - Automatic HA Core URL discovery — the addon auto-discovers your HA instance URL from
internal_urlin Settings → System → Network, with automatic fallback to network interface detection if the URL is set to "automatic" - WebSocket ingress session creation — ingress sessions are created via HA Core's WebSocket API (the only method accepted by the Supervisor), using the long-lived access token for authentication
- New
discover-esphome.jsstartup script runs the same 5-step discovery flow as the MCP server (find addon → get ingress entry → resolve HA Core URL → create WebSocket session → build URL) and writesHAB_ESPHOME_URLandHAB_ESPHOME_SESSIONto the environment sohab esphomecommands work from the shell - Discovery is best-effort at addon startup — if ESPHome is not installed, not running, or the access token is missing, it skips silently
- Bumped
hassio_roletomanager— required for ingress session creation via the Supervisor API - Safer automation editing in AGENTS.md — AI instructions now require reading all existing automations before writing to
automations.yaml, preventing accidental overwrites - Beta channel infrastructure — added
ha_opencode_betaaddon directory and CI workflows for beta releases, enabling faster testing of experimental changes
hab CLI from Source + Debian Trixie Base Image
- Upgraded base image to Debian Trixie — migrated from
bookworm(Debian 12) totrixie(Debian 13), bringing Node.js 18 → 20, git 2.39 → 2.47, glibc 2.36 → 2.41, and newer versions of jq, curl, and tmux - hab CLI built from source — hab is now compiled from the main branch at each add-on release via a multi-stage Docker build, replacing the previous pinned release binary. This ensures the latest features and fixes are always included without waiting for upstream releases
- Removed daily/weekly release-tracking workflows — the automated version-bump PRs (
update-hab-cli.yaml,check-hab-update.yaml) have been replaced with a lightweight weekly status check that reports the latest commit on main
hab CLI: Automated Update Tracking + Live Command Discovery
- Automated hab update detection — new weekly GitHub Actions workflow checks for new hab CLI releases every Monday and opens a pull request automatically, keeping the version pins in
build.yamlandDockerfilein sync. Can also be triggered manually from the Actions tab. - Dynamic hab help injection — at container startup,
hab --helpoutput is injected live intoAGENTS.mdbetween sentinel markers, so the AI always sees the exact commands available in the installed hab version — no manual documentation update needed when hab gains new features - Note for users who saw missing icons after the 1.5.2 repo rename: a standard update is not sufficient to restore them — uninstall and reinstall the add-on once to refresh the Supervisor icon cache
Rename: GitHub repository ha_opencode -> opencode
- Renamed GitHub repository from
magnusoverli/ha_opencodetomagnusoverli/opencode - All old URLs auto-redirect via GitHub — no action needed for existing users
- Updated all repository URL references across config, docs, CI, and README
- Reverted the directory rename from v1.5.1 — add-on directory must match slug for icon/logo discovery
Fix: Restore add-on logo in Home Assistant update notifications
- Reverted directory rename (
opencode/back toha_opencode/) — HA Supervisor requires the directory name to match the add-on slug for icon/logo discovery
Renamed to OpenCode + hab CLI Integration
Based on feedback from @balloob:
- Renamed from "HA OpenCode" to "OpenCode" across all user-facing surfaces (sidebar panel, add-on store, logs, banner, docs, build labels)
- MCP enabled by default — the Home Assistant MCP integration is now on out of the box, no manual toggle needed
- Integrated hab CLI (Home Assistant Builder v1.4.0) — a CLI by balloob designed for AI agents to manage HA via REST and WebSocket APIs
- Installed as a pre-authenticated binary (amd64 + aarch64)
- Exposed as a native MCP tool (
hab_run) so the AI discovers it alongside existing tools — no bash guesswork needed - Covers dashboard CRUD, area/floor/zone/label management, helper creation, automation management via API, script management, backup/restore, blueprints, calendar, device management, groups, and search
- Security: uses
execFile(no shell injection), blocks auth/self-update commands
- AGENTS.md auto-update — on add-on update, AGENTS.md is refreshed with the latest AI instructions unless the user has customized it
- Available in the shell help after exiting OpenCode (
hab <cmd>) - MCP tool count: 32 → 33
Fix: write_config_safe now blocks writes when HA config check is unavailable
write_config_safepreviously treated a failed HA config check API call as a success, leaving unvalidated config on disk. The tool now restores the original file (or removes the newly written file) whenever the validation result is anything other than an explicit"valid"from HA Core — including when the check API is unreachable or returns an error.- Removed overreaching "will never fail to start" guarantees from documentation and agent instructions. Claims now accurately reference the multi-layered guardrails (deprecation scanning, Jinja2 pre-validation, structural checks, backup/restore, HA Core config check) rather than making absolute promises.
- Expanded DOCS.md to cover
env_vars,cpu_mode, andopencode_configconfiguration options.
Feature: User-Defined Environment Variables
- Added
env_varsconfiguration option to pass custom environment variables into the container- Supports any key/value pair (e.g.
AZURE_RESOURCE_NAME,OPENAI_API_KEY) - Variables are available to OpenCode, the terminal shell, and all child processes
- Configurable from the add-on's Configuration tab in Home Assistant
- Supports any key/value pair (e.g.
- Security hardening:
- Variable names validated against strict shell identifier regex
- Critical system variables (
HOME,PATH,SUPERVISOR_TOKEN, etc.) are blocked from being overridden - Values are single-quote escaped to prevent shell injection
- File permissions set to 600 and excluded from backups to protect secrets
- Removed unused legacy
run.shentry point (dead code cleanup)
Closes #12
CI: Prevent redundant builds and fix release notes extraction
- Added
[skip ci]to the automated version bump commit in the release workflow, preventing unnecessary CI runs when the release bot pushes tomain - Fixed changelog extraction in release workflow — the
awkrange pattern was matching the section header as both start and end, producing empty release notes
Safe Config Writing & Multi-Layered Validation Pipeline
This release adds a comprehensive config validation system with multiple layers of protection against AI-written configuration causing your Home Assistant to fail to start. Inspired by community feedback on making AI coding agents safe for production HA instances.
- Writes YAML config files with automatic validation and backup/restore
- If validation fails after writing, the original file is automatically restored
- Supports
dry_runmode to pre-validate config without touching disk - Validates through multiple layers before committing:
- Deprecation pattern scanning (20+ patterns)
- Jinja2 template pre-validation through HA's own template engine
- Structural YAML checks (automations need triggers/actions, scripts need sequences, etc.)
- YAML lint checks (tabs, comma-separated entity lists, multiline issues)
- Full HA Core config check (
POST /config/core/check_config)
- Path traversal protection — blocks writes to internal directories (
.storage,.cloud, etc.)
- GitHub remote patterns — deprecation patterns are fetched from the repo hourly, allowing updates between add-on releases
- HA Repairs API — queries your installation's active repair/deprecation warnings via WebSocket (
repairs/list_issues) - HA Alerts feed — checks
alerts.home-assistant.iofor known integration issues affecting your config - All remote sources have timeouts, caching (1 hour TTL), and graceful fallback to bundled data
- The LSP server now surfaces deprecated syntax as yellow squigglies while editing YAML files
- Shares the same pattern database as the MCP server for consistency
- Also fetches updated patterns from GitHub in the background
- Extracted deprecation patterns from MCP server into a shared JSON file (
rootfs/opt/shared/deprecation-patterns.json) - Both MCP and LSP servers load from the same source
- Expanded from 10 to 20 patterns, adding coverage for:
- Legacy MQTT platform syntax (
platform: mqttunder domain keys) - Direct state object access (
states.sensor.x.state— usestates('sensor.x')) - Direct attribute access (
states.sensor.x.attributes— usestate_attr()) entity_idinsidedata:(should usetarget:)hassioservice domain (renamed tohomeassistant)- String format
for:durations (should use dict format) - Legacy
value_templatekey (modern template sensors usestate:)
- Legacy MQTT platform syntax (
INSTRUCTIONS.mdupdated with mandatorywrite_config_safeworkflowAGENTS.mdupdated with new tool references and deprecation guidance- MCP server version bumped to v2.6.0 (Safe Config Edition), tool count 31 → 32
Housekeeping: Licensing, CI, and Documentation
- Added missing
ws,prettier, and Home Assistant base image entries toTHIRD-PARTY-LICENSES.md, including the Apache-2.0 license text for the HA base image - Contributor mentions in the changelog are now linked directly to GitHub profiles
- Split CI build workflow into separate per-architecture jobs (
build-aarch64.yaml,build-amd64.yaml) to enable independent build status badges in the README - CI workflow runs now include the version number in their name for easier identification in the Actions tab
Bug Fix: ARM64 Initialization Failure + Documentation Overhaul
- Fixed OpenCode failing to start on ARM64 devices (e.g. Home Assistant Green) — ARM64 was incorrectly routed into
baselinemode even though no ARM64 baseline package exists, leaving the session with a non-existent binary path. ARM64 now correctly uses the regular OpenCode binary (reported by @timsteinberg and @wizzyto12, fixed by @Teeflo) - Fixed potential infinite exec loop in the OpenCode wrapper when
/usr/local/bin/opencodewas already a symlink from a previous run (fixed by @Teeflo) - Added safe fallback in
opencode-session.shfor the edge case where ARM64 baseline mode is manually forced via config (fixed by @Teeflo) - Revamped README with improved structure, clearer installation steps, and updated badges (contributed by @Teeflo)
- Corrected MCP tool count (22 → 31), resource count (9 → 13), and added go-to-definition to the LSP feature description to reflect the actual implementation
- Updated icon and logo assets (contributed by @Teeflo)
Bug Fix: ARM64 Baseline Binary Initialization (fixes #7)
- Fixed OpenCode failing to initialize on ARM64 devices (e.g. Home Assistant Green) when using the baseline binary
OPENCODE_BIN_PATHinopencode-session.shwas hardcoded to the x64 baseline path — now correctly resolves based on architecture
- Added proper ARM64 detection in CPU capability check, skipping the irrelevant x86 AVX flag inspection
- Fixed potential infinite exec loop in the OpenCode wrapper fallback path
- Thanks to @timsteinberg and @Teeflo for reporting!
Re-tagged release to include the changelog in the published image (1.3.0–1.3.3 were built before the changelog was finalized).
Architecture Refactor, CPU Compatibility, and Bug Fixes
- Refactored s6 service architecture: initialization logic (directory setup, config generation, file deployment) now runs once in a dedicated
init-opencodeoneshot service, keeping the ttyd long-running service clean and focused - Added CPU baseline detection for older processors without AVX2 support — the add-on now auto-detects CPU capabilities and selects the appropriate OpenCode binary (configurable via
cpu_mode: auto/baseline/regular) - Added custom OpenCode configuration injection — power users can now paste a JSON config in the add-on settings to customize OpenCode behavior (providers, keybindings, etc.)
- Fixed MCP
get_error_logtool returning 404 errors by routing through the correct Supervisor proxy endpoint (/core/api/error_log) - Fixed init-opencode oneshot service failing to execute (absolute path in
upfile) - Fixed CPU auto-detection crashing on base image (replaced
grep -oPwith portableawk) - Terminal banner now displays the actual add-on version instead of hardcoded "v1.0"
Inspired by work done in okliam's fork. Thanks for exploring these ideas!
New Feature: Prettier YAML Formatter + Comprehensive Style Guide
- Added Prettier formatter for automatic YAML formatting aligned with Home Assistant conventions
- Installed globally in container and auto-configured for
.yaml/.ymlfiles - Deploys
.prettierrc.yamlto/homeassistant/on first install (user-customizable) - Added comprehensive YAML Style Guide section to AGENTS.md covering all 13 official HA YAML formatting rules
- Style guide includes good/bad examples for each rule and marks rules Prettier cannot enforce
- AI agents now have explicit, inline guidance to write HA-compliant YAML on every change
- Reference: https://developers.home-assistant.io/docs/documenting/yaml-style-guide/
Bug Fix: Multiple OpenCode Instances Spawning (fixes #4)
- Fixed container health check failing due to missing
pgrep(addedprocpspackage) - Added
tmuxfor session persistence — reconnecting now reattaches to the existing session instead of spawning a new OpenCode instance - Prevents orphaned OpenCode processes from accumulating and consuming memory on resource-constrained devices (e.g. Raspberry Pi)
Bug Fix: watch_firmware_update Timeout
- Fixed
watch_firmware_updatetool timing out before returning results - Tool now returns immediately with current status instead of blocking
- Call the tool repeatedly to monitor progress (AI can poll as needed)
- Removed unused
poll_intervalandtimeoutparameters
Bug Fix: Update Tools Not Available
- Fixed critical bug where update management and ESPHome tools were defined in the wrong array
- Tools
watch_firmware_update,get_available_updates,update_component,get_update_progress,get_running_jobs, and ESPHome tools are now properly exposed - AI assistants can now use these tools for firmware and system updates
Documentation: Update Management Instructions
- Added update management section to INSTRUCTIONS.md and AGENTS.md
- AI assistants now properly use
watch_firmware_updatefor device updates - Documented
get_available_updates,update_component, andget_update_progresstools - Added example patterns for firmware and system updates
Build Fix: Prevent Update Race Condition
- Fixed timing issue where updates appeared in Home Assistant before images were built
- Workflow now triggers on tag push instead of release creation
- Version in config.yaml is automatically updated after images are successfully pushed
- GitHub release is created automatically after build completes
New Feature: Visual Firmware Update Monitoring
- Added
watch_firmware_updateMCP tool for real-time update monitoring (MCP server v2.5)- Beautiful visual timeline with timestamps and status icons
- Tracks progress from initiation through reboot to completion
- Works with ESPHome, WLED, Zigbee coordinators, and any Home Assistant update entity
- Automatic progress bar when device reports percentage
- Optional
start_updateparameter to initiate update before monitoring - Configurable
poll_interval(1-30s) andtimeout(1-30min) - Clear success/failure summary with version change display
- Troubleshooting tips on failure
Infrastructure: Pre-built Docker Images
- Add-on now uses pre-built Docker images from GitHub Container Registry
- Update progress now visible in Home Assistant UI
- Significantly faster updates (no local build required)
- Images built automatically via GitHub Actions on each release
- Added CI/CD workflow for multi-architecture builds (amd64, aarch64)
- Existing users automatically migrate on update - no manual steps required
New Feature: ESPHome Integration
- Added 3 new MCP tools for ESPHome device management (MCP server v2.4)
esphome_list_devices- List all configured ESPHome devices with version infoesphome_compile- Compile firmware with full build log outputesphome_upload- Flash firmware to devices via OTA or USB
- Real-time build log streaming via WebSocket connection to ESPHome add-on
- Auto-discovery of ESPHome add-on via Supervisor API
- Added
wsWebSocket dependency for ESPHome communication - Graceful error handling when ESPHome is not installed or not running
- Build log truncation for large outputs (>300 lines)
- Helpful troubleshooting tips included on compile/upload failures
New Feature: Update Management
- Added 5 new MCP tools for managing Home Assistant updates (MCP server v2.3)
get_available_updates- Check for updates across Core, OS, Supervisor, and appsget_addon_changelog- View app changelogs before updatingupdate_component- Initiate updates with optional backupget_update_progress- Real-time progress monitoring with visual feedbackget_running_jobs- List all Supervisor jobs (updates, backups, restores)
- Added
callSupervisor()API wrapper for direct Supervisor API access - Safety guard prevents self-update from within the container (use HA UI instead)
Build Improvements
- Improved Dockerfile for best practices and performance
- Use dynamic BUILD_VERSION label instead of hardcoded version
- Add configurable OPENCODE_VERSION arg for reproducible builds
- Fix parallel npm install with proper subshell syntax
- Replace deprecated
--productionflag with modern--omit=dev - Remove npm audit suppression for better security visibility
- Consolidate ENV and RUN layers for efficiency
- Add .dockerignore to exclude unnecessary files from build context
- Fixed license in build.yaml (MIT → Unlicense)
Terminology Update
- Renamed "add-on" to "app" throughout the project to align with Home Assistant 2026.1 rebranding
- Home Assistant now calls add-ons "apps" to better reflect that they are standalone applications running alongside Home Assistant
- Updated all documentation, comments, and user-facing strings
Bug Fixes
- Fixed font rendering issues in web terminal (fixes #1)
- Removed explicit fontFamily configuration from ttyd
- Browser now uses default monospace font, avoiding letter-spacing issues when specified fonts aren't installed
- Thanks to @pixeye33 for reporting!
- Fixed invalid JSON Schema for call_service MCP tool (fixes #2)
- Updated target properties (entity_id, area_id, device_id) to use
oneOfwith properitemsdefinition for array types - AI model APIs (OpenAI, Anthropic) now accept the schema without validation errors
- Thanks to @Teeflo for the detailed bug report!
- Updated target properties (entity_id, area_id, device_id) to use
Bug Fixes
- Fixed MCP server API endpoint access
- Added
callHACore()function for direct Home Assistant Core API access - Fixed
get_error_logto use correct endpoint (/api/error_logvia Core API) - Some endpoints are not available via Supervisor proxy and require direct Core API access
- Added
- Improved device discovery in
get_devicestool- More reliable device listing by iterating through all entity states
- Ensures all devices are discovered, including those missed by filter-based approaches
Bug Fixes
- Fixed MCP server Jinja2 template bugs
- Fixed
get_areastemplate to usenamespace()for proper list accumulation - Fixed
get_devicesto return device attributes (name, manufacturer, model, area) - Fixed
get_error_logendpoint from/error_logto/error/all - Fixed
ha://areasresource template with namespace() fix
- Fixed
MCP Server Enhancements
- Added documentation tools to MCP server v2.2 (Documentation Edition)
get_integration_docs- Fetch live documentation from Home Assistant websiteget_breaking_changes- Check for breaking changes by version/integrationcheck_config_syntax- Validate YAML for deprecated patterns- Implemented HTML parsing and content extraction from HA documentation pages
- Added deprecation pattern database for common configuration issues
- LLMs now guided to always verify syntax against current docs before writing config
- Enhanced AGENTS.md with Home Assistant interaction guidelines
- Added Home Assistant Interaction Model section
- Added RESTRICTED section listing internal directories that should never be accessed
- Provided guidance on when to use configuration files vs MCP tools
All notable changes to this project will be documented in this file.
UI Improvements
- Updated app icon and logo images
New Feature
- Added AGENTS.md customization feature
- Default AGENTS.md file deployed to Home Assistant config directory on first install
- Contains AI instructions and rules for OpenCode behavior
- Users can customize AGENTS.md to add their own rules, preferences, and context
- Edit
/config/AGENTS.mdusing File Editor or any text editor - Includes user consent rules, Home Assistant knowledge, safety guidelines, and MCP awareness
Documentation
- Added LICENSE file (MIT License)
- Added repository README.md with installation instructions
- Cleaned up CHANGELOG to match repository history
Improvements
- Optimized Docker build process with better layer caching
- Copy package.json files first to preserve npm install cache
- Install MCP and LSP dependencies in parallel for faster builds
- Code changes no longer invalidate dependency installation cache
- Simplified configuration script
- Combined MCP and LSP configuration into single operation
- Streamlined logging output
- Improved startup experience
- Removed unnecessary delay before launching OpenCode
Initial Release
- OpenCode AI coding agent for Home Assistant
- Web terminal with ingress support
- Access to your configuration directory
ha-logscommand for viewing system logs- MCP server for AI assistant integration (experimental)
ha-mcpcommand to manage MCP integration- Support for 75+ AI providers
- Home Assistant LSP (Language Server) for intelligent YAML editing
- Entity ID autocomplete
- Service autocomplete
- Hover information for entities and services
- Diagnostics for unknown entities/services
- Go-to-definition for !include and !secret references