mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-08-20 03:47:20 +02:00
55 KiB
55 KiB
07308545 (2026-08-15)
- Update to latest version from aaddrick/claude-desktop-debian (changelog : https://github.com/aaddrick/claude-desktop-debian/releases)
- Upstream tag : v3.2.2+claude1.30096.1
07308544 (2026-08-13)
- Update to latest version from aaddrick/claude-desktop-debian (changelog : https://github.com/aaddrick/claude-desktop-debian/releases)
- Upstream tag : v3.2.2+claude1.28929.0
07308543 (2026-08-08)
- Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases)
- Upstream tag : debiantrixie-version-07308543
2026.08.04 (04-08-2026)
- Fix: reverted the GPU acceleration added in 2026.08.03. It did not just fail to help — it was
what disabled the GPU.
--use-gl=angle --use-angle=gl-eglforces Mesa's EGL X11 platform, which offers no window-capable EGLConfig under this Xvfb, so the GPU process loggedgl_surface_egl.cc:262 No suitable EGL configs found, abandoned GL, and was relaunched with--use-gl=disabledwhile every renderer got--disable-gpu-compositing. Chromium already renders on the GPU here with no flags at all, because LSIO's Xvfb runs with-vfbdevice /dev/dri/renderD128and its GLX is therefore backed by the real render node — the premise that Xvfb offers only a software path was wrong for this base image. Measured three times, including at the production 15360x8640 screen: with the flags the GPU process loadslibEGL_mesaand holds 1 fd on the render node; without them it loadslibGLX_mesa, holds 8, and no renderer carries--disable-gpu-compositing. Removesclaude-gpu-probeand thegpu_accelerationoption. The probe was not wrong about the hardware, it was answering the wrong question: it exercised ANGLE's default GLX path, which works, and so it passed while the flags it gated disabled the GPU. - Fix:
max_resolutionnever did anything; the option is renamed toMAX_RES. It wroteMAX_RESinto the s6container_environment, but the base image'ssvc-xorgstarts#!/usr/bin/env bashiorather thanwith-contenvand never reads that directory, so Xvfb kept starting at 15360x8640. Naming the optionMAX_RESmakes the add-on env layer inject it directly into every servicerunscript, which is howDRINODEalready reaches Xvfb.MAX_RESships with no default, so nothing changes for anyone until it is set: the screen stays at the base image's 15360x8640. The oldmax_resolutiondefault of1920x1080is deliberately not carried over — it had never taken effect, so shipping it now would have silently shrunk every existing desktop, including on 4K displays. Home Assistant drops options that are no longer in the schema (it logs a warning), so a savedmax_resolutionis discarded rather than migrated. The schema bounds each axis to 100-9999, which keeps the worst case (~400 MB of framebuffer) below the 15360x8640 default it replaces. Removes22-display_tuning.sh. - Removed the amd64 GPU driver install, which has never run in any release. The 2026.08.03
build corrected its gate variable but the guard is
if [[ ... ]]and there is noSHELLdirective, so it runs under dash, which has no[[— the condition was false and theRUNstill exited 0. Verified in the shipped 2026.08.03 image: novainfo, nointel-media-va-driver-non-free, and no matching install in its apt history. It was deleted rather than repaired, because it had nothing to add. Hardware OpenGL already works without it: the GPU process loads the Mesa gallium megadriver over DRI3 and holds 8 fds on/dev/dri/renderD128, with no swrast/llvmpipe in the GL path.libgl1-mesa-driandmesa-vulkan-driversalready come from the LSIO base at a newer backports version (Mesa 25.0.7) than reinstalling them would give. Andintel-media-va-driver-non-free, the one genuinely new payload, was installed live on the running add-on and changed nothing: VA-API failed identically to the free driver (iHD_drv_video.so init failed) on both/dev/dri/renderD128andcard0. That failure is below the add-on, in the host i915 stack. Repairing the guard would have turned dead code into an untested apt transaction that swaps a base-image package for no measured benefit. - A
[[in the Dockerfile's legacy/etc/services.dshim is corrected to[for the same dash reason; that directory does not exist on this s6-overlay v3 base, so it is behaviour-neutral here.
2026.08.03 (03-08-2026)
- Performance: Claude Desktop now uses the GPU instead of rendering on the CPU.
Under Xvfb, Chromium probed GLX, found only Xvfb's software path, and fell back to
--use-gl=disabled+--disable-gpu-compositing, making the renderer the add-on's largest CPU consumer. It is now launched with--ozone-platform=x11 --use-gl=angle --use-angle=gl-egl, but only when the newclaude-gpu-probeconfirms Claude Desktop's own bundled ANGLE can create a hardware GL context on this host. Newgpu_accelerationoption (auto/on/off, defaultauto); any probe failure keeps the previous software rendering unchanged. - Performance: new
max_resolutionoption (default1920x1080) caps the virtual screen via the base image'sMAX_RES. Xvfb previously ran at 15360x8640, so Xvfb and the Selkies capture loop tracked damage over a 133-megapixel area continuously, even with no browser connected. Selkies still resizes dynamically below the cap. - Performance: Claude Code now talks to the Home Assistant MCP server over its native HTTP
transport instead of through the
mcp-proxystdio bridge, removing one Python process per Claude Code session (~45 MB of private resident memory each). Claude Desktop keeps the bridge, as the config schema for a remote entry there is not confirmed. - Performance: new
mcp_servers_desktop/mcp_servers_codeoptions select which MCP servers each client registers. Every stdio MCP server is a separate process per client, and Desktop starts another full set per Claude Code session it hosts. Defaults register all of them in both clients, i.e. the previous behaviour. - Fix: the Dockerfile's Intel graphics block was dead code. It was gated on
TARGETARCH, which the repo's builder does not pass, so it never ran: the shipped amd64 image has novainfoand nointel-media-va-driver-non-free. It now usesBUILD_ARCH, and its Vulkan ICD check no longer namesintel_icd.x86_64.json, a file Debian does not ship. - Fix: stale Home Assistant MCP registrations (and the bearer token in them) are now removed
from Claude Code's config when
enable_ha_mcpis turned off. Ownership of an HTTP entry is recorded when the add-on writes it, so a manually configuredhomeassistantserver is never claimed, overwritten, or deleted — not even when it sits on the default URL. --disable-dev-shm-usageis now applied only when/dev/shmis actually small (under 256 MB). It is a workaround for Docker's 64 MB default, but Home Assistant ignores the add-on'sshm_sizeso the real size varies per install; the size is now read at startup, keeping the crash workaround where it is needed and dropping it where it only pushed Chromium's shared memory into ordinary files. If the size cannot be determined, the flag is kept.
2026.08.02 (02-08-2026)
- Minor bugs fixed
ubunturesolute-version-3a10bef7 (2026-08-01)
- Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases)
kali-version-e963b19b (2026-08-01)
- Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases)
1.37 (28-07-2026)
- Fix the recurring "For your security, sign in again to keep using Claude." prompt for real. The v1.35 fix was ineffective:
--password-store=basicwas reaching the process (confirmed on a live install's/proc/<pid>/cmdline), yet the app kept loggingsafeStorage not available, tokens will not persistandEncryption not available, returning empty env varson every launch. The missing half is an application-side opt-in — Electron refuses its built-inbasic_textbackend unless the app callssafeStorage.setUsePlainTextEncryption(true)beforeready, and Claude Desktop never calls it (the symbol is present in the Electron binary but absent fromresources/app.asar). SoisEncryptionAvailable()stayedfalseand the auth token was never persisted, exactly as when the keyring backend was forced without a keyring daemon. Verified against a standalone Electron of the same generation: with--password-store=basicand no opt-inisEncryptionAvailable()isfalse; with the opt-in it istrue, and a separate later process decrypts a blob written by an earlier one — which is the restart survival this add-on needs.- The patch (
86-claude_safestorage.sh+claude-safestorage-patch.js, new). A small Node script injects that one opt-in call into the app's main bundle (.vite/build/index.pre.js) insideapp.asar. Insertion is placed after the bundle's leading"use strict";rather than before it, because a directive prologue only takes effect as the first statement — prepending ahead of it would silently drop the entire main process out of strict mode. The archive is rebuilt rather than edited in place, since an asar's header stores a byte offset and length per file: entries flaggedunpacked(which live inapp.asar.unpacked/, not in the archive body) and symlink entries are carried through untouched, so the native-module layout is preserved, and the per-file SHA-256integrityrecord is recomputed for the one file that changed. The injector fails closed: anything that does not open with an unambiguously terminated"use strict"directive is refused rather than patched by guesswork, since"use strict" + xis an expression and injecting into it would yield a syntax error. The rebuild is written to a temporary file,fsynced, and then fully re-validated from disk — entry count, every offset and length parsed as an exact in-bounds integer, the last body ending precisely at EOF, and the patched entry's recomputed SHA-256 — before it is renamed over the original and the directory synced; the temporary file is removed on every failure path. So a torn, truncated or short write can never replace a working archive. Verified byte-for-byte against the real archive: same 211 entries, nounpacked/symlink flag drift, no trailing slack, every integrity hash valid, and content differing in exactly one file. - Why it re-runs every boot.
81-claude_update.shapt-upgradesclaude-desktopon startup, and a new package ships a fresh, unpatchedapp.asar; a one-shot patch at image build time would therefore be undone by the first update. The script is marker-guarded, so a boot where the app did not change is a no-op, and it is numbered86-to land after both the update check and85-openbox_autostart.sh, while still completing before any s6 service — i.e. before the desktop launches the app. A failure is logged and swallowed rather than propagated, and the patcher is run under a 120stimeout: an unpatched app still runs, it just forgets the sign-in, which is not worth blocking startup over. The hook ends in an explicitexit 0so no logging branch can turn a non-fatal patch failure into a failed cont-init, and it sweeps stale temporary archives itself —timeoutkills the patcher outright, so the run that hits the cap cannot execute its own cleanup, and each stranded file is archive-sized. gnome-keyringstays out of the image. Re-adding it would reintroduce the first-boot keyring password prompt that blocks Claude Desktop from launching at all. This route needs no keyring, no D-Bus Secret Service, no daemon and no password, so no prompt can appear. The trade-off is unchanged from v1.35 and is inherent to thebasicbackend: its key is fixed rather than gated by a keyring, so any process that can read the persistent$HOME/.config/Claudeprofile can recover the stored credentials.- One-time step after upgrading. The previously stored session is already stale, so a single sign-in is still needed once after this update; it then persists across restarts.
- The patch (
1.36.4 (28-07-2026)
- Fix Selkies dying with a Rust
RuntimeDirNotSetunwrap panic just afterData WebSocket Server listening on port 8081, and the data websocket then being proxied to the wrong port. Upstream relies on s6-rc ordering:init-selkies-configpublishesXDG_RUNTIME_DIRandCUSTOM_WS_PORTinto the s6 envdir andsvc-selkiesstarts afterwards. The add-on entrypoint replaces s6-overlay and starts everys6-rc.drun script in parallel with no dependency graph, so Selkies can snapshot the envdir before that oneshot has written to it -- which is why it bound port 8081 (its own default) instead of the 8082 nginx proxies to, and why its Wayland compositor found no runtime directory to bind a socket in.20-folders.shnow exports both variables inside each run script, where no start ordering can lose them, and corrects the base image's$HOME/.XDGoverride where that write happens instead of appending a correction after theexit 0that the oneshot-tolerance block adds -- which meant the correction never ran on any boot after the first.
1.36.3 (28-07-2026)
- Make the Selkies startup scripts add-on agnostic so
webtopandwebtop_kdecan share them by symlink instead of carrying their own drifted copies.20-folders.shnow derives its default data location from the home directory the Dockerfile baked into theabcuser (getent passwd abc) rather than hardcoding/data/data, and thepermission_mode: bypassroot guard is skipped on add-ons that do not declare that option.80-configuration.shfalls back topipwhen the image does not shipuv. No behaviour change for Claude Desktop:getent passwd abcreturns/data/data, which is exactly the value that was hardcoded before.
1.36.2 (28-07-2026)
- Minor bugs fixed
1.36.1 (27-07-2026)
- Fix the Codex CLI install failing on every boot with
Verified Codex <version> installation failed; Codex is unavailable this boot, leavinginstall_codex_clipermanently non-functional. The download, its SHA-256 verification, and the extraction all succeeded; the chain broke at the final step, which validates the candidate binary by running--versionas theabcruntime user.mktemp -dcreates its directory0700 root:root, andabccannot traverse a root-only directory, so executing the staged binary failed withunable to exec: Permission denied(exit 126) before it could be moved into place. Reproduced and fixed by making the staging directory traversable (chmod 0755) immediately aftermktemp; verified on a live add-on container, where the same probe goes from exit 126 to success once the mode is widened. Nothing secret is staged there — the public release archive and the extracted binary, both world-readable upstream artifacts — and the existingcleanup()trap still removes the directory on exit. The validation deliberately keeps running asabcrather than root, so the binary is exercised as the identity that will actually run it.
1.36 (27-07-2026)
- Add optional OpenAI Codex CLI support, so a Claude session in this add-on can delegate work to ChatGPT Codex. Three parts: an
install_codex_cliswitch, a browserless way to activate a ChatGPT subscription on it, and an MCP registration that makes Codex callable as a tool from Claude.- Install (
install_codex_cli, default off). Codex is deliberately not baked into the image: the Linux release binary is ~310 MB extracted, which is not worth carrying in every installation for an off-by-default option, and updating it would then require an add-on rebuild. The new81-codex_cli.shcont-init script downloads the pinned static-musl release (ARG/ENV CODEX_VERSION, currently0.145.0) into/data/codex/binand symlinks it ontoPATH./datais the add-on's own persistent volume — independent of the configurabledata_location— so the ~113 MB download happens once, not per boot and not again after an add-on update unless the pinned release changes. The install prefix is outside$HOMEon purpose: the managed-MCP merge in82-claude_tools.shtreats any servercommandunder$HOMEas user-installed and refuses to manage it, so an add-on-owned binary living there could never be updated or removed by the add-on. The download fails open like the Claude Desktop update check — an offline boot, a GitHub outage or a bad pin logs a warning and leaves any existing binary in place instead of aborting startup, and the new binary is validated by actually running--versionfrom the staging directory before it replaces the current one, so a truncated download can never overwrite a working install. Staging deliberately happens under/datarather than the default/tmp:/tmpin this image is a RAM-backed tmpfs, so holding the 110 MB archive plus the 310 MB binary there during boot is a real risk on a small Home Assistant host, and it is mountednoexec, which would make the validation step impossible anyway. Staging on the destination filesystem also turns the final move into an atomic rename instead of a second 310 MB copy. Disabling the option is non-destructive: the binary and the completed sign-in are kept, so a disable/re-enable cycle needs neither another download nor another login. - Subscription activation (
codex-login). Codex's default sign-in serves an OAuth callback onlocalhost:1455and expects a local browser, which cannot work here — the image ships no browser, and the add-on is reached through Home Assistant ingress. The new/usr/local/bin/codex-loginhelper runscodex login --device-authinstead, the flow OpenAI documents for headless machines: it prints a verification URL and a short-lived one-time code to approve on any other device, then polls until done. It can be run from the desktop's xterm (openbox right-click menu), from a Claude Code session, or from the container console, and it drops to theabcruntime user first so~/.codex/auth.jsonis not created root-owned — the same failure mode83-github_cli.shdocuments for~/.gitconfig. Output is line-buffered so the URL and code appear immediately even without a TTY. If a session is already authenticated the helper reports the account and exits rather than starting a second flow. Credentials live in the persistent home, so the sign-in survives restarts and updates. - MCP bridge.
codex mcp-serverexposes Codex itself as a stdio MCP server (toolscodexandcodex-reply, verified by driving the 0.145.0 binary over stdio), which is registered through the existing managed-MCP merge in82-claude_tools.shrather than a second copy of that logic — so it inherits the merge's idempotence, its refusal to clobber a user-customized entry, its removal-when-disabled behaviour, and the0600re-tightening of the token-bearing config files. Registration covers both Claude Code (~/.claude.json) and Claude Desktop, so every session type gets the tool. A managedCLAUDE.mdblock tells Claude what Codex is and when a second agent is worth the round-trip, since registering a server without guidance rarely gets it used — the same gap the Headroom block exists to close. - Sandbox (
codex_sandbox_mode, defaultdanger-full-access). Codex normally confines itself with a Linux OS sandbox (Landlock, or its bundled bubblewrap), which is unreliable inside a Home Assistant add-on container — and the container is already the security boundary. The default therefore bypasses Codex's own sandbox;read-onlyandworkspace-writeremain selectable. The chosen mode is applied in two places that are kept in sync: as root-level-cconfig overrides in the MCP registration (Codex forwards those to the MCP server, and they must precede the subcommand), and as a managed block at the top of~/.codex/config.tomlso plain terminalcodex/codex execruns behave the same. That block is written at position 0 rather than appended, because a bare TOML key placed after a[table]header would silently become a key of that table.approval_policyis alwaysnever— an MCP- or cron-driven run has nobody to answer a prompt. Claude Code's own permission prompts still gate everymcp__codex__*call unlesspermission_modeisbypass. 84-claude_runtime_ownership.shnow also reconciles~/.codex, andclaude-tools-doctor.shreports the Codex binary, the installed-versus-pinned version, the two new switches, and the login status (which prints the auth mode, never the token).
- Install (
1.35 (23-07-2026)
- Fix recurring "For your security, sign in again to keep using Claude." and the Claude app's dispatch tab showing this desktop as offline when opened from mobile first. Root cause (confirmed from
~/.config/Claude/logs/main.logon a live install): the app launches with--password-store=gnome-libsecret, forcing Electron's libsecret/Secret-Service backend, butgnome-keyringwas removed from the image in a previous commit because it prompted for a keyring password on first boot and blocked the app from launching. With the flag still forcing libsecret and no keyring daemon running,safeStorage.isEncryptionAvailable()isfalse— logs showedsession will not persist; app secrets fall back to plaintextandcannot store allowlist cache. The un-persisted session then goes stale, failing the elevated-access OAuth check (session_stale_relogin) that the cowork/dispatch bridge needs, so the bridge is "parked until re-login" — which is what the Claude app surfaces as the desktop being offline, until a fresh sign-in (only completable from a computer, seeSIGN_IN.mdProblem A) un-parks it.rootfs/defaults/autostartnow launches with--password-store=basicinstead: Electron's built-in fixed-key store needs no daemon and never prompts, and persists under$HOME/.config/Claude(/data/data, persistent), so the session survives restarts and dispatch stays online regardless of which device connects first. A passwordless keyring was considered and rejected — it would live in the same persistent volume as the ciphertext, adding no real protection in this single-user self-hosted setup.Dockerfile's stale comment (still describing gnome-keyring as installed) is corrected; the package stays removed.- New
85-openbox_autostart.sh: the app is actually launched from the persistent$HOME/.config/openbox/autostart, which the base image'sinit-selkies-configoneshot only seeds from/defaults/autostartwhen the persistent copy is missing — so on any existing install, editing/defaults/autostartalone would never reach the file actually being run. This new cont-init script re-syncs the persistent copy from the image on every boot (as root, before any s6-rc service starts, so it also overwrites a copy a prior boot may have left root-owned/read-only underRESTART_APP), so the--password-storechange (and any future autostart change) reaches existing installs on upgrade, not just fresh ones. - One-time step after upgrading: the previously-stored session is already stale, so complete one sign-in from a computer (mobile cannot complete the OAuth flow in the streamed desktop, see
SIGN_IN.mdProblem A). The session then persists normally.
- New
- Fix
21-gpu_permissions.shfailing at boot (exiting 2) while working fine when re-run manually. Root cause: the script runs under bashio, which setsset -o pipefail, together with the script's ownset -e;getent group "$gid" | awk ...exits 2 whenever$gidhas no named group yet, which is the normal case here because this script deliberately runs before the base image'sinit-video/init-adduserhave named the passed-through/dev/drigids. That exit 2 aborted the script immediately, before reaching its own-z "$gname"fallback (written specifically to create adri<gid>group for exactly this unnamed case) — and, as a side effect, before thechmod o+rwfallback further down, so the boot-time GPU-permission hardening from 1.31 wasn't fully applied either. A manual re-run afterward always "worked" because by theninit-videohad already named the group. Fixed by not letting that expected exit propagate:gname="$(getent group "$gid" | awk -F: '{print $1}')" || gname="". The fallback now also distinguishes the expected exit 2 (unnamed GID) from any othergetentfailure, logging a warning instead of silently treating unrelated NSS/database errors the same way. SIGN_IN.mdnow states explicitly that thebasicpassword store trades away OS-backed at-rest protection for the persisted session.
1.34 (22-07-2026)
- Reduce idle and active remote-desktop overhead without changing Claude Desktop, Claude Code, GPU acceleration, Headroom, RTK, or TokenSave behavior. Selkies now defaults to 15 FPS instead of 30 FPS, uses browser-rendered cursors, and disables unused audio, microphone, gamepad, second-screen, and collaborative-sharing channels. All settings remain overridable through
env_varsfor installations that need those features. - Explicitly install and build-validate the Intel userspace graphics stack in the amd64 image for Intel N150/Twin Lake and other modern Intel iGPUs:
intel-media-va-driverfor VA-API encoding/decoding,libgl1-mesa-drifor the Mesa Iris OpenGL driver,mesa-vulkan-driversfor Intel Vulkan, andvainfofor runtime diagnostics. The host-providedi915kernel driver and existing/dev/dridevice mapping remain unchanged.
1.33 (22-07-2026)
- Add cowork virtualization support:
qemu-system-x86andovmf(Bookworm main, installed via apt) plusvirtiofsdfor sharing the workspace into the sandbox microVM.virtiofsdis only packaged for Debian trixie/sid, not Bookworm or bookworm-backports, and its trixie.deblinks a newer GLIBC than this add-on's Bookworm runtime — so it now gets built from the pinned crates.io release (1.14.0) in a dedicatedvirtiofsd-builderstage, the same GLIBC-safe pattern already used forrtkandtokensave. Its build deps (libseccomp-dev,libcap-ng-dev,pkg-config,clang,libclang-dev) live only in that builder stage; only the runtime shared libs (libseccomp2,libcap-ng0) ship in the final image. The built binary is validated with--versionat build time alongsidertk/tokensave, so a GLIBC/ABI mismatch fails the image build instead of surfacing at container start. Docker itself is deliberately not installed: this base image already ships Docker-in-Docker (docker-ce/containerd.iofrom Docker's own apt repo, started via the pre-existingSTART_DOCKERenv var) — an initial attempt to alsoapt-get install docker.iobroke the build, since Debian's package pulls incontainerd/runc, which apt refuses to install alongside the base image's already-installedcontainerd.io(Conflicts).
ubunturesolute-version-8208e985 (2026-07-21)
- Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases)
kali-version-9ad48e7a (2026-07-18)
- Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases)
1.32 (17-07-2026)
- Bump
tokensavefrom 7.2.0 to 7.4.0 (rtkwas already pinned to its current latest GitHub release,v0.43.0;headroom-aiis intentionally installed unpinned from PyPI, so it already tracks latest at every build and had nothing to bump). Reviewed the intervening 7.3.0/7.4.0 release notes against every tokensave surface this add-on drives (install --agent claude --git-hook yes,uninstall --agent claude,sync,init,doctor --agent claude,gain --all --range 30d, and themcp__tokensave__*tool set granted insettings.json): no flag, output shape, or MCP tool name used here changed. Directly relevant fixes carried along:tokensave syncauto-migrates a v12 database (missing the trait-dispatch caller cache) to v13 as a normal part of syncing, which the add-on's corruption-quarantine logic won't mistake for corruption since the schema migration doesn't produce a "malformed"/"not a database" error; andinstall/uninstall's JSON writer now resolves a symlinked~/.claude/settings.jsonbefore its atomic rename instead of replacing the symlink with a plain file, so a dotfiles-managed settings file survives untouched. - Fix startup TokenSave repository preparation silently doing nothing: both
81-tokensave_repositories.shand the indexing loop in82-claude_tools.shreadtokensave_project_pathsthroughdone < <(bashio::config ...), butbashio::configbegins with aread -d ''heredoc that always returns non-zero, and a process substitution inherits theerrexitenabled by the bashio wrapper itself — so the subshell died before printing and every boot iterated over an empty list (nosafe.directorypersistence, no startupsync/init; command substitutions were unaffected because subshells droperrexitwheninherit_errexitis off, which is why every other option lookup worked). Repositories only got indexed when tokensave's own git hooks or a manualtokensave inithappened to run. The list is now captured with a command substitution first and the loop reads from the captured variable (here-string); same fix applied toclaude-tools-doctor.sh. The indexing loop also moved ahead of the MCP-registration merge, and the merge now re-tightens the 0600 mode on the token-bearing configs even on no-change boots — a first-timetokensave initrewrites~/.claude.jsonitself at default permissions, which previously could leave the stored Home Assistant token world-readable until the next registration change. - Simplification pass over the startup logic: every remaining line now serves a live purpose, with no change to what gets configured — Headroom (proxy routing, MCP registration, CLAUDE.md guidance, PostToolUse auto-compression, dashboard exposure), RTK (global files + PreToolUse hook), and TokenSave (full agent integration + per-repo indexing) are still applied automatically to every new session type (terminal, Desktop cowork/dispatch, cron).
82-claude_tools.sh: the three hand-rolled~/.claude/settings.jsonhook mutators (rtk add, rtk remove, headroom PostToolUse) are replaced by one sharedmanage_settings_hookhelper using the proven strip-then-re-append pass (same dedup/matcher-migration semantics; additionally no longer creates an emptysettings.jsonwhen asked to remove a hook from a machine that never had one). The two copy-pasted CLAUDE.md guidance managers (headroom, ha-api-helper) collapse into onemanage_claude_md_blockhelper producing byte-identical blocks, so existing installs are recognized without a rewrite.81-tokensave_repositories.shis merged into the TokenSave loop of82-claude_tools.sh: the same path list was parsed twice with identical trimming/validation only sosafe.directorycould be persisted before repository detection ran as root. Detection now runs directly as the runtime user with a one-shotsafe.directoryoverride (the persisted entry is still written for tokensave's git hooks and Claude sessions), removing the duplicate loop and the root-reads-abc-gitconfig coupling. The battle-tested defensive sync/init block (flock, retries, corruption quarantine, init sentinel) is unchanged.- The
/tmp/claude-desktop-commandindirection is gone:82-claude_tools.shwrote the default launch command to a file that onlydefaults/autostartread, with the identical default hardcoded as its fallback — nothing else ever wrote it.autostartnow launches Claude Desktop directly (keyring bootstrap unchanged). 82-claude_tools.shno longer ends with its own recursive chown of~/.claude,~/.claude.json, and~/.config/Claude:84-claude_runtime_ownership.shalready reconciles exactly those paths after all Claude configuration scripts have run.83-claude_permissions.shdrops the hidden.addon-permission-mode.jsonstate file in favor of the same managed-value semantics used forANTHROPIC_BASE_URL:auto/bypasssetpermissions.defaultMode,strictremoves it only while it still holds an add-on-managed value (auto/bypassPermissions), and a hand-set custom value is never deleted. The old restore-from-state behavior could resurrect a stale value recorded on the first managed boot; the stale state file is cleaned up on upgrade.80-configuration.shsheds branches that were unreachable in this image:apk/pacmaninstallers (the base is Debian), thepip3fallback (uvis always baked in), and the no-op timezone error path (invalidTZvalues are now actually detected against/usr/share/zoneinfobefore the symlink is written).- Remove the dead
auto_updateoption fromconfig.yamland the README: its schema entry was removed back in 1.22 and81-claude_update.shhas updated Claude Desktop unconditionally (best-effort, offline-safe) ever since; the README now states that behavior instead of documenting a switch that did nothing.
1.31 (16-07-2026)
- Pin the LinuxServer selkies base image to a fixed version (
…-debianbookworm-45960cc3-ls113) instead of the rolling…-debianbookwormtag. The rolling tag is rebuilt continuously (and itself installs selkies "latest" at base-build time), so the desktop/stream runtime could change under the add-on with no change to its own files — builds are now reproducible and the base only moves when this value is bumped deliberately. The pinned tags resolve to exactly the image the rolling tag currently points at (amd64sha256:6a4d5154…, aarch64sha256:90914dfd…). - Fix Claude Desktop never appearing — the Selkies web client stayed on "waiting for stream" forever with
libEGL warning: failed to open /dev/dri/card0: Permission deniedin the log. The LinuxServer base image grants the desktop user (abc) access to the/dev/drirender nodes in itsinit-videos6 oneshot, but that oneshot is not a dependency ofsvc-xorg/svc-selkies/svc-de, so on Home Assistant those long-running services regularly start (vias6-setuidgid abc) beforeabchas been added to the render group. Xorg/Selkies/pixelflux then open the render device without permission, the video pipeline produces no frames, and the stream never starts. Prepare the exposed DRI nodes in a new21-gpu_permissions.shcont-init script instead:cont-init.druns to completion before any s6-rc service starts, soabcis added to each node's owning group (and the node is made world read/write as a timing-independent fallback) in time for the graphical services to use the GPU. Best-effort and a no-op on hosts that expose no GPU.
1.30 (16-07-2026)
- Compress large tool outputs automatically in every Claude Code session with a managed
PostToolUsehook (newheadroom_auto_compressoption, enabled by default). Desktop-spawned sessions (cowork/dispatch) pinANTHROPIC_BASE_URLto the production endpoint (headroom #869), so the transparent proxy never sees their traffic and compression there depended entirely on the model remembering to call theheadroomMCP tools per the CLAUDE.md guidance — in practice most large outputs went uncompressed. The new/usr/local/bin/headroom-posttooluse-compress.pyhook fires onBash/Grep/Glob/WebFetchresults over ~4000 characters, compresses them with Headroom's rule-based pipeline (SmartCrusher and friends; the Kompress ML path is disabled because its background model load can never complete inside a short-lived hook process), and swaps the result in viahookSpecificOutput.updatedToolOutputwith a retrieval marker appended. Originals are stored in the shared CCR SQLite store (~/.headroom/ccr_store.db— the same one the headroom MCP server reads), somcp__headroom__headroom_retrievealways recovers the full output; savings are recorded to the durable ledger (clientposttooluse-hook) and show up in the existing gains report. The hook fails open (any error leaves the tool output untouched), never touchesstderrfields so error text reaches the model verbatim, skips anything below a 50-token savings floor, and is registered idempotently in~/.claude/settings.jsononly after a--self-testconfirms the interpreter can import headroom; disabling the option (or Headroom) removes the managed entry without touching user-defined hooks. Measured on a representative Home Assistantstatesdump: 10781 -> 2964 tokens (73% saved) at ~1.7 s hook overhead, with sub-100 ms pass-through for small outputs.
1.29 (16-07-2026)
- Point the Headroom MCP server at the persistent Kompress model cache. 1.27 set
HF_HOMEon thesvc-headroomproxy longrun only, but the MCP server is a separate process spawned by Claude Desktop / Claude Code from the registeredmcpServersentry, so it never inherited that export and kept resolving the HuggingFace cache to~/.cache— symlinked to tmpfs here and wiped on every restart. Its Kompress ML path therefore never found the model, re-downloaded ~270 MB into tmpfs on each boot, and lost it again on the next one;headroom_compressfell back torouter:noop(unchanged output) on prose and other unstructured content. The managedheadroomentry in bothclaude_desktop_config.jsonand~/.claude.jsonnow carriesenv.HF_HOMEpointing at the same~/.headroom/hfcache the proxy warms. Rule-based compression (SmartCrusher, structured tool output) was unaffected and worked throughout. - Fix
~/.gitconfigbeing written asrootand left unreadable by theabcruntime user, which broke git for the user that actually runs it: every commit failed withAuthor identity unknownand theghcredential helper was invisible to authenticated pushes.git config --globalran as root during init and rewrites the file on every start, so20-folders.sh's earlier recursive chown never stuck to it (.config/ghsurvived abc-owned only because the "already authenticated" branch skips rewriting it). The git/gh setup now runs asabcvias6-setuidgid, matching81-tokensave_repositories.sh, and reclaims any root-owned copies left by an earlier version before writing. - Fix
~/.bashrcaccumulating staleHOME/FM_HOMEexports whendata_locationchanges. The idempotency guard only tested for the current$LOCATION, so changing the option and later changing it back appended a second block while leaving the first, and the last one written won for every interactive shell — leaving$HOMEpointing at a directory the add-on no longer manages. Any tool that resolves config through$HOMEthen read the wrong path (headroom doctorreportedclaude: not routed (no ~/.claude/settings.json)against a correctly routed install, and bareheadroominvocations created a stray.headroomtree under the old location). The block is now marker-delimited and rewritten from scratch on every boot, so it is idempotent across any number ofdata_locationchanges.
1.27 (15-07-2026)
- Route Claude Desktop cowork/local-agent-mode sessions through the Headroom proxy. Desktop spawns its bundled Claude Code binary at an absolute path (bypassing the add-on's PATH wrapper) with
ANTHROPIC_BASE_URLpinned to the production endpoint, so those sessions never produced proxy savings. The add-on now managesenv.ANTHROPIC_BASE_URLin~/.claude/settings.json— settingsenventries replace inherited environment values at CLI startup — gated onheadroom_wrap_claude_codeand never overwriting a user-customized endpoint. - Fix Headroom's Kompress compression engine never activating, which made even proxied traffic record zero token savings (e.g. 175 requests, 0 saved). The proxy's startup preload is deliberately cache-only, but the HuggingFace model cache defaulted to
~/.cache— tmpfs in this add-on, wiped every restart — so the ONNX model (plus the separately fetchedanswerdotai/ModernBERT-basetokenizer) was never cached and the engine idled in "deferred" mode forever, misleadingly logged asKompress: not installed.svc-headroomnow pointsHF_HOMEat persistent storage (~/.headroom/hf, ~270 MB); the proxy's own request path already downloads a missing model in the background on first use and passes requests through uncompressed until it lands, so no blocking startup pre-warm is needed — the port binds immediately either way, and Kompress activates within the first couple of requests on the first boot, then loads instantly on every boot after. The already-installedproxyextra's ONNX runtime is sufficient — the multi-gigabyte PyTorchmlextra is deliberately not installed.
1.26 (15-07-2026)
- Fix startup permission failures that prevented Claude Desktop from starting: storage was chowned to a hardcoded
1000:1000, but the sharedabcdesktop user was never mapped to that UID. During initabcwas still the image default (911), so TokenSave (.claude.json.new), RTK (RTK.md), nginx, PulseAudio, the Mesa shader cache, and Claude Desktop itself all hitPermission denied; the base image'sinit-adduserthen remappedabcto root mid-startup (PUID/PGID were read from add-on options where they did not exist, falling back to0), which also made Claude Code rejectpermission_mode: bypass. - Add
PUID/PGIDadd-on options (default1000:1000) and remapabcto that identity at the very start of folder setup, before any ownership is applied and before any service resolves the user. The base image'sinit-adduseris pinned to the same effective identity so it can no longer remapabcmid-startup. - In
permission_mode: bypass, a configuredPUID: 0automatically falls back to UID1000(Claude Code refuses bypass permissions as root), retaining the configured group. - Fix
bashio::config.array: command not foundin the TokenSave repository setup, tools configuration, andclaude-tools-doctor.sh: the function only exists in the repo's standalone bashio, not in the real bashio shipped in the image. Usebashio::config, which prints list entries one per line. - Return managed Claude configuration files to the effective
abcidentity instead of the raw configuredPUID/PGID(which previously fell back to0and left the files root-owned). - Pre-create
/tmp/.X11-unixwith the standard sticky mode so Xorg, which runs as the non-rootabcuser on a tmpfs/tmp, no longer fails to create its socket directory (_XSERVTransmkdir: euid != 0).
1.25 (15-07-2026)
- Minor bugs fixed
1.24 (15-07-2026)
- Fix the
/usr/local/bin/claudewrapper never routing terminal Claude Code sessions through the Headroom proxy: it hardcodedHEADROOM_BIN="/usr/local/bin/headroom"while the binary is installed at/usr/bin/headroom, so the executable check always failed and the wrapper fell back to launching Claude Code directly. Resolve the binary withcommand -v headroominstead. - Harden startup TokenSave indexing so an interrupted
init/syncor a hard add-on stop can no longer leave a corrupt semantic graph that fails every subsequent boot. Each configured repository is now prepared under a startup-scopedflock(serialised against overlapping restarts and mid-boot git sync hooks); an existing index is refreshed with a retried incrementalsync(transientSQLITE_BUSYno longer looks like corruption); and only a genuinely unreadable index — or a half-written one flagged by aninitsentinel — is quarantined to.tokensave/corrupt-<timestamp>/and rebuilt from scratch, so the graph self-heals instead of propagating corruption.
1.23 (15-07-2026)
- Add a
ha-clihelper that lets Claude configure Home Assistant (automations, scripts, scenes, helpers, dashboards, area/label/floor/entity registries, and service calls) through the Home Assistant Core API instead of a filesystem mount. It authenticates automatically with the add-on'sSUPERVISOR_TOKENvia the Supervisor Core-API proxy (no token setup), and deliberately cannot reachconfiguration.yaml/secrets.yamlor other add-ons' credentials. Toggle with the newenable_ha_api_helperoption (default on), which also controls a managed guidance block appended to~/.claude/CLAUDE.md.
1.21 (15-07-2026)
- Fix Claude Code bypass permissions being rejected when the add-on uses its default root
PUID. - In
permission_mode: bypass, remap the sharedabcDesktop runtime to an unused non-root UID before storage ownership and Selkies startup, while retaining its configured primary group for mounted-path access. - Make folder setup and final Claude configuration ownership follow the effective
abcidentity instead of the configured root UID. - Drop root console invocations of the add-on's
/usr/local/bin/claudewrapper to the non-rootabcruntime before passing--dangerously-skip-permissions. - Extend
claude-tools-doctor.shwith configured/effective UID and GID checks for bypass mode.
1.20 (15-07-2026)
- Complete the TokenSave Claude Code integration at startup: install its MCP server, permissions, PreToolUse/UserPromptSubmit/Stop hooks, global guidance, and Git synchronization hooks instead of registering only
tokensave serve. - Add
tokensave_project_pathsfor explicit per-repository initialization and incremental synchronization; no repositories are scanned or indexed unless listed. - Route PATH-based Claude Code launches through the already-supervised Headroom proxy by default with a recursion-safe
/usr/local/bin/claudewrapper; fall back to the official binary when the proxy is unavailable. - Pass the local proxy URL explicitly to the Headroom MCP server, while retaining MCP-only integration for the Desktop Electron application.
- Keep the unauthenticated Headroom dashboard container-local by default; add
expose_headroom_dashboardand leave port8787/tcpunmapped until explicitly enabled. - Fix the hourly gains report so Headroom no longer suppresses RTK output, add TokenSave gains, and gate each tool on its actual add-on option.
- Add
claude-tools-doctor.shto inspect binaries, redacted MCP registrations, hooks, proxy health, routing, project indexes, and gains. - Install local validation tools (
jq,shellcheck,yamllint, currenthadolint, and currentactionlint) to reduce avoidable CI round-trips. - Disable the unpinned third-party Caveman startup installer by default; it remains opt-in.
1.19 (14-07-2026)
- Minor bugs fixed
1.18 (14-07-2026)
- Breaking: remove the standalone Claude Code web terminal (ttyd/tmux service, port
7681, and theenable_terminal,terminal_username,terminal_password,terminal_workspaceoptions). The add-on is now built purely around Claude Desktop; Claude Code remains installed and powers Desktop cowork/dispatch sessions with the RTK hook, Caveman, and MCP servers intact. If the add-on refuses to start after the update, open its Configuration tab and re-save to drop the removed options. - Remove the
claude-directandclaude-headroomterminal wrapper scripts and the unusedha_smart_contextanddangerously_skip_permissionsoptions. - Fix the Headroom dashboard being unreachable at
http://<host>:8787/dashboard: the supervised proxy only listened on127.0.0.1; it now binds0.0.0.0so the mapped port works. - Fix dispatch/remote sessions and sign-in persistence: install the missing
gnome-keyringpackage. The existing keyring bootstrap silently no-oped without it, leaving ElectronsafeStorageunavailable ("cannot store allowlist cache"), so auth tokens and dispatch permission grants were lost on restart. - Add the tokensave code-intelligence MCP server (pinned 7.2.0, built from source like RTK), registered for both Claude Desktop and Claude Code; disable with
install_tokensave: false. - Implement the Home Assistant MCP bridge for real:
enable_ha_mcpplus newha_mcp_url/ha_mcp_tokenoptions register Home Assistant's MCP Server integration in Claude throughmcp-proxy, using the integration's stateless Streamable HTTP endpoint (/api/mcp). - Write the Claude configuration files with
0600permissions, since they hold the Home Assistant access token in clear text. - Restrict the build-time
chmod +xpass to the directories the add-on actually ships scripts in instead of traversing the whole image. - Register add-on-managed MCP servers in Claude Code's
~/.claude.jsonas well as Claude Desktop's config, without clobbering user-customized entries. - Install
uvand use it for theadditional_pipoption for much faster package installs.
1.16 (14-07-2026)
- Minor bugs fixed
1.15 (13-07-2026)
- Minor bugs fixed
ubunturesolute-version-6dc44b0e (2026-07-13)
- Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases)
1.14 (10-07-2026)
- Build pinned RTK 0.43.0 source on Debian Bookworm for both architectures instead of installing the upstream arm64 release binary, which requires GLIBC 2.39 and cannot run in the add-on image.
- Execute
rtk --versioninside the final image during the Docker build so future ABI incompatibilities fail CI instead of surfacing at runtime. - Validate the final Bookworm-built RTK binary in a native aarch64 image build.
- Correct the repository PR checks so changed changelog paths are exported and aarch64 images are built explicitly for
linux/arm64.
debiantrixie-version-c55d3809 (2026-07-11)
- Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases)
1.13 (10-07-2026)
- Add the official Claude Code stable package,
tmux,ripgrep, and a pinned upstreamttydbinary for both supported architectures. - Add an optional authenticated Claude Code web terminal on port
7681; the port remains unmapped by default and reconnecting clients attach to the same persistent tmux session. - Validate and canonicalize
terminal_workspace, restrict it to supported storage roots, and never re-own existing directories. - Order the terminal after service initialization and start tmux with an explicit Bash shell and workspace.
- Add
claude-headroomfor Headroom's supported wrapper, reusing the supervised proxy with--no-proxywhile leaving RTK management to the add-on. - Keep Claude Desktop on the MCP-only Headroom integration and remove the ineffective
ANTHROPIC_BASE_URLexport from its launch environment. - Preserve ownership of Claude settings for the configured runtime user and remove only the exact add-on-managed RTK hook when RTK is disabled.
- Fetch the repository-standard helper templates during image construction so the add-on builds from its actual Docker context.
- Install only Headroom's proxy, code-compression, and MCP features instead of unused CUDA, voice, image, memory, and evaluation stacks.
- Document the shared-home architecture, separate Desktop/CLI sessions, direct HTTP terminal security, shared concurrent sessions, and configurable data location.
1.12 (09-07-2026)
- Minor bugs fixed
1.11 (09-07-2026)
- Minor bugs fixed
1.10 (09-07-2026)
- Minor bugs fixed
1.9 (08-07-2026)
- Minor bugs fixed
1.8 (08-07-2026)
- Expose the Headroom live savings dashboard on mapped port
8787wheninstall_headroomis enabled, while keeping the proxy local-only if the port mapping is disabled. - Map
8787/tcpby default and document the dashboard URL.
1.7 (07-07-2026)
- Add an hourly rtk + headroom token-savings report to the add-on log (
claude-gains-report.sh, seeded via/defaults/crontabs/rootand run by the base image's cron). Lets you confirm at a glance that both tools keep running and see accumulated gains — if the numbers stop growing, the tool has stopped working. - Run the Headroom optimization proxy as a supervised local backend (
svc-headroomon 127.0.0.1:8787) so theheadroom_compress/headroom_retrieveMCP tools can actually store/retrieve compressed content and record savings. It is a backend only — no client'sANTHROPIC_BASE_URLis routed through it, so the Claude Desktop app (which force-overrides it, headroom #869) is unaffected. Previously the MCP server was registered but had no backend, so it recorded no savings. - Nudge Claude to use the headroom compression tools via a managed, idempotent block appended to the user's
CLAUDE.md(removed automatically wheninstall_headroomis disabled).
1.6 (07-07-2026)
- Fix default desktop launch failing when
install_headroomis enabled (the default): the code rewrote the launch toheadroom wrap claude-desktop …, butheadroom wraponly supports coding-agent CLIs (claude,codex, ...) with arguments after--, so it produced an invalid command that left the app unlaunched. Leave the plain launch intact and instead register theheadroomMCP server (headroom mcp serve) in Claude Desktop's config, exposing theheadroom_compress/headroom_retrieve/headroom_statstools inside the app. This is the supported headroom integration for Desktop, which overridesANTHROPIC_BASE_URLso transparent proxy compression is not possible (headroom #869). Disabling the option removes the entry again. - Make the autostart resilient: if the launch command fails to start, fall back to the plain Claude Desktop launch so the app always comes up.
1.5 (07-07-2026)
- Change the default Claude Desktop data location to
/data/data. - Add Home Assistant smart context, Home Assistant MCP, and dangerous permission skip options.
1.4 (07-07-2026)
- Persist Claude Desktop sign-in: bundle gnome-keyring/libsecret/dbus-x11 and start an unlocked Secret Service in the desktop session, and launch with --password-store=gnome-libsecret. Fixes "Your sign-in won't be saved on this device. Install and unlock a system keyring". The keyring DB lives on persistent storage (/config/data), so the session survives restarts.
1.3 (07-07-2026)
- Fix startup crash loop ("All subprocesses terminated. Exiting."):
- Make the Selkies desktop init oneshots (init-video, init-selkies-config) tolerant so a partially-permitted device/permission op in the HA sandbox no longer fails add-on bringup.
- Pre-create /tmp/selkies_js.log so the base image's "chmod 777 /tmp/selkies*" calls never fail on an empty glob.
- Reconcile XDG_RUNTIME_DIR to the tmpfs runtime dir instead of persistent storage.
- Run Claude Desktop with --disable-dev-shm-usage and drop the misplaced shm_size env var (Home Assistant ignores shm_size), fixing Electron renderer crashes on the default 64 MB /dev/shm.
1.2 (07-07-2026)
-
Add baked-in git/GitHub CLI support with optional startup credential configuration.
-
Fix Selkies startup by creating the s6 environment directory and XDG runtime directory before services start.
1.0 (07-07-2026)
- Minor bugs fixed
Changelog
1.1
- Fix build failure: set HOME=/root when running rtk install script to ensure binary is installed to /root/.local/bin instead of /config/.local/bin (caused by LSIO base image overriding HOME)
1.0
- Fix build failure: remove separate
npmapt package (already bundled in NodeSource nodejs)
debianbookworm-1ae1f8ff-ls13
- Initial Claude Desktop add-on using LinuxServer Selkies, Home Assistant ingress, persistent sign-in data, runtime Claude Desktop updates, optional apt/pip additions, custom scripts, and bundled Claude Code optimization tools.