Compare commits

..

205 Commits

Author SHA1 Message Date
alexbelgium
8d11bfe8e1 feat(claude_desktop): expose SUDO_PASSWORD option (LinuxServer.io convention)
Add SUDO_PASSWORD as a schema-only option, matching the existing
PASSWORD/TZ pattern. It passes through automatically via the add-on's
existing options-to-env-var mechanism (00-global_var.sh), which the
LinuxServer.io base image already reads to gate sudo access for the abc
user. Disabled by default when left unset; no rootfs changes needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 14:09:36 +02:00
Alexandre
587121cb1b Update config.yaml 2026-07-15 13:29:35 +02:00
Alexandre
29f2cfd198 Update 81-claude_update.sh 2026-07-15 13:29:07 +02:00
Alexandre
3329c4b40d nobuild 2026-07-15 13:17:03 +02:00
github-actions
9471dffcca GitHub bot: sanitize (spaces + LF endings) & chmod [nobuild] 2026-07-15 09:18:15 +00:00
Alexandre
215327e439 Merge pull request #2862 from alexbelgium/agent/claude-bypass-nonroot
Fix Claude bypass permissions under root PUID
2026-07-15 11:17:27 +02:00
Alexandre
8ecbfccdcd Document Claude bypass root fix 2026-07-15 11:05:49 +02:00
Alexandre
5a2efc4f9e Document non-root Claude bypass runtime 2026-07-15 11:04:27 +02:00
Alexandre
ef0aecbde6 Bump Claude Desktop add-on version 2026-07-15 11:02:55 +02:00
Alexandre
7a6ad72617 Diagnose Claude bypass runtime identity 2026-07-15 11:02:23 +02:00
Alexandre
b5985f230e Restore effective Claude runtime ownership 2026-07-15 11:01:22 +02:00
Alexandre
d48d1f4d8d Drop root for Claude bypass launches 2026-07-15 11:01:06 +02:00
Alexandre
6bf379bffc Use effective Claude runtime ownership 2026-07-15 10:59:49 +02:00
Alexandre
5d577ad954 Run Claude bypass mode as non-root 2026-07-15 10:59:09 +02:00
GitHub Actions
85dab2ae6e Revert "Update config.yaml"
This reverts commit ad50abc365.
2026-07-15 08:27:28 +00:00
Alexandre
ad50abc365 Update config.yaml 2026-07-15 10:25:14 +02:00
github-actions
dc280a5caf GitHub bot: sanitize (spaces + LF endings) & chmod [nobuild] 2026-07-15 08:19:42 +00:00
Alexandre
c0c1df8c27 Merge pull request #2861 from alexbelgium/agent/claude-tools-hardening
Improve Claude Desktop optimization tooling
2026-07-15 10:18:44 +02:00
Alexandre
a38bc75f95 Report Claude permission mode in diagnostics 2026-07-15 10:11:00 +02:00
Alexandre
8073317150 Document Claude permission modes 2026-07-15 10:09:44 +02:00
Alexandre
15505a265f Trust configured TokenSave repositories 2026-07-15 10:08:34 +02:00
Alexandre
d1ceafebe8 Fix actionlint amd64 asset mapping 2026-07-15 10:08:08 +02:00
Alexandre
c76b257f5d Persist Claude permission mode 2026-07-15 10:05:29 +02:00
Alexandre
321f2fde73 Apply Claude permission mode in wrapper 2026-07-15 10:04:48 +02:00
Alexandre
45f88307d4 Add Claude permission modes 2026-07-15 10:04:23 +02:00
Alexandre
7cd82b2758 Fix validator release asset lookup 2026-07-15 09:20:43 +02:00
Alexandre
66d3886b80 Improve Claude optimization tooling 2026-07-15 09:17:05 +02:00
Alexandre
bdd56b8057 Improve Claude optimization tooling 2026-07-15 09:16:08 +02:00
Alexandre
9c55193c38 Improve Claude optimization tooling 2026-07-15 09:15:18 +02:00
Alexandre
6b6233e1fa Improve Claude optimization tooling 2026-07-15 09:14:23 +02:00
Alexandre
22951ac4f5 Improve Claude optimization tooling 2026-07-15 09:12:44 +02:00
Alexandre
006f3052ac Improve Claude optimization tooling 2026-07-15 09:12:14 +02:00
Alexandre
0ff2e8f783 Improve Claude optimization tooling 2026-07-15 09:11:58 +02:00
Alexandre
3c8a32199e Improve Claude optimization tooling 2026-07-15 09:11:46 +02:00
Alexandre
c8d706c9de Improve Claude optimization tooling 2026-07-15 09:11:30 +02:00
Alexandre
c04f3e288c Improve Claude optimization tooling 2026-07-15 09:11:20 +02:00
github-actions
f6c2bef0be GitHub bot: changelog [nobuild] 2026-07-14 17:59:29 +00:00
Alexandre
f8c447ed19 Update config.yaml 2026-07-14 19:46:49 +02:00
Alexandre
bd82e72ffa Remove gnome-keyring from Dockerfile
Removed gnome-keyring from the list of packages to install.
2026-07-14 19:46:37 +02:00
github-actions
a3ecb38fea GitHub bot : README updated 2026-07-14 17:26:53 +00:00
Alexandre
eada7a0ba0 Merge pull request #2860 from alexbelgium/feat/claude-desktop-only-v2
fix(claude_desktop): correct HA MCP endpoint, harden config perms and chmod scope
2026-07-14 16:52:58 +02:00
alexbelgium
e7921b822e fix(claude_desktop): correct HA MCP endpoint, harden config perms and chmod scope
Home Assistant's MCP Server integration serves stateless Streamable HTTP at
/api/mcp; mcp-proxy defaults to SSE, so the previous registration (SSE at
/mcp_server/sse) could never attach. Pass --transport=streamablehttp
--stateless and default ha_mcp_url to /api/mcp.

Match managed MCP entries by binary basename outside $HOME so a base-image
path change still updates them, while user-installed binaries under $HOME
remain untouched. Resolve tokensave via command -v like the others.

Write Claude config files 0600 (they hold the HA long-lived token in clear
text) and scope the build-time chmod +x pass to the shipped script dirs.

Docs: dashboard reachability wording, stale /config/data HOME, and the
custom-script filename (claude_desktop.sh, per the $slug.sh template).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 16:52:15 +02:00
Alexandre
aa1486c1d8 nobuild 2026-07-14 16:39:19 +02:00
GitHub Actions
b4008c4db9 Revert "update"
This reverts commit fa2328f741.
2026-07-14 14:37:19 +00:00
Alexandre
fa2328f741 update 2026-07-14 16:36:25 +02:00
Alexandre
e8bb55682b Merge pull request #2859 from alexbelgium/bump-builder-2026.06.0
ci: bump builder build-image action to 2026.06.0
2026-07-14 16:35:01 +02:00
Alexandre
7fdf95940b Merge pull request #2858 from alexbelgium/feat/claude-desktop-only
feat(claude_desktop): desktop-only architecture, fix dashboard + dispatch
2026-07-14 16:33:19 +02:00
alexbelgium
583c5e655a ci: bump home-assistant/builder build-image action to 2026.06.0
Legacy monolithic builder was removed upstream in 2026.06.0; this repo
already uses the modular build-image action, so only the pin moves
(2026.03.2 -> 2026.06.0). Action inputs/outputs unchanged upstream —
drop-in compatible. Also strips trailing whitespace at EOF (yamllint).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 16:31:24 +02:00
alexbelgium
b56be1f57d feat(claude_desktop): desktop-only architecture, fix dashboard + dispatch
Remove standalone web terminal (ttyd/tmux service, port 7681, terminal_*
options, claude-direct/claude-headroom wrappers). Claude Code stays and
powers Desktop cowork/dispatch sessions.

Fix Headroom dashboard: proxy bound 127.0.0.1 only, mapped port 8787
refused external connections; bind 0.0.0.0.

Fix dispatch/sign-in persistence: gnome-keyring package was never
installed, so the autostart keyring bootstrap no-oped and Electron
safeStorage was unavailable (allowlist cache + auth grants lost).

Add tokensave MCP (pinned 7.2.0, source-built like RTK), real HA MCP
bridge via mcp-proxy (enable_ha_mcp + ha_mcp_url/ha_mcp_token), uv for
additional_pip. Register managed MCP servers in Desktop and Claude Code
configs without clobbering user entries. Drop orphan options
ha_smart_context/dangerously_skip_permissions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:27:52 +02:00
github-actions
50150a4775 GitHub bot: changelog [nobuild] 2026-07-14 14:26:50 +00:00
github-actions
6814088369 GitHub bot: sanitize (spaces + LF endings) & chmod [nobuild] 2026-07-14 14:19:56 +00:00
Alexandre
2951b04f57 Update config.yaml 2026-07-14 16:18:58 +02:00
Alexandre
245c52fcf2 Merge pull request #2857 from alexbelgium/agent/add-chatgpt-codex-addon
Add ChatGPT Codex add-on with Headroom and RTK
2026-07-14 16:18:22 +02:00
Alexandre
2b6c9eace7 Release latest-version build policy 2026-07-14 16:04:13 +02:00
Alexandre
fd268d0e6d Normalize latest-version documentation 2026-07-14 16:01:29 +02:00
Alexandre
5792d84336 Keep updater metadata separate from build resolution 2026-07-14 16:00:57 +02:00
Alexandre
bf97abdb4f Document latest-version build policy 2026-07-14 16:00:44 +02:00
Alexandre
7de4789196 Document unpinned tool installation 2026-07-14 15:59:05 +02:00
Alexandre
34e8a75bf8 Install latest tool releases at build time 2026-07-14 15:58:55 +02:00
Alexandre
652be8b13c Pin Codex and Headroom releases 2026-07-14 15:03:34 +02:00
Alexandre
78f5289518 Fix Codex add-on lint metadata 2026-07-14 14:59:11 +02:00
Alexandre
12384ee606 Follow custom data location for Codex workspace 2026-07-14 14:55:02 +02:00
Alexandre
df0dacf6b9 Restrict Codex ingress to administrators 2026-07-14 14:53:30 +02:00
Alexandre
2cbf2a6f08 Add ChatGPT Codex add-on with Headroom and RTK 2026-07-14 14:51:06 +02:00
Alexandre
adcd892e62 Merge pull request #2856 from alexbelgium/fix/elasticsearch-force-rebuild
fix(elasticsearch): force fresh image pull for users stuck on a stale 7.17.9 image
2026-07-14 14:34:59 +02:00
Alexandre
980be49d9b Merge branch 'master' into fix/elasticsearch-force-rebuild 2026-07-14 14:34:28 +02:00
github-actions
9cff4f83b9 GitHub bot: changelog [nobuild] 2026-07-14 11:42:46 +00:00
Alexandre
688d1cbdcf Update config.yaml 2026-07-14 13:40:23 +02:00
alexbelgium
02bbfa86c3 fix(elasticsearch): force fresh image pull, clarify non-root failure
The published 8.19.18 images are correct (verified: real ES 8.19.18,
run as root, migration + privilege-drop in place). But some upgrades
were left running a stale cached Elasticsearch 7.17.9 image that starts
as uid 1000, producing the reported "mv: cannot move '/data/config' ...
Permission denied" and "AccessDeniedException[.../data/nodes/0]".

- Bump version to 8.19.18-3 to force Home Assistant / Docker to pull a
  fresh image tag instead of reusing the cached one.
- Add an explicit root check on the first init pass (before any move or
  chown) so a non-root start fails with a clear, actionable message
  instead of the cryptic permission error, and wrap the config-archive
  mv with the same clear failure. The re-exec'd uid-1000 pass returns
  before this check, so the privilege drop still works.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 13:35:03 +02:00
Alexandre
a5916d9236 nobuild 2026-07-14 13:06:55 +02:00
Alexandre
371c206fc0 Update Elasticsearch version to 8.19.18 2026-07-14 13:06:17 +02:00
github-actions
75ce8e94e4 GitHub bot: changelog [nobuild] 2026-07-14 10:47:03 +00:00
Alexandre
0b7b0ac1df Update config.yaml 2026-07-14 12:43:40 +02:00
Alexandre
2f4ab956db Update config.yaml 2026-07-14 12:43:18 +02:00
Alexandre
08a7bd35cb Merge pull request #2854 from alexbelgium/fix/elasticsearch-runtime-root-permission
fix(elasticsearch): stay root at runtime, fix upgrade permission failure
2026-07-14 12:41:49 +02:00
alexbelgium
a313475d92 fix(elasticsearch): drop to uid 1000 before starting Elasticsearch
Elasticsearch refuses to bootstrap as root ("can not run elasticsearch
as root"). The previous fix in this PR kept the container root at
runtime to fix the /data permission failure, but never dropped
privileges again afterward — unlike 7.17.9, whose own entrypoint used
`chroot --userspec=1000:0` before launching Elasticsearch, the upstream
8.x entrypoint no longer does that. So every start, fresh or upgrade,
would fail once addon-init.sh's setup finished.

Fix: after addon-init.sh completes its root-only work (migration guard,
data/config relocation, chown), it re-execs the entrypoint itself as
uid 1000 via `chroot --userspec=1000:0 / ...` — the same mechanism
7.17.9 used, and exactly what the add-on's AppArmor profile already
grants (sys_chroot, setuid, setgid). On the re-exec'd pass the script
returns immediately (guarded by an exported sentinel) so none of the
setup work repeats; exported env vars (env_vars, the security default)
survive the exec normally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:33:26 +02:00
alexbelgium
087d23eeaf fix(elasticsearch): stay root at runtime, fix upgrade permission failure
Reported: on upgrade from an existing 7.17.9 install, the add-on failed
to start with "mv: cannot move '/data/config' to
'/data/config.bak-7.17.9': Permission denied".

Root cause: a previous fix in this same release restored `USER 1000:0`
at the end of the Dockerfile to match the upstream base image's own
final USER directive. But the upstream 8.19 entrypoint no longer drops
privileges itself (confirmed: it execs elasticsearch directly, no
gosu/chroot dance), and existing installs have /data owned by root
(7.17.9's default image variant runs fully as root). A non-root
container can never chown or move that data.

Revert to root at runtime, matching how this add-on always ran and
matching its own AppArmor profile (chown, setuid, setgid, sys_chroot,
mount capabilities — all meaningless for a non-root process anyway).
Root stays required for the build-time entrypoint patch too, unchanged
from the prior fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:12:16 +02:00
github-actions
a9a6b22a62 GitHub bot: sanitize (spaces + LF endings) & chmod [nobuild] 2026-07-14 09:43:11 +00:00
Alexandre
b16305a9e6 Merge pull request #2853 from alexbelgium/fix/elasticsearch-8x-migration
fix(elasticsearch): upgrade to 8.19.18 with automatic data migration
2026-07-14 11:42:25 +02:00
github-actions
34135ba471 GitHub bot: changelog [nobuild] 2026-07-14 08:07:54 +00:00
Alexandre
ab02e92ad1 Update config.yaml 2026-07-14 09:59:51 +02:00
Alexandre
6f93187535 nobuild 2026-07-14 09:56:15 +02:00
Alexandre
a90fe9ee4a Update Dockerfile 2026-07-14 09:34:10 +02:00
Alexandre
6bb4cb735d Update config.yaml 2026-07-14 09:32:13 +02:00
Alexandre
299c97c83f Merge pull request #2818 from alexbelgium/codex/fix-netbird-server-startup
[codex] Fix NetBird server startup
2026-07-14 09:01:51 +02:00
Alexandre
ad5eba5657 Update config.yaml 2026-07-14 08:56:36 +02:00
github-actions
bd6daa32b7 GitHub bot: changelog [nobuild] 2026-07-14 06:48:31 +00:00
Alexandre
7df08e4f84 Update config.yaml 2026-07-14 08:46:38 +02:00
github-actions
b8421be1e9 GitHub bot: changelog [nobuild] 2026-07-13 09:36:03 +00:00
Alexandre
30f99d738b Update config.yaml 2026-07-13 11:34:08 +02:00
alexbelgium
d44b38981e Updater bot : zzz_archived_code-server updated to 4.128.0 2026-07-13 08:34:21 +02:00
alexbelgium
c6c5197eb8 Updater bot : tdarr updated to 2.83.01 2026-07-13 08:33:00 +02:00
alexbelgium
a966369e96 Updater bot : tandoor_recipes updated to 2.6.13 2026-07-13 08:32:58 +02:00
alexbelgium
0363265d84 Updater bot : social_to_mealie updated to 1.7.1 2026-07-13 08:32:42 +02:00
alexbelgium
bb2146866f Updater bot : scrutiny_fa updated to v1.66.0 2026-07-13 08:32:25 +02:00
alexbelgium
21b9783fe2 Updater bot : scrutiny updated to v1.66.0 2026-07-13 08:32:21 +02:00
alexbelgium
8162d42e41 Updater bot : radarr updated to 6.3.0.10514 2026-07-13 08:32:03 +02:00
alexbelgium
4b848c9054 Updater bot : prowlarr updated to develop-2.5.1.5464-ls268 2026-07-13 08:31:56 +02:00
GitHub Actions
731f099c8c Revert "Updater bot : ente updated to 4.4.24"
This reverts commit 5755df5181.
2026-07-13 06:31:53 +00:00
GitHub Actions
e56dcf7abd Revert "Updater bot : flexget updated to 3.19.27"
This reverts commit dc206213ca.
2026-07-13 06:31:53 +00:00
GitHub Actions
e25b4ec1d3 Revert "Updater bot : gitea updated to 1.27.0"
This reverts commit 19c3cf8252.
2026-07-13 06:31:53 +00:00
GitHub Actions
9161c28e27 Revert "Updater bot : grav updated to 2.0.10"
This reverts commit 289b3b53f1.
2026-07-13 06:31:53 +00:00
GitHub Actions
82af311c37 Revert "Updater bot : immich updated to 3.0.2"
This reverts commit 3c5212b4ef.
2026-07-13 06:31:53 +00:00
GitHub Actions
85dd1669fa Revert "Updater bot : immich_cuda updated to 3.0.2"
This reverts commit 3ad3b1d1ba.
2026-07-13 06:31:53 +00:00
GitHub Actions
98962ac296 Revert "Updater bot : immich_frame updated to 1.0.35.0"
This reverts commit 2468d11400.
2026-07-13 06:31:53 +00:00
GitHub Actions
6d199b146b Revert "Updater bot : immich_noml updated to 3.0.2"
This reverts commit c8a52ba915.
2026-07-13 06:31:53 +00:00
GitHub Actions
b0750a8a7f Revert "Updater bot : immich_openvino updated to 3.0.2"
This reverts commit cedccabef2.
2026-07-13 06:31:53 +00:00
GitHub Actions
ef9f76e91c Revert "Updater bot : jackett updated to 0.24.2206"
This reverts commit e17cc922f9.
2026-07-13 06:31:53 +00:00
GitHub Actions
8bc048b993 Revert "Updater bot : linkwarden updated to 2.15.1"
This reverts commit 796a4132bf.
2026-07-13 06:31:53 +00:00
GitHub Actions
26533b6697 Revert "Updater bot : maintainerr updated to 3.17.1"
This reverts commit afe45b7a75.
2026-07-13 06:31:53 +00:00
GitHub Actions
3eafa3e028 Revert "Updater bot : navidrome updated to 0.63.2"
This reverts commit 44f576699d.
2026-07-13 06:31:53 +00:00
GitHub Actions
9173829335 Revert "Updater bot : nzbget updated to v26.2-ls253"
This reverts commit 246a7ce157.
2026-07-13 06:31:53 +00:00
GitHub Actions
6b50abe96d Revert "Updater bot : openproject updated to 17.6.0"
This reverts commit a5bba509ef.
2026-07-13 06:31:52 +00:00
GitHub Actions
9a4f384d5a Revert "Updater bot : plex updated to 1.43.2.10687-563d026ea-ls312"
This reverts commit 521d555615.
2026-07-13 06:31:52 +00:00
alexbelgium
521d555615 Updater bot : plex updated to 1.43.2.10687-563d026ea-ls312 2026-07-13 08:31:45 +02:00
alexbelgium
a5bba509ef Updater bot : openproject updated to 17.6.0 2026-07-13 08:31:36 +02:00
alexbelgium
246a7ce157 Updater bot : nzbget updated to v26.2-ls253 2026-07-13 08:31:28 +02:00
alexbelgium
44f576699d Updater bot : navidrome updated to 0.63.2 2026-07-13 08:31:14 +02:00
alexbelgium
afe45b7a75 Updater bot : maintainerr updated to 3.17.1 2026-07-13 08:30:55 +02:00
alexbelgium
796a4132bf Updater bot : linkwarden updated to 2.15.1 2026-07-13 08:30:51 +02:00
alexbelgium
e17cc922f9 Updater bot : jackett updated to 0.24.2206 2026-07-13 08:30:29 +02:00
alexbelgium
cedccabef2 Updater bot : immich_openvino updated to 3.0.2 2026-07-13 08:30:21 +02:00
alexbelgium
c8a52ba915 Updater bot : immich_noml updated to 3.0.2 2026-07-13 08:30:16 +02:00
alexbelgium
2468d11400 Updater bot : immich_frame updated to 1.0.35.0 2026-07-13 08:30:11 +02:00
alexbelgium
3ad3b1d1ba Updater bot : immich_cuda updated to 3.0.2 2026-07-13 08:30:07 +02:00
alexbelgium
3c5212b4ef Updater bot : immich updated to 3.0.2 2026-07-13 08:30:02 +02:00
alexbelgium
289b3b53f1 Updater bot : grav updated to 2.0.10 2026-07-13 08:29:55 +02:00
alexbelgium
19c3cf8252 Updater bot : gitea updated to 1.27.0 2026-07-13 08:29:48 +02:00
alexbelgium
dc206213ca Updater bot : flexget updated to 3.19.27 2026-07-13 08:29:37 +02:00
alexbelgium
5755df5181 Updater bot : ente updated to 4.4.24 2026-07-13 08:29:15 +02:00
alexbelgium
0b6c410001 Updater bot : emby_beta updated to 4.10.0.19 2026-07-13 08:29:04 +02:00
alexbelgium
2a498af497 Updater bot : claude_desktop updated to ubunturesolute-version-6dc44b0e 2026-07-13 08:28:44 +02:00
alexbelgium
b620907a6a Updater bot : birdnet-pipy updated to 0.8.4 2026-07-13 08:27:15 +02:00
alexbelgium
98629f7214 Updater bot : birdnet-go updated to 20260712 2026-07-13 08:27:09 +02:00
github-actions
769cfc278e Github bot : image compressed 2026-07-12 23:21:20 +00:00
github-actions
9d21c49fa5 GitHub bot : README updated 2026-07-12 17:22:16 +00:00
Alexandre
49d78a32d5 Merge pull request #2846 from alexbelgium/agent/fix-claude-rtk-arm64
Fix RTK compatibility and Claude add-on validation
2026-07-12 19:12:22 +02:00
Alexandre
5208dd3ce9 Merge branch 'master' into agent/fix-claude-rtk-arm64 2026-07-12 19:12:06 +02:00
Alexandre
055f6e58f3 Update config.yaml 2026-07-12 19:11:14 +02:00
github-actions[bot]
e2bec544cb Update stargazer map & cache 2026-07-12 01:24:56 +00:00
Alexandre
23f756b4db Merge pull request #2848 from ToledoEM/fix/npm-letsencrypt-persist
Persist NPM Let's Encrypt certificates
2026-07-11 16:41:09 +02:00
ToledoEM
efa5ed9b59 coderabbitai suggestions 2026-07-11 12:26:19 +01:00
ToledoEM
82c784ce6e Persist NPM Let's Encrypt certificates 2026-07-11 12:14:25 +01:00
GitHub Actions
83b791e6c3 Revert "Updater bot : ente updated to 4.4.24"
This reverts commit 839cfd1382.
2026-07-10 23:32:12 +00:00
GitHub Actions
c3a8e1d57b Revert "Updater bot : flexget updated to 3.19.27"
This reverts commit b21ce72e0e.
2026-07-10 23:32:12 +00:00
GitHub Actions
382de98a9b Revert "Updater bot : grav updated to 2.0.10"
This reverts commit 91ed6c3f46.
2026-07-10 23:32:12 +00:00
GitHub Actions
ca6c6a54d3 Revert "Updater bot : immich updated to 3.0.2"
This reverts commit 6e02e611f4.
2026-07-10 23:32:12 +00:00
GitHub Actions
57d8edb445 Revert "Updater bot : immich_cuda updated to 3.0.2"
This reverts commit aa77249314.
2026-07-10 23:32:12 +00:00
GitHub Actions
d9252da5a3 Revert "Updater bot : immich_frame updated to 1.0.35.0"
This reverts commit c8f5ec8f20.
2026-07-10 23:32:12 +00:00
GitHub Actions
deb51a0bed Revert "Updater bot : immich_noml updated to 3.0.2"
This reverts commit af68eece53.
2026-07-10 23:32:12 +00:00
GitHub Actions
dbaa8a8a98 Revert "Updater bot : immich_openvino updated to 3.0.2"
This reverts commit b98ae69a6c.
2026-07-10 23:32:12 +00:00
GitHub Actions
4cf79224f7 Revert "Updater bot : jackett updated to 0.24.2200"
This reverts commit 534a526185.
2026-07-10 23:32:12 +00:00
GitHub Actions
90fd373c2c Revert "Updater bot : linkwarden updated to 2.15.0"
This reverts commit 481094574d.
2026-07-10 23:32:12 +00:00
GitHub Actions
e930e36e0d Revert "Updater bot : maintainerr updated to 3.17.1"
This reverts commit 22bbbfdf75.
2026-07-10 23:32:12 +00:00
GitHub Actions
35c3077bec Revert "Updater bot : navidrome updated to 0.63.1"
This reverts commit 682a96fc8e.
2026-07-10 23:32:12 +00:00
GitHub Actions
06e0a32f81 Revert "Updater bot : nzbget updated to v26.2-ls253"
This reverts commit e8260efe37.
2026-07-10 23:32:12 +00:00
GitHub Actions
22f9490b77 Revert "Updater bot : openproject updated to 17.6.0"
This reverts commit 29ca739709.
2026-07-10 23:32:12 +00:00
GitHub Actions
72851eea95 Revert "Updater bot : plex updated to 1.43.2.10687-563d026ea-ls312"
This reverts commit 554d7dc04f.
2026-07-10 23:32:12 +00:00
GitHub Actions
2bc142b5fe Revert "Updater bot : prowlarr updated to develop-2.5.1.5460-ls267"
This reverts commit ea3e5e425b.
2026-07-10 23:32:12 +00:00
GitHub Actions
3e5649f00f Revert "Updater bot : scrutiny updated to v1.66.0"
This reverts commit 8788211f8a.
2026-07-10 23:32:12 +00:00
GitHub Actions
8c7a43b5be Revert "Updater bot : scrutiny_fa updated to v1.66.0"
This reverts commit 842c237965.
2026-07-10 23:32:12 +00:00
GitHub Actions
e7a6add76f Revert "Updater bot : social_to_mealie updated to 1.7.0"
This reverts commit 2aaf940b73.
2026-07-10 23:32:12 +00:00
GitHub Actions
0d56b4dded Revert "Updater bot : tandoor_recipes updated to 2.6.13"
This reverts commit 71c67e7eef.
2026-07-10 23:32:12 +00:00
GitHub Actions
7ee213406d Revert "Updater bot : tdarr updated to 2.82.02"
This reverts commit e6210d484d.
2026-07-10 23:32:12 +00:00
alexbelgium
e6210d484d Updater bot : tdarr updated to 2.82.02 2026-07-11 01:31:25 +02:00
alexbelgium
71c67e7eef Updater bot : tandoor_recipes updated to 2.6.13 2026-07-11 01:31:23 +02:00
alexbelgium
2aaf940b73 Updater bot : social_to_mealie updated to 1.7.0 2026-07-11 01:31:08 +02:00
alexbelgium
842c237965 Updater bot : scrutiny_fa updated to v1.66.0 2026-07-11 01:30:50 +02:00
alexbelgium
8788211f8a Updater bot : scrutiny updated to v1.66.0 2026-07-11 01:30:46 +02:00
alexbelgium
ea3e5e425b Updater bot : prowlarr updated to develop-2.5.1.5460-ls267 2026-07-11 01:30:22 +02:00
alexbelgium
554d7dc04f Updater bot : plex updated to 1.43.2.10687-563d026ea-ls312 2026-07-11 01:30:11 +02:00
alexbelgium
29ca739709 Updater bot : openproject updated to 17.6.0 2026-07-11 01:30:01 +02:00
alexbelgium
e8260efe37 Updater bot : nzbget updated to v26.2-ls253 2026-07-11 01:29:54 +02:00
alexbelgium
682a96fc8e Updater bot : navidrome updated to 0.63.1 2026-07-11 01:29:40 +02:00
alexbelgium
22bbbfdf75 Updater bot : maintainerr updated to 3.17.1 2026-07-11 01:29:21 +02:00
alexbelgium
481094574d Updater bot : linkwarden updated to 2.15.0 2026-07-11 01:29:17 +02:00
alexbelgium
534a526185 Updater bot : jackett updated to 0.24.2200 2026-07-11 01:28:54 +02:00
alexbelgium
b98ae69a6c Updater bot : immich_openvino updated to 3.0.2 2026-07-11 01:28:46 +02:00
alexbelgium
af68eece53 Updater bot : immich_noml updated to 3.0.2 2026-07-11 01:28:41 +02:00
alexbelgium
c8f5ec8f20 Updater bot : immich_frame updated to 1.0.35.0 2026-07-11 01:28:37 +02:00
alexbelgium
aa77249314 Updater bot : immich_cuda updated to 3.0.2 2026-07-11 01:28:32 +02:00
alexbelgium
6e02e611f4 Updater bot : immich updated to 3.0.2 2026-07-11 01:28:28 +02:00
alexbelgium
91ed6c3f46 Updater bot : grav updated to 2.0.10 2026-07-11 01:28:21 +02:00
alexbelgium
b21ce72e0e Updater bot : flexget updated to 3.19.27 2026-07-11 01:28:04 +02:00
alexbelgium
839cfd1382 Updater bot : ente updated to 4.4.24 2026-07-11 01:27:42 +02:00
alexbelgium
ae22240269 Updater bot : emby_beta updated to 4.10.0.18 2026-07-11 01:27:31 +02:00
alexbelgium
91429643ef Updater bot : codex updated to 2.1.2 2026-07-11 01:27:20 +02:00
alexbelgium
507ea9fb8c Updater bot : cleanuparr updated to 2.9.16 2026-07-11 01:27:12 +02:00
alexbelgium
434aa76c2a Updater bot : claude_desktop updated to debiantrixie-version-c55d3809 2026-07-11 01:27:08 +02:00
alexbelgium
397a6eed88 Updater bot : browser_chromium updated to version-30a7c401 2026-07-11 01:26:33 +02:00
alexbelgium
859e47772a Updater bot : browser_brave updated to 1.92.139-ls112 2026-07-11 01:26:22 +02:00
alexbelgium
8153a944d8 Updater bot : birdnet-pipy updated to 0.8.3 2026-07-11 01:25:38 +02:00
alexbelgium
6f143deb49 Updater bot : aurral updated to 1.76.52 2026-07-11 01:25:13 +02:00
github-actions
0fc95bfe88 GitHub bot : README updated 2026-07-10 17:33:25 +00:00
Alexandre
0c651312ab Validate Claude arm64 build and changelog 2026-07-10 15:40:24 +02:00
Alexandre
6b4c11cbd8 Fix add-on changelog and arm64 CI checks 2026-07-10 15:39:27 +02:00
Alexandre
424573548e Finalize Claude RTK arm64 validation 2026-07-10 15:36:14 +02:00
Alexandre
effd7f4319 Run final Claude add-on build matrix 2026-07-10 15:30:35 +02:00
Alexandre
69458eb13d Remove temporary Claude build diagnostic 2026-07-10 15:30:06 +02:00
Alexandre
2bbc48f7ab Use native arm64 runner for RTK validation 2026-07-10 15:23:30 +02:00
Alexandre
94135b9b05 Trigger Claude add-on architecture builds 2026-07-10 15:22:49 +02:00
Alexandre
7b3eb17efd Document RTK arm64 compatibility fix 2026-07-10 15:21:23 +02:00
Alexandre
5d7d6ff334 Bump Claude Desktop add-on to 1.14 2026-07-10 15:20:52 +02:00
Alexandre
bd9f4f3d23 Build RTK against Bookworm for arm64 compatibility 2026-07-10 15:20:30 +02:00
Alexandre
918b9477b0 Fix NetBird server startup 2026-07-06 17:33:39 +02:00
227 changed files with 1251 additions and 563 deletions

View File

@@ -162,6 +162,7 @@ DARKNAGAN,France
DDanii, DDanii,
DMurzNN, DMurzNN,
DUC750, DUC750,
DY-hub,
DaFlowah, DaFlowah,
DaJonas94, DaJonas94,
Daafip,Netherlands Daafip,Netherlands
@@ -238,6 +239,7 @@ EtienneMD,
Evel270, Evel270,
Everestlion, Everestlion,
EvertJob, EvertJob,
Exlatis,
Extrunder, Extrunder,
F0264, F0264,
F4bsi,Germany F4bsi,Germany
@@ -563,6 +565,7 @@ PhoenixTwoFive,Germany
PhysShell, PhysShell,
PierreNa,France PierreNa,France
PietroSpina, PietroSpina,
Pingmin,
PiotrKrzyzek,United States PiotrKrzyzek,United States
PiratesGhost, PiratesGhost,
Pixelzeus, Pixelzeus,
@@ -897,10 +900,12 @@ antorimba,
antx-code, antx-code,
anyezhe, anyezhe,
aorosora, aorosora,
araminimichael,
arbal,United States arbal,United States
ardemk, ardemk,
ared469, ared469,
arethefreshest, arethefreshest,
arozoire,
arpit-mehra, arpit-mehra,
artemave,France artemave,France
artemdanielov, artemdanielov,
@@ -1156,6 +1161,7 @@ danbruno,
danctrl,Germany danctrl,Germany
danez,United States danez,United States
danieldotnl,Netherlands danieldotnl,Netherlands
danishru,
dannybeeckman, dannybeeckman,
dannybloomfield,United States dannybloomfield,United States
danveitch76, danveitch76,
@@ -1744,6 +1750,7 @@ ljsquare,
llabourdeth, llabourdeth,
llewy, llewy,
llfjahn, llfjahn,
llugo,
lmalmoreno,Brazil lmalmoreno,Brazil
lnrdmx, lnrdmx,
loc4t3llix, loc4t3llix,
@@ -2050,6 +2057,7 @@ pedrolicassali,
pedromfa, pedromfa,
pedrware,Portugal pedrware,Portugal
peeetek, peeetek,
peggleg,
pejannl, pejannl,
pem884,United States pem884,United States
pepelatc, pepelatc,
@@ -2273,6 +2281,7 @@ skalingclouds,United States
skamaleo, skamaleo,
skavieller, skavieller,
skipper00, skipper00,
skoducks,United States
skylidefr, skylidefr,
skynet-network, skynet-network,
slimehands, slimehands,
@@ -2532,6 +2541,7 @@ williamcorsel,Netherlands
willigenburggihaux, willigenburggihaux,
willnewcombe,United Kingdom willnewcombe,United Kingdom
wimb0, wimb0,
wingerasc,
witold-gren,Poland witold-gren,Poland
wonderfulhuber, wonderfulhuber,
wonkygecko,United States wonkygecko,United States
1 username country
162 DDanii
163 DMurzNN
164 DUC750
165 DY-hub
166 DaFlowah
167 DaJonas94
168 Daafip Netherlands
239 Evel270
240 Everestlion
241 EvertJob
242 Exlatis
243 Extrunder
244 F0264
245 F4bsi Germany
565 PhysShell
566 PierreNa France
567 PietroSpina
568 Pingmin
569 PiotrKrzyzek United States
570 PiratesGhost
571 Pixelzeus
900 antx-code
901 anyezhe
902 aorosora
903 araminimichael
904 arbal United States
905 ardemk
906 ared469
907 arethefreshest
908 arozoire
909 arpit-mehra
910 artemave France
911 artemdanielov
1161 danctrl Germany
1162 danez United States
1163 danieldotnl Netherlands
1164 danishru
1165 dannybeeckman
1166 dannybloomfield United States
1167 danveitch76
1750 llabourdeth
1751 llewy
1752 llfjahn
1753 llugo
1754 lmalmoreno Brazil
1755 lnrdmx
1756 loc4t3llix
2057 pedromfa
2058 pedrware Portugal
2059 peeetek
2060 peggleg
2061 pejannl
2062 pem884 United States
2063 pepelatc
2281 skamaleo
2282 skavieller
2283 skipper00
2284 skoducks United States
2285 skylidefr
2286 skynet-network
2287 slimehands
2541 willigenburggihaux
2542 willnewcombe United Kingdom
2543 wimb0
2544 wingerasc
2545 witold-gren Poland
2546 wonderfulhuber
2547 wonkygecko United States

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 60 KiB

BIN
.github/stats.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -35,6 +35,7 @@ jobs:
git fetch origin "${{ github.event.before }}" || true git fetch origin "${{ github.event.before }}" || true
changed_changelog_files=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" | grep -iE '^([^/]+/)?changelog\.(md|txt|ya?ml|json)$' || true) changed_changelog_files=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" | grep -iE '^([^/]+/)?changelog\.(md|txt|ya?ml|json)$' || true)
echo "$changed_changelog_files" echo "$changed_changelog_files"
echo "changelogs_files=$changed_changelog_files" >> "$GITHUB_OUTPUT"
changed_config_files=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" | grep -E '^[^/]+/config\.(json|ya?ml)$' || true) changed_config_files=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" | grep -E '^[^/]+/config\.(json|ya?ml)$' || true)
echo "$changed_config_files" echo "$changed_config_files"
all_changed_files=$(echo -e "$changed_config_files\n$changed_changelog_files" | sort -u) all_changed_files=$(echo -e "$changed_config_files\n$changed_changelog_files" | sort -u)
@@ -208,6 +209,7 @@ jobs:
uses: docker/build-push-action@v7 uses: docker/build-push-action@v7
with: with:
context: ${{ matrix.addon }} context: ${{ matrix.addon }}
platforms: linux/arm64
push: false push: false
load: true load: true
file: ${{ matrix.addon }}/Dockerfile file: ${{ matrix.addon }}/Dockerfile

View File

@@ -300,7 +300,7 @@ jobs:
- name: Build ${{ matrix.addon }} add-on - name: Build ${{ matrix.addon }} add-on
if: steps.info.outputs.build_arch == 'true' && steps.info.outputs.has_dockerfile == 'true' if: steps.info.outputs.build_arch == 'true' && steps.info.outputs.has_dockerfile == 'true'
uses: home-assistant/builder/actions/build-image@2026.03.2 uses: home-assistant/builder/actions/build-image@2026.06.0
with: with:
arch: ${{ matrix.arch }} arch: ${{ matrix.arch }}
cache-gha: "false" cache-gha: "false"
@@ -433,4 +433,3 @@ jobs:
done done
git push origin HEAD:master git push origin HEAD:master

View File

@@ -1,51 +0,0 @@
---
name: Claude Add-on Build Diagnostic
on:
pull_request:
branches:
- master
jobs:
diagnose:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Gather add-on information
id: information
uses: frenck/action-addon-information@v1.4
with:
path: ./claude_desktop/
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build aarch64 and capture tail
shell: bash
run: |
set +e
BUILD_FROM="$(jq -r '.build_from.aarch64 // empty' '${{ steps.information.outputs.build }}')"
docker buildx build \
--platform linux/arm64 \
--progress=plain \
--build-arg "BUILD_FROM=${BUILD_FROM}" \
--file claude_desktop/Dockerfile \
claude_desktop >build.log 2>&1
status=$?
tail -n 300 build.log >build-tail.log
printf 'build_status=%s\n' "$status" >build-status.txt
exit 0
- name: Upload diagnostic log
uses: actions/upload-artifact@v4
with:
name: claude-aarch64-build-log
path: |
build-tail.log
build-status.txt
retention-days: 1

View File

@@ -56,19 +56,19 @@ If you want to do add the repository manually, please follow the procedure highl
### Number of addons ### Number of addons
- In the repository : 135 - In the repository : 136
- Installed : 508490 - Installed : 626324
### Top 3 ### Top 3
1. Arpspoof (59486x) 1. Arpspoof (86665x)
2. Sponsorblockcast (55582x) 2. Sponsorblockcast (82801x)
3. Flaresolverr (44486x) 3. Jellyfin (71957x)
### Architectures used ### Architectures used
- amd64: 88% - amd64: 90%
- aarch64: 12% - aarch64: 10%
### Stars evolution ### Stars evolution
@@ -77,7 +77,7 @@ If you want to do add the repository manually, please follow the procedure highl
## Add-ons provided by this repository ## Add-ons provided by this repository
%%ADDONS_LIST%% %%ADDONS_LIST%%
&#10003; [Arpspoof (59486x)](arpspoof/) : block internet connection for local network devices &#10003; [Arpspoof (86665x)](arpspoof/) : block internet connection for local network devices
&emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Farpspoof%2Fconfig.yaml) &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Farpspoof%2Fconfig.yaml)
![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Farpspoof%2Fupdater.json) ![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Farpspoof%2Fupdater.json)
@@ -143,6 +143,17 @@ If you want to do add the repository manually, please follow the procedure highl
![amd64][amd64-badge] ![amd64][amd64-badge]
![ingress][ingress-badge] ![ingress][ingress-badge]
&#10003; ![image](https://api.iconify.design/mdi/bird.svg) [BirdNET-Pi (zach7036)](birdnet-pi-zach/) : Realtime acoustic bird classification system
&emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fbirdnet-pi-zach%2Fconfig.yaml)
![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fbirdnet-pi-zach%2Fupdater.json)
![aarch64][aarch64-badge]
![amd64][amd64-badge]
![ingress][ingress-badge]
![mqtt][mqtt-badge]
![smb][smb-badge]
![localdisks][localdisks-badge]
&#10003; ![image](https://api.iconify.design/mdi/bird.svg) [BirdNET-PiPy](birdnet-pipy/) : BirdNET-PiPy bird detection with a modern web dashboard &#10003; ![image](https://api.iconify.design/mdi/bird.svg) [BirdNET-PiPy](birdnet-pipy/) : BirdNET-PiPy bird detection with a modern web dashboard
&emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fbirdnet-pipy%2Fconfig.yaml) &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fbirdnet-pipy%2Fconfig.yaml)
@@ -247,7 +258,7 @@ If you want to do add the repository manually, please follow the procedure highl
![amd64][amd64-badge] ![amd64][amd64-badge]
![ingress][ingress-badge] ![ingress][ingress-badge]
&#10003; ![image](https://api.iconify.design/mdi/robot-happy.svg) [Claude Desktop](claude_desktop/) : Claude Desktop streamed through a browser with LinuxServer Selkies &#10003; ![image](https://api.iconify.design/mdi/robot-happy.svg) [Claude Desktop](claude_desktop/) : Claude Desktop with Headroom MCP context compression and RTK acceleration
&emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fclaude_desktop%2Fconfig.yaml) &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fclaude_desktop%2Fconfig.yaml)
![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fclaude_desktop%2Fupdater.json) ![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fclaude_desktop%2Fupdater.json)
@@ -302,6 +313,7 @@ If you want to do add the repository manually, please follow the procedure highl
&#10003; [Elasticsearch server](elasticsearch/) : Free and Open, Distributed, RESTful Search Engine &#10003; [Elasticsearch server](elasticsearch/) : Free and Open, Distributed, RESTful Search Engine
&emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Felasticsearch%2Fconfig.yaml) &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Felasticsearch%2Fconfig.yaml)
![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Felasticsearch%2Fupdater.json)
![aarch64][aarch64-badge] ![aarch64][aarch64-badge]
![amd64][amd64-badge] ![amd64][amd64-badge]
@@ -508,7 +520,7 @@ If you want to do add the repository manually, please follow the procedure highl
![smb][smb-badge] ![smb][smb-badge]
![localdisks][localdisks-badge] ![localdisks][localdisks-badge]
&#10003; ![image](https://api.iconify.design/mdi/billiards-rack.svg) [Jellyfin NAS](jellyfin/) : A free Software Media System that puts you in control of managing and streaming your media &#10003; ![image](https://api.iconify.design/mdi/billiards-rack.svg) [Jellyfin (71957x) NAS](jellyfin/) : A free Software Media System that puts you in control of managing and streaming your media
&emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fjellyfin%2Fconfig.yaml) &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fjellyfin%2Fconfig.yaml)
![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fjellyfin%2Fupdater.json) ![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fjellyfin%2Fupdater.json)
@@ -571,7 +583,7 @@ If you want to do add the repository manually, please follow the procedure highl
![aarch64][aarch64-badge] ![aarch64][aarch64-badge]
![amd64][amd64-badge] ![amd64][amd64-badge]
&#10003; ![image](https://api.iconify.design/mdi/movie-search.svg) [Maintainerr](maintainerr/) : Rule-based media cleanup tool for Plex, Jellyfin and Emby. Creates collections and optionally deletes unwatched content. &#10003; ![image](https://api.iconify.design/mdi/movie-search.svg) [Maintainerr](maintainerr/) : Rule-based media cleanup tool for Plex, Jellyfin (71957x) and Emby. Creates collections and optionally deletes unwatched content.
&emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fmaintainerr%2Fconfig.yaml) &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fmaintainerr%2Fconfig.yaml)
![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fmaintainerr%2Fupdater.json) ![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fmaintainerr%2Fupdater.json)
@@ -885,7 +897,7 @@ If you want to do add the repository manually, please follow the procedure highl
![smb][smb-badge] ![smb][smb-badge]
![localdisks][localdisks-badge] ![localdisks][localdisks-badge]
&#10003; ![image](https://api.iconify.design/mdi/movie-search.svg) [Seerr](seerr/) : Open-source media request and discovery manager for Jellyfin, Plex, and Emby &#10003; ![image](https://api.iconify.design/mdi/movie-search.svg) [Seerr](seerr/) : Open-source media request and discovery manager for Jellyfin (71957x), Plex, and Emby
&emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fseerr%2Fconfig.yaml) &emsp;&emsp;![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fseerr%2Fconfig.yaml)
![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fseerr%2Fupdater.json) ![Update](https://img.shields.io/badge/dynamic/json?label=Updated&query=%24.last_update&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fseerr%2Fupdater.json)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,4 +1,7 @@
## 1.76.52 (2026-07-11)
- Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases)
## 1.76.51 (2026-06-17) ## 1.76.51 (2026-06-17)
- Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases)
## 1.76.49 (2026-06-05) ## 1.76.49 (2026-06-05)

View File

@@ -1,5 +1,5 @@
name: Aurral name: Aurral
version: "1.76.51" version: "1.76.52"
slug: aurral slug: aurral
description: >- description: >-
Self-hosted music discovery, request management, flows, and playlist Self-hosted music discovery, request management, flows, and playlist

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,9 +1,9 @@
{ {
"last_update": "2026-06-17", "last_update": "2026-07-11",
"repository": "alexbelgium/hassio-addons", "repository": "alexbelgium/hassio-addons",
"slug": "aurral", "slug": "aurral",
"source": "github", "source": "github",
"upstream_repo": "lklynet/aurral", "upstream_repo": "lklynet/aurral",
"upstream_version": "1.76.51", "upstream_version": "1.76.52",
"github_beta": false "github_beta": false
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,3 +1,5 @@
## source-20260714 (14-07-2026)
- Minor bugs fixed
## source-20260709 (09-07-2026) ## source-20260709 (09-07-2026)
- Minor bugs fixed - Minor bugs fixed
## source-20260708-4 (08-07-2026) ## source-20260708-4 (08-07-2026)

View File

@@ -127,5 +127,5 @@ slug: birdnet-go-dev
udev: true udev: true
url: https://github.com/alexbelgium/hassio-addons url: https://github.com/alexbelgium/hassio-addons
usb: true usb: true
version: "source-20260709" version: "source-20260714"
video: true video: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,3 +1,6 @@
## 20260712 (2026-07-13)
- Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases)
## nightly-20260615-4 (09-07-2026) ## nightly-20260615-4 (09-07-2026)
- Minor bugs fixed - Minor bugs fixed
## nightly-20260615-3 (05-07-2026) ## nightly-20260615-3 (05-07-2026)

View File

@@ -128,4 +128,4 @@ slug: birdnet-go
udev: true udev: true
url: https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-go url: https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-go
usb: true usb: true
version: "nightly-20260615-4" version: "20260712"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -2,10 +2,10 @@
"github_beta": true, "github_beta": true,
"github_exclude": "-4", "github_exclude": "-4",
"github_fulltag": true, "github_fulltag": true,
"last_update": "2026-06-17", "last_update": "2026-07-13",
"repository": "alexbelgium/hassio-addons", "repository": "alexbelgium/hassio-addons",
"slug": "birdnet-go", "slug": "birdnet-go",
"source": "github", "source": "github",
"upstream_repo": "tphakala/birdnet-go", "upstream_repo": "tphakala/birdnet-go",
"upstream_version": "nightly-20260615" "upstream_version": "20260712"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,4 +1,10 @@
## 0.8.4 (2026-07-13)
- Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases)
## 0.8.3 (2026-07-11)
- Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases)
## 0.8.2.1 (2026-07-05) ## 0.8.2.1 (2026-07-05)
- Re-tag of 0.8.2-1 with no content change. Home Assistant compares add-on versions with semver semantics, where a `-N` suffix counts as a *pre-release* and sorts **below** the base version — so users already on 0.8.2 saw the 0.8.2-1 nginx fix as "Up-to-date" with the Update button disabled. Four-segment `0.8.2.1` sorts above both `0.8.2` and `0.8.2-1` (and below the next upstream `0.8.3`), so the update becomes installable everywhere. - Re-tag of 0.8.2-1 with no content change. Home Assistant compares add-on versions with semver semantics, where a `-N` suffix counts as a *pre-release* and sorts **below** the base version — so users already on 0.8.2 saw the 0.8.2-1 nginx fix as "Up-to-date" with the Update button disabled. Four-segment `0.8.2.1` sorts above both `0.8.2` and `0.8.2-1` (and below the next upstream `0.8.3`), so the update becomes installable everywhere.

View File

@@ -96,4 +96,4 @@ schema:
ssl: bool? ssl: bool?
slug: birdnet-pipy slug: birdnet-pipy
url: https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-pipy url: https://github.com/alexbelgium/hassio-addons/tree/master/birdnet-pipy
version: "0.8.2.1" version: "0.8.4"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,8 +1,8 @@
{ {
"last_update": "2026-07-04", "last_update": "2026-07-13",
"repository": "alexbelgium/hassio-addons", "repository": "alexbelgium/hassio-addons",
"slug": "birdnet-pipy", "slug": "birdnet-pipy",
"source": "github", "source": "github",
"upstream_repo": "Suncuss/BirdNET-PiPy", "upstream_repo": "Suncuss/BirdNET-PiPy",
"upstream_version": "0.8.2" "upstream_version": "0.8.4"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,4 +1,7 @@
## 1.92.139-ls112 (2026-07-11)
- Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases)
## 1.92.134-ls109 (2026-07-04) ## 1.92.134-ls109 (2026-07-04)
- Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases)

View File

@@ -69,5 +69,5 @@ slug: brave
tmpfs: true tmpfs: true
udev: true udev: true
url: https://github.com/alexbelgium/hassio-addons url: https://github.com/alexbelgium/hassio-addons
version: "1.92.134-ls109" version: "1.92.139-ls112"
video: true video: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,9 +1,9 @@
{ {
"github_fulltag": "true", "github_fulltag": "true",
"last_update": "2026-07-04", "last_update": "2026-07-11",
"repository": "alexbelgium/hassio-addons", "repository": "alexbelgium/hassio-addons",
"slug": "brave", "slug": "brave",
"source": "github", "source": "github",
"upstream_repo": "linuxserver/docker-brave", "upstream_repo": "linuxserver/docker-brave",
"upstream_version": "1.92.134-ls109" "upstream_version": "1.92.139-ls112"
} }

View File

@@ -1,4 +1,7 @@
## version-30a7c401 (2026-07-11)
- Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases)
## version-7148c2a3 (2026-07-04) ## version-7148c2a3 (2026-07-04)
- Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases)

View File

@@ -71,5 +71,5 @@ slug: chromium
tmpfs: true tmpfs: true
udev: true udev: true
url: https://github.com/alexbelgium/hassio-addons url: https://github.com/alexbelgium/hassio-addons
version: "version-7148c2a3" version: "version-30a7c401"
video: true video: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,9 +1,9 @@
{ {
"github_fulltag": "true", "github_fulltag": "true",
"last_update": "2026-07-04", "last_update": "2026-07-11",
"repository": "alexbelgium/hassio-addons", "repository": "alexbelgium/hassio-addons",
"slug": "chromium", "slug": "chromium",
"source": "github", "source": "github",
"upstream_repo": "linuxserver/docker-chromium", "upstream_repo": "linuxserver/docker-chromium",
"upstream_version": "version-7148c2a3" "upstream_version": "version-30a7c401"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,3 +1,58 @@
## 1.23 (15-07-2026)
- Expose `SUDO_PASSWORD`, per LinuxServer.io's base-image convention: setting it grants the `abc` user sudo access gated by that password. Sudo access stays disabled by default when left unset. Passed straight through by the existing option-to-env-var mechanism; no rootfs changes needed.
## 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 shared `abc` Desktop 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 `abc` identity instead of the configured root UID.
- Drop root console invocations of the add-on's `/usr/local/bin/claude` wrapper to the non-root `abc` runtime before passing `--dangerously-skip-permissions`.
- Extend `claude-tools-doctor.sh` with 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_paths` for 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/claude` wrapper; 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_dashboard` and leave port `8787/tcp` unmapped 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.sh` to inspect binaries, redacted MCP registrations, hooks, proxy health, routing, project indexes, and gains.
- Install local validation tools (`jq`, `shellcheck`, `yamllint`, current `hadolint`, and current `actionlint`) 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 the `enable_terminal`, `terminal_username`, `terminal_password`, `terminal_workspace` options). 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-direct` and `claude-headroom` terminal wrapper scripts and the unused `ha_smart_context` and `dangerously_skip_permissions` options.
- Fix the Headroom dashboard being unreachable at `http://<host>:8787/dashboard`: the supervised proxy only listened on `127.0.0.1`; it now binds `0.0.0.0` so the mapped port works.
- Fix dispatch/remote sessions and sign-in persistence: install the missing `gnome-keyring` package. The existing keyring bootstrap silently no-oped without it, leaving Electron `safeStorage` unavailable ("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_mcp` plus new `ha_mcp_url`/`ha_mcp_token` options register Home Assistant's MCP Server integration in Claude through `mcp-proxy`, using the integration's stateless Streamable HTTP endpoint (`/api/mcp`).
- Write the Claude configuration files with `0600` permissions, since they hold the Home Assistant access token in clear text.
- Restrict the build-time `chmod +x` pass 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.json` as well as Claude Desktop's config, without clobbering user-customized entries.
- Install `uv` and use it for the `additional_pip` option 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 --version` inside 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) ## 1.13 (10-07-2026)
- Add the official Claude Code stable package, `tmux`, `ripgrep`, and a pinned upstream `ttyd` binary for both supported architectures. - Add the official Claude Code stable package, `tmux`, `ripgrep`, and a pinned upstream `ttyd` binary for both supported architectures.

View File

@@ -9,7 +9,32 @@
ARG BUILD_FROM ARG BUILD_FROM
ARG BUILD_VERSION ARG BUILD_VERSION
ARG RTK_VERSION="v0.43.0"
ARG RTK_COMMIT="5a7880d404db8364d602f2ecdc41dd790f64013f"
ARG TOKENSAVE_VERSION="7.2.0"
# The upstream aarch64 release is cross-built on ubuntu-latest and requires
# GLIBC 2.39. Build the pinned source on Bookworm instead so it is compatible
# with the add-on runtime on both supported architectures.
FROM rust:1.91-bookworm AS rtk-builder
ARG RTK_VERSION
ARG RTK_COMMIT
RUN git clone --depth 1 --branch "${RTK_VERSION}" https://github.com/rtk-ai/rtk.git /src/rtk && \
test "$(git -C /src/rtk rev-parse HEAD)" = "${RTK_COMMIT}" && \
cd /src/rtk && \
cargo build --release --locked && \
install -D -m 0755 target/release/rtk /out/rtk && \
/out/rtk --version
# tokensave ships no Bookworm-compatible prebuilt binary either; build the pinned
# crates.io release from source so GLIBC matches the add-on runtime.
FROM rust:1.91-bookworm AS tokensave-builder
ARG TOKENSAVE_VERSION
RUN cargo install tokensave --version "${TOKENSAVE_VERSION}" --locked --root /out && \
/out/bin/tokensave --version
FROM ${BUILD_FROM} FROM ${BUILD_FROM}
ARG BUILD_ARCH
################## ##################
# 2 Modify Image # # 2 Modify Image #
@@ -45,17 +70,21 @@ RUN curl -fsSL --retry 3 --retry-delay 2 \
# 3 Install apps # # 3 Install apps #
################## ##################
# Add rootfs # Add rootfs. Only the directories this add-on ships scripts in are traversed, so the chmod
# cannot alter executables elsewhere in the image.
COPY rootfs/ / COPY rootfs/ /
RUN find . -type f \( -name "*.sh" -o -name "run" -o -name "finish" \) -print -exec chmod +x {} \; && \ RUN find /etc/cont-init.d /etc/s6-overlay /defaults /usr/local/bin -type f \
chmod +x /usr/local/bin/claude-direct /usr/local/bin/claude-headroom /usr/local/bin/claude-terminal-shell \( -name "*.sh" -o -name "run" -o -name "finish" \) -print -exec chmod +x {} \; && \
chmod +x /usr/local/bin/claude
# Uses /bin for compatibility purposes # Uses /bin for compatibility purposes
# hadolint ignore=DL4005 # hadolint ignore=DL4005
RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \ RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \
if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi
# Install Claude Desktop, Claude Code, browser-terminal tooling, and Python tooling # Install Claude Desktop, Claude Code, Python tooling, and lightweight local validators.
# gnome-keyring provides the Secret Service backend Electron safeStorage needs to persist
# sign-in and dispatch grants.
RUN install -d -m 0755 /etc/apt/keyrings && \ RUN install -d -m 0755 /etc/apt/keyrings && \
curl -fsSLo /usr/share/keyrings/claude-desktop-archive-keyring.asc https://downloads.claude.ai/claude-desktop/key.asc && \ curl -fsSLo /usr/share/keyrings/claude-desktop-archive-keyring.asc https://downloads.claude.ai/claude-desktop/key.asc && \
curl -fsSLo /etc/apt/keyrings/claude-code.asc https://downloads.claude.ai/keys/claude-code.asc && \ curl -fsSLo /etc/apt/keyrings/claude-code.asc https://downloads.claude.ai/keys/claude-code.asc && \
@@ -71,33 +100,53 @@ RUN install -d -m 0755 /etc/apt/keyrings && \
git \ git \
gh \ gh \
ripgrep \ ripgrep \
tmux && \ jq \
shellcheck \
yamllint && \
test -x /usr/bin/claude && \
apt-get clean && \ apt-get clean && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
# ttyd is not packaged in Debian bookworm. Install the pinned upstream static binary. # Install the current upstream hadolint and actionlint releases for both supported
ARG TTYD_VERSION="1.7.7" # architectures. The GitHub release API resolves the latest asset at build time, so these
# developer tools are intentionally not version-pinned.
RUN set -eux; \ RUN set -eux; \
case "$(dpkg --print-architecture)" in \ case "${BUILD_ARCH}" in \
amd64) ttyd_arch="x86_64" ;; \ amd64) hadolint_arch="x86_64"; actionlint_arch="amd64" ;; \
arm64) ttyd_arch="aarch64" ;; \ aarch64) hadolint_arch="arm64"; actionlint_arch="arm64" ;; \
*) echo "Unsupported architecture for ttyd: $(dpkg --print-architecture)" >&2; exit 1 ;; \ *) echo "Unsupported validation-tools architecture: ${BUILD_ARCH}" >&2; exit 1 ;; \
esac; \ esac; \
curl -fsSL --retry 3 --retry-delay 2 \ hadolint_name="hadolint-linux-${hadolint_arch}"; \
-o /usr/local/bin/ttyd \ hadolint_url="$(curl -fsSL https://api.github.com/repos/hadolint/hadolint/releases/latest \
"https://github.com/tsl0922/ttyd/releases/download/${TTYD_VERSION}/ttyd.${ttyd_arch}"; \ | jq -r --arg name "${hadolint_name}" '.assets[] | select(.name == $name) | .browser_download_url' \
chmod 0755 /usr/local/bin/ttyd; \ | head -n 1)"; \
/usr/local/bin/ttyd --version test -n "${hadolint_url}"; \
curl -fsSL --retry 3 --retry-delay 2 -o /usr/local/bin/hadolint "${hadolint_url}"; \
chmod 0755 /usr/local/bin/hadolint; \
actionlint_suffix="_linux_${actionlint_arch}.tar.gz"; \
actionlint_url="$(curl -fsSL https://api.github.com/repos/rhysd/actionlint/releases/latest \
| jq -r --arg suffix "${actionlint_suffix}" '.assets[] | select(.name | endswith($suffix)) | .browser_download_url' \
| head -n 1)"; \
test -n "${actionlint_url}"; \
curl -fsSL --retry 3 --retry-delay 2 -o /tmp/actionlint.tar.gz "${actionlint_url}"; \
tar -xzf /tmp/actionlint.tar.gz -C /tmp actionlint; \
install -m 0755 /tmp/actionlint /usr/local/bin/actionlint; \
rm -f /tmp/actionlint /tmp/actionlint.tar.gz; \
hadolint --version; \
actionlint -version
# Install only the Headroom proxy, code-compression, and MCP features used by this add-on. # Copy the pinned Bookworm-built RTK and tokensave binaries and execute them in the final
# image. This makes an ABI mismatch fail the image build instead of surfacing at runtime.
COPY --from=rtk-builder /out/rtk /usr/local/bin/rtk
COPY --from=tokensave-builder /out/bin/tokensave /usr/local/bin/tokensave
RUN /usr/local/bin/rtk --version && /usr/local/bin/tokensave --version
# Install only the Headroom proxy, code-compression, and MCP features used by this add-on,
# plus mcp-proxy (stdio->HTTP bridge for the Home Assistant MCP server) and uv (fast
# installer used for the additional_pip option).
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends nodejs && \ apt-get install -y --no-install-recommends nodejs && \
pip3 install --break-system-packages "headroom-ai[proxy,code,mcp]" && \ pip3 install --break-system-packages "headroom-ai[proxy,code,mcp]" mcp-proxy uv && \
curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh -o /tmp/rtk-install.sh && \
HOME=/root sh /tmp/rtk-install.sh && \
rm /tmp/rtk-install.sh && \
if [ -x /root/.local/bin/rtk ] && [ ! -x /usr/local/bin/rtk ]; then mv /root/.local/bin/rtk /usr/local/bin/rtk; fi && \
if [ -x /usr/local/bin/rtk ]; then chmod +x /usr/local/bin/rtk; else echo "rtk binary was not installed on PATH"; exit 1; fi && \
apt-get clean && \ apt-get clean && \
rm -rf /var/lib/apt/lists/* /root/.cache rm -rf /var/lib/apt/lists/* /root/.cache
@@ -145,7 +194,6 @@ CMD [ "/ha_entrypoint.sh" ]
# 5 Labels # # 5 Labels #
############ ############
ARG BUILD_ARCH
ARG BUILD_DATE ARG BUILD_DATE
ARG BUILD_DESCRIPTION ARG BUILD_DESCRIPTION
ARG BUILD_NAME ARG BUILD_NAME

View File

@@ -4,8 +4,9 @@
![Supports amd64 Architecture][amd64-shield] ![Supports amd64 Architecture][amd64-shield]
![Project Maintenance][maintenance-shield] ![Project Maintenance][maintenance-shield]
Run Claude Desktop and an optional persistent Claude Code web terminal in one Run Claude Desktop in a LinuxServer.io Selkies add-on, with Headroom context
LinuxServer.io Selkies add-on. compression, RTK Bash-output acceleration, and TokenSave semantic code
intelligence wired in by default.
## Installation ## Installation
@@ -20,151 +21,201 @@ currently does not include Computer Use or dictation.
## Architecture ## Architecture
Claude Desktop and Claude Code run as separate clients inside the same add-on. Everything is built around the Claude Desktop app. Claude Code is installed in
They share the configured persistent home directory, Git credentials, the same image but is not exposed as a standalone service: Claude Desktop's
repositories, Claude Code configuration, Headroom storage, and RTK cowork and dispatch sessions run it internally, and they pick up the shared
configuration, but they do not share or hand off a conversation. Claude Code configuration (`~/.claude`), hooks, MCP servers, permissions, and
PATH tools.
- **Claude Desktop** uses Headroom through its MCP tools. - **Claude Desktop** uses Headroom through its MCP tools.
- **Claude Code** uses Headroom's supported `headroom wrap claude` integration. - **Claude Code sessions inside Desktop** get the same MCP servers, permission
- **RTK** filters Claude Code Bash output through its `PreToolUse` hook. mode, and RTK/TokenSave hooks through the shared Claude Code configuration.
- **tmux** keeps the terminal session running when the browser disconnects. - PATH-based Claude Code launches are routed through the supervised Headroom
proxy when `headroom_wrap_claude_code` is enabled. If a Desktop release calls
`/usr/bin/claude` directly, the session remains functional and still has the
shared permission mode and Headroom MCP tools, but transparent proxy
compression cannot be injected.
- When `permission_mode: bypass` is selected while `PUID` is `0`, the add-on
automatically remaps the shared `abc` desktop account to an unused non-root
UID before Selkies and Claude Desktop start. Claude Code refuses bypass mode
under an effective root UID.
- **gnome-keyring** provides the Secret Service backend Electron needs to
persist sign-in and dispatch permission grants across restarts.
## Optimization layers
The three bundled optimization tools are complementary:
- **RTK** rewrites supported Bash commands so Claude receives compact output.
- **TokenSave** builds a local semantic graph for explicitly selected code
repositories and steers Claude away from repeated Explore/Grep/Read fan-out.
- **Headroom** transparently compresses proxied Claude Code traffic and also
exposes on-demand compress/retrieve/statistics MCP tools to Claude Desktop.
TokenSave's complete Claude integration is installed at startup: MCP server,
permissions, PreToolUse/UserPromptSubmit/Stop hooks, global prompt rules, and
Git synchronization hooks. A repository is indexed only when it is listed in
`tokensave_project_paths`; no automatic filesystem scan is performed.
## Features ## Features
- Claude Desktop in single-app Selkies mode. - Claude Desktop in single-app Selkies mode with Home Assistant ingress.
- Home Assistant ingress support for Claude Desktop. - Official Claude Code stable package powering Desktop cowork/dispatch
- Official Claude Code stable package installed in the same image. sessions.
- Optional authenticated `ttyd` web terminal on port `7681`.
- Persistent `tmux` session shared by reconnecting terminal clients.
- Persistent `$HOME` at the configured `data_location` (default `/data/data`), - Persistent `$HOME` at the configured `data_location` (default `/data/data`),
preserving Desktop and Claude Code state across restarts. preserving Desktop and Claude Code state across restarts.
- Persistent sign-in through a bundled, auto-unlocked gnome-keyring.
- Configurable Claude Code permissions: strict prompts, automatic safe-action
approval, or explicit full bypass for trusted installations.
- Automatic non-root runtime enforcement for bypass mode, including root-console
wrapper launches.
- Optional runtime Claude Desktop updates from Anthropic's apt repository. - Optional runtime Claude Desktop updates from Anthropic's apt repository.
- Optional extra apt and pip package installation. - Optional extra apt and pip package installation (pip installs use `uv`).
- Baked-in `git`, GitHub CLI (`gh`), `ripgrep`, and terminal tooling. - Baked-in `git`, GitHub CLI (`gh`), `ripgrep`, `jq`, `shellcheck`, `yamllint`,
`hadolint`, and `actionlint`.
- Custom script support through the repository standard `claude_desktop.sh`. - Custom script support through the repository standard `claude_desktop.sh`.
- Optional bundled Claude Code optimization tools: Headroom, RTK, and Caveman. - Bundled optimization tools: Headroom, RTK, and TokenSave; Caveman remains
- Headroom dashboard exposed on mapped port `8787` when enabled. available as an opt-in plugin.
- Optional Home Assistant MCP bridge so Claude can query and control Home
Assistant.
- Independent hourly savings reports for Headroom, RTK, and TokenSave.
- `claude-tools-doctor.sh` diagnostics for binaries, routing, hooks, MCP
registrations, project indexes, proxy health, permissions, runtime identity,
and gains.
- Low-power defaults for GPU mapping, Selkies frame rate, and volatile caches. - Low-power defaults for GPU mapping, Selkies frame rate, and volatile caches.
## Claude Code terminal setup
The terminal service is enabled in the add-on configuration but remains
unavailable until authentication is configured. Port `7681` is not mapped by
default.
1. Set a unique `terminal_password`. The existing `PASSWORD` option is accepted
only as a compatibility fallback.
2. Optionally set `terminal_username` and `terminal_workspace`.
3. Map container port `7681` to a host port in the add-on **Network** section.
4. Restart the add-on.
5. Reach `http://<home-assistant-host>:7681` only through an encrypted VPN or an
HTTPS reverse proxy, then sign in with the configured terminal credentials.
The terminal opens in a persistent tmux session. Closing the browser detaches
from tmux rather than terminating commands that are already running.
Start the optimized Claude Code path with:
```shell
claude-headroom
```
This reuses the supervised Headroom proxy on `127.0.0.1:8787` and launches
Claude Code with the required routing. Headroom is told not to install RTK
because the add-on already maintains the RTK hook in
`~/.claude/settings.json`.
To bypass Headroom for troubleshooting, run:
```shell
claude-direct
```
Running `claude` directly is equivalent to the direct path. The first Claude
Code launch may require its own account authentication; Desktop and Claude Code
store separate client credentials even though both use the configured
persistent home directory.
### Multiple concurrent clients
Every browser connection attaches to the same tmux session. Concurrent clients
therefore see the same terminal, keystrokes, and resize events. This is useful
for reconnecting to one long-running session, but it is not an isolated
multi-user terminal.
### Terminal user and permissions
The service drops privileges to the LinuxServer `abc` account before starting
ttyd. The effective numeric UID and GID follow the configured `PUID` and `PGID`.
Using `PUID: 0` can provide root-equivalent access inside the add-on; use a
non-zero UID/GID where your storage permissions allow it.
The configured workspace must resolve to the persistent home directory or a
subdirectory of `/share`, `/media`, `/mnt`, `/data`, or `/config`. Existing
directories are never re-owned by the terminal service and must already be
readable, writable, and searchable by `abc`.
### Terminal security
The direct ttyd endpoint uses HTTP Basic Authentication without TLS.
Credentials and terminal traffic are unencrypted on the network. ttyd also
receives its Basic Authentication credential as a process argument, so it is
visible to processes with sufficient access inside the container.
Do not expose port `7681` directly to the public internet. Use a VPN such as
WireGuard or Tailscale, or place the endpoint behind an HTTPS reverse proxy.
Use a unique `terminal_password` rather than reusing the Selkies `PASSWORD`.
## Options ## Options
| Option | Default | Description | | Option | Default | Description |
| ------ | ------- | ----------- | | ------ | ------- | ----------- |
| `PUID` / `PGID` | `0` / `0` | Numeric user and group applied by the LinuxServer initialization. | | `PUID` / `PGID` | `0` / `0` | Numeric user and group applied by LinuxServer initialization. In bypass mode, a root `PUID` is automatically replaced at runtime by an unused non-root UID while the configured group is retained. |
| `TZ` | | Optional timezone, for example `Europe/Brussels`. | | `TZ` | | Optional timezone, for example `Europe/Brussels`. |
| `KEYBOARD` | | Optional Selkies keyboard layout. | | `KEYBOARD` | | Optional Selkies keyboard layout. |
| `PASSWORD` | | Optional password for direct Selkies ports and compatibility fallback for terminal authentication. | | `PASSWORD` | | Optional password for direct Selkies ports. |
| `SUDO_PASSWORD` | | LinuxServer.io convention: grants the `abc` user sudo access gated by this password. Sudo access is disabled by default when left unset. |
| `DRINODE` | | Optional GPU device override for Selkies. | | `DRINODE` | | Optional GPU device override for Selkies. |
| `DNS_server` | `8.8.8.8` | DNS server used by the standard DNS module. | | `DNS_server` | `8.8.8.8` | DNS server used by the standard DNS module. |
| `auto_update` | `true` | Upgrade `claude-desktop` from Anthropic's apt repository at startup. | | `auto_update` | `true` | Upgrade `claude-desktop` from Anthropic's apt repository at startup. |
| `enable_terminal` | `true` | Enable the supervised Claude Code web-terminal service. | | `permission_mode` | `auto` | Claude Code permission policy: `strict`, `auto`, or `bypass`. |
| `terminal_username` | `claude` | Username used by ttyd Basic Authentication. | | `install_headroom` | `true` | Register Headroom MCP and run the supervised local proxy. |
| `terminal_password` | | Dedicated terminal password. The service idles when this and `PASSWORD` are empty. | | `headroom_wrap_claude_code` | `true` | Route PATH-based Claude Code launches through the already-running Headroom proxy. |
| `terminal_workspace` | | Initial directory; defaults to `<data_location>/workspace`. | | `expose_headroom_dashboard` | `false` | Bind Headroom to all interfaces. Port `8787/tcp` must also be mapped manually. |
| `install_headroom` | `true` | Enable Headroom MCP for Desktop and the supervised local proxy reused by `claude-headroom`. | | `install_rtk` | `true` | Configure RTK's Claude Code `PreToolUse` Bash hook. |
| `install_rtk` | `true` | Configure RTK's Claude Code `PreToolUse` hook. | | `install_tokensave` | `true` | Install TokenSave's complete global Claude integration. |
| `install_caveman` | `true` | Install the Caveman Claude Code plugin in the persistent Claude home. | | `tokensave_project_paths` | `[]` | Explicit absolute Git repository paths to initialize or sync at startup. |
| `install_caveman` | `false` | Install the third-party Caveman Claude Code plugin at startup. |
| `enable_tools_health_report` | `true` | Write independent Headroom, RTK, and TokenSave gains to the add-on log hourly. |
| `install_github_cli` | `true` | Enable setup checks for the baked-in `git` and `gh` commands. | | `install_github_cli` | `true` | Enable setup checks for the baked-in `git` and `gh` commands. |
| `github_token` | | Optional GitHub token used to authenticate `gh` and Git operations. | | `github_token` | | Optional GitHub token used to authenticate `gh` and Git operations. |
| `github_username` | | Optional global Git author name. | | `github_username` | | Optional global Git author name. |
| `github_email` | | Optional global Git author email. | | `github_email` | | Optional global Git author email. |
| `ha_smart_context` | `true` | Enable Home Assistant smart context support for Claude tooling. | | `enable_ha_mcp` | `false` | Register Home Assistant's MCP server in Claude (requires `ha_mcp_token`). |
| `enable_ha_mcp` | `true` | Enable Home Assistant MCP support for Claude tooling. | | `ha_mcp_url` | `http://homeassistant:8123/api/mcp` | Streamable HTTP endpoint of Home Assistant's MCP Server integration. |
| `dangerously_skip_permissions` | `false` | Reserved compatibility option; it is not applied by the terminal launcher. | | `ha_mcp_token` | | Home Assistant long-lived access token used by the MCP bridge. |
| `additional_apps` | | Comma-separated Debian apt packages to install at startup. | | `additional_apps` | | Comma-separated Debian apt packages to install at startup. |
| `additional_pip` | | Comma-separated pip packages installed with `--break-system-packages`. | | `additional_pip` | | Comma-separated pip packages installed at startup (via `uv`). |
| `data_location` | `/data/data` | Persistent home directory for both Claude clients and tooling. | | `data_location` | `/data/data` | Persistent home directory for Claude and tooling. |
| `env_vars` | `[]` | Additional environment variables exported inside the container. | | `env_vars` | `[]` | Additional environment variables exported inside the container. |
### Permission modes
```yaml
permission_mode: auto
```
- `strict` keeps Claude Code's normal interactive permission prompts.
- `auto` asks Claude Code's automatic permission classifier to approve safe
operations while retaining prompts for risky actions. This is the default.
- `bypass` disables Claude Code permission checks by using
`bypassPermissions` in the shared settings and
`--dangerously-skip-permissions` for wrapper-launched sessions.
Claude Code does not permit bypass mode when its effective UID is `0`. If the
add-on is configured with `PUID: 0`, selecting `bypass` remaps only the shared
`abc` runtime account to an available non-root UID (preferring `1000`, then
`911`) before storage ownership and Desktop startup. Its configured primary
GID is retained, so group-based access to mounted Home Assistant paths remains
available. Strict and auto modes keep the configured identity unchanged.
A root shell invoking `/usr/local/bin/claude` in bypass mode is also dropped to
the remapped `abc` account. Directly invoking `/usr/bin/claude` as root still
bypasses the add-on wrapper and will be rejected by Claude Code.
`bypass` gives Claude broad authority over all mounted writable data and every
command or credential available inside the add-on. Enable it only in a trusted
installation with trusted repositories and mounts. Mounted paths must remain
accessible to the effective non-root UID or its retained group.
### TokenSave project example
Only repositories listed here are indexed. Paths must be absolute, mounted in
the add-on, and resolve to a Git working tree:
```yaml
tokensave_project_paths:
- /share/projects/hassio-addons
- /share/projects/birdnet-go
```
At startup, an uninitialized repository receives `tokensave init`; an existing
index receives an incremental `tokensave sync`. Removing a path from the option
stops automatic synchronization but does not delete its `.tokensave` database.
Configured repositories are added to Git's `safe.directory` list for the shared
runtime user before TokenSave performs repository discovery.
## Headroom behavior ## Headroom behavior
When `install_headroom` is enabled, the add-on registers `headroom mcp serve` in When `install_headroom` is enabled, the add-on registers `headroom mcp serve`
Claude Desktop and starts a supervised local Headroom backend. Desktop can use with the explicit local proxy URL in Claude Desktop and Claude Code, then starts
`headroom_compress`, `headroom_retrieve`, and `headroom_stats` through MCP. a supervised Headroom backend on `127.0.0.1:8787`.
Claude Desktop overrides `ANTHROPIC_BASE_URL`, so it is deliberately launched Claude Desktop overrides `ANTHROPIC_BASE_URL`, so Desktop chat deliberately uses
without proxy injection. The web terminal instead provides `claude-headroom`, the MCP integration. The `/usr/local/bin/claude` wrapper routes PATH-based Claude
which reuses the supervised proxy through Headroom's `--no-proxy` mode. RTK Code sessions through `headroom wrap claude --no-proxy`, reusing the supervised
setup remains owned by the add-on through Headroom's `--no-rtk` mode. backend without starting a second proxy.
The Headroom dashboard remains available at: The dashboard is disabled externally by default. To expose it:
```text 1. Set `expose_headroom_dashboard: true`.
http://<home-assistant-host>:8787/dashboard 2. Map `8787/tcp` in the add-on **Network** section.
3. Open `http://<home-assistant-host>:8787/dashboard`.
The dashboard is unauthenticated. Do not publish this port to the public
internet.
## Diagnostics
Run the following inside the add-on through a custom script or container console:
```bash
claude-tools-doctor.sh
``` ```
when the `8787/tcp` port is mapped. Treat this endpoint as sensitive and do not The report checks the tool binaries, configuration switches, configured and
expose it directly to the public internet. effective runtime identities, redacted MCP registrations, Claude hooks,
permission mode, Headroom health, TokenSave indexes, routing, and recorded
savings. It never prints MCP environment values because the Home Assistant MCP
entry can contain a long-lived token.
The hourly report can also be invoked manually:
```bash
claude-gains-report.sh
```
## Home Assistant MCP bridge
To let Claude query and control Home Assistant:
1. In Home Assistant, add the **Model Context Protocol Server** integration
(Settings → Devices & services → Add integration).
2. Create a long-lived access token (your profile → Security).
3. Set `enable_ha_mcp: true` and paste the token into `ha_mcp_token` in the
add-on configuration, then restart the add-on.
The add-on bridges Claude to the integration's stateless Streamable HTTP
endpoint (`/api/mcp`) with `mcp-proxy`. Override `ha_mcp_url` only if your Home
Assistant instance is not reachable as `homeassistant:8123` from add-ons.
## Custom scripts ## Custom scripts
@@ -178,10 +229,14 @@ the image.
Persistent state is stored in the configured `data_location` (default Persistent state is stored in the configured `data_location` (default
`/data/data`): `/data/data`):
- Claude Desktop sign-in: `~/.config/Claude` - Claude Desktop sign-in: `~/.config/Claude` (token encrypted via
- Claude Code settings, hooks, sessions, and plugins: `~/.claude` gnome-keyring; keyring DB in `~/.local/share/keyrings`)
- Default terminal workspace: `~/workspace` - Claude Code settings, hooks, sessions, plugins, and permission mode:
- Headroom and RTK user state: their standard paths below the shared home `~/.claude`
- Headroom, RTK, and TokenSave user state: their standard paths below the
shared home
- TokenSave repository indexes: `.tokensave/` inside each explicitly configured
project
Volatile cache data is redirected to `/tmp/cache` through `$XDG_CACHE_HOME` and Volatile cache data is redirected to `/tmp/cache` through `$XDG_CACHE_HOME` and
`$HOME/.cache`. `$HOME/.cache`.

View File

@@ -4,7 +4,10 @@ Two related sign-in problems when Claude Desktop runs inside the LinuxServer Sel
streamed desktop. streamed desktop.
**Status:** **Status:**
- **Shipped:** Problem B (keyring persistence) is implemented in v1.4 (Dockerfile + `rootfs/defaults/autostart`). - **Shipped:** Problem B (keyring persistence) — the `autostart` bootstrap landed in v1.4, but
the `gnome-keyring` package itself was missing from the image until v1.17 (the bootstrap
silently no-oped and Electron logged "safeStorage encryption is not available"). Fixed in
v1.17: the Dockerfile now installs `gnome-keyring`.
- **Planned only:** Problem A (in-desktop browser for OAuth) is intentionally not implemented. - **Planned only:** Problem A (in-desktop browser for OAuth) is intentionally not implemented.
The image ships no browser; complete the login with the user-side workaround below. The image ships no browser; complete the login with the user-side workaround below.
@@ -50,8 +53,9 @@ magic link into the in-session Chromium (not a phone).
### User-side workaround (no rebuild) ### User-side workaround (no rebuild)
- Add-on Configuration → `additional_apps: chromium`, restart (installed by - Add-on Configuration → `additional_apps: chromium`, restart (installed by
`rootfs/etc/cont-init.d/80-configuration.sh`). `rootfs/etc/cont-init.d/80-configuration.sh`).
- Run the two `xdg-settings`/`xdg-mime` commands once in an in-session terminal, or add them - Add the two `xdg-settings`/`xdg-mime` commands to the custom script
to the custom script `/addon_configs/db21ed7f_claude-desktop/claude-desktop.sh`. `/addon_configs/db21ed7f_claude-desktop/claude_desktop.sh` (the image ships no standalone
terminal).
--- ---
@@ -94,14 +98,14 @@ Claude Desktop uses. No extra `dbus-launch` is needed.
then exposes the Secret Service and exports `GNOME_KEYRING_CONTROL`/`SSH_AUTH_SOCK`. then exposes the Secret Service and exports `GNOME_KEYRING_CONTROL`/`SSH_AUTH_SOCK`.
- `--password-store=gnome-libsecret` forces Electron to use the libsecret backend instead - `--password-store=gnome-libsecret` forces Electron to use the libsecret backend instead
of falling back to plaintext. of falling back to plaintext.
3. Persistence: the keyring DB lives in `$HOME/.local/share/keyrings/` and `HOME=/config/data` 3. Persistence: the keyring DB lives in `$HOME/.local/share/keyrings/` and `HOME=/data/data`
(persistent add-on storage), so the empty-password login keyring survives restarts and is (persistent add-on storage), so the empty-password login keyring survives restarts and is
re-unlocked automatically each boot by the same `autostart` line — the sign-in then sticks. re-unlocked automatically each boot by the same `autostart` line — the sign-in then sticks.
### User-side workaround (no rebuild) ### User-side workaround (no rebuild)
- Add-on Configuration → `additional_apps: gnome-keyring, libsecret-1-0, dbus-x11`, restart. - Add-on Configuration → `additional_apps: gnome-keyring, libsecret-1-0, dbus-x11`, restart.
- Add the keyring-start lines above to the custom script - Add the keyring-start lines above to the custom script
`/addon_configs/db21ed7f_claude-desktop/claude-desktop.sh`, and relaunch Claude Desktop `/addon_configs/db21ed7f_claude-desktop/claude_desktop.sh`, and relaunch Claude Desktop
with `--password-store=gnome-libsecret` (e.g. edit the in-session openbox autostart). with `--password-store=gnome-libsecret` (e.g. edit the in-session openbox autostart).
--- ---

View File

@@ -2,7 +2,7 @@ arch:
- aarch64 - aarch64
- amd64 - amd64
audio: true audio: true
description: Claude Desktop with a persistent Claude Code web terminal in one add-on description: "Claude Desktop with Headroom, RTK, and TokenSave optimization"
devices: devices:
- /dev/dri - /dev/dri
- /dev/dri/card0 - /dev/dri/card0
@@ -13,8 +13,8 @@ environment:
AUTO_GPU: "1" AUTO_GPU: "1"
FM_HOME: /data/data FM_HOME: /data/data
HOME: /data/data HOME: /data/data
PGID: "0" PGID: "1000"
PUID: "0" PUID: "1000"
SELKIES_FRAMERATE: "30" SELKIES_FRAMERATE: "30"
START_DOCKER: "false" START_DOCKER: "false"
TITLE: Claude Desktop TITLE: Claude Desktop
@@ -35,35 +35,33 @@ options:
env_vars: [] env_vars: []
DNS_server: 8.8.8.8 DNS_server: 8.8.8.8
data_location: /data/data data_location: /data/data
PGID: 0
PUID: 0
additional_apps: "" additional_apps: ""
additional_pip: "" additional_pip: ""
auto_update: true auto_update: true
github_email: "" github_email: ""
ha_smart_context: true enable_ha_mcp: false
enable_ha_mcp: true ha_mcp_url: http://homeassistant:8123/api/mcp
dangerously_skip_permissions: false ha_mcp_token: ""
enable_terminal: true
terminal_username: claude
terminal_password: ""
terminal_workspace: ""
github_token: "" github_token: ""
github_username: "" github_username: ""
install_caveman: true enable_tools_health_report: true
expose_headroom_dashboard: false
headroom_wrap_claude_code: true
install_caveman: false
install_github_cli: true install_github_cli: true
install_headroom: true install_headroom: true
install_rtk: true install_rtk: true
install_tokensave: true
permission_mode: auto
tokensave_project_paths: []
panel_admin: false panel_admin: false
panel_icon: mdi:robot-happy panel_icon: mdi:robot-happy
ports: ports:
3001/tcp: null 3001/tcp: null
7681/tcp: null 8787/tcp: null
8787/tcp: 8787
ports_description: ports_description:
3001/tcp: Claude Desktop web interface 3001/tcp: Claude Desktop web interface
7681/tcp: HTTP Basic-auth Claude Code terminal (no TLS) 8787/tcp: Optional Headroom dashboard and proxy
8787/tcp: Headroom dashboard and proxy
privileged: privileged:
- SYS_ADMIN - SYS_ADMIN
- DAC_READ_SEARCH - DAC_READ_SEARCH
@@ -76,29 +74,35 @@ schema:
DRINODE: list(/dev/dri/card0|/dev/dri/card1|/dev/dri/card2|/dev/dri/renderD128|/dev/dri/renderD129|)? DRINODE: list(/dev/dri/card0|/dev/dri/card1|/dev/dri/card2|/dev/dri/renderD128|/dev/dri/renderD129|)?
KEYBOARD: list(da-dk-qwerty|de-de-qwertz|en-gb-qwerty|en-us-qwerty|es-es-qwerty|fr-ch-qwertz|fr-fr-azerty|it-it-qwerty|ja-jp-qwerty|pt-br-qwerty|sv-se-qwerty|tr-tr-qwerty)? KEYBOARD: list(da-dk-qwerty|de-de-qwertz|en-gb-qwerty|en-us-qwerty|es-es-qwerty|fr-ch-qwertz|fr-fr-azerty|it-it-qwerty|ja-jp-qwerty|pt-br-qwerty|sv-se-qwerty|tr-tr-qwerty)?
PASSWORD: str? PASSWORD: str?
PGID: int SUDO_PASSWORD: password?
PUID: int
TZ: match([A-Z][a-z]*./[A-Z][a-z]*.)? TZ: match([A-Z][a-z]*./[A-Z][a-z]*.)?
additional_apps: str? additional_apps: str?
additional_pip: str? additional_pip: str?
auto_update: bool? cifsdomain: str?
cifspassword: str?
cifsusername: str?
localdisks: str?
networkdisks: str?
github_email: str? github_email: str?
ha_smart_context: bool?
enable_ha_mcp: bool? enable_ha_mcp: bool?
dangerously_skip_permissions: bool? ha_mcp_url: str?
enable_terminal: bool? ha_mcp_token: password?
terminal_username: match(^[A-Za-z0-9_.-]+$)?
terminal_password: password?
terminal_workspace: str?
github_token: password? github_token: password?
github_username: str? github_username: str?
enable_tools_health_report: bool
expose_headroom_dashboard: bool
headroom_wrap_claude_code: bool
install_caveman: bool install_caveman: bool
install_github_cli: bool install_github_cli: bool
install_headroom: bool install_headroom: bool
install_rtk: bool install_rtk: bool
install_tokensave: bool
permission_mode: list(strict|auto|bypass)
tokensave_project_paths:
- str
slug: claude_desktop slug: claude_desktop
tmpfs: true tmpfs: true
udev: true udev: true
url: https://github.com/alexbelgium/hassio-addons url: https://github.com/alexbelgium/hassio-addons
version: "1.13" version: "1.23"
video: true video: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -22,8 +22,7 @@ else
fi fi
# Headroom is intentionally not injected into the Desktop process. Claude Desktop overrides # Headroom is intentionally not injected into the Desktop process. Claude Desktop overrides
# ANTHROPIC_BASE_URL, so Desktop uses the registered Headroom MCP tools instead. The Claude Code # ANTHROPIC_BASE_URL, so Desktop uses the registered Headroom MCP tools instead.
# terminal uses the supported `headroom wrap claude` integration through claude-headroom.
# Launch the configured command. If a custom/wrapped command fails to start, fall back to # Launch the configured command. If a custom/wrapped command fails to start, fall back to
# the plain Claude Desktop launch so the app always comes up for the user. # the plain Claude Desktop launch so the app always comes up for the user.

View File

@@ -1,4 +1,4 @@
# Hourly rtk + headroom token-savings report to the add-on log (heartbeat + gains). # Hourly RTK + Headroom + TokenSave savings report to the add-on log.
# Seeded to /data/data/crontabs/root by init-crontab-config and run by svc-cron; edit the # Seeded to /data/data/crontabs/root by init-crontab-config and run by svc-cron; edit the
# persistent copy to customize. Output goes to /proc/1/fd/1 so it shows in the add-on log. # persistent copy to customize. Output goes to /proc/1/fd/1 so it shows in the add-on log.
0 * * * * /usr/local/bin/claude-gains-report.sh > /proc/1/fd/1 2>&1 0 * * * * /usr/local/bin/claude-gains-report.sh > /proc/1/fd/1 2>&1

View File

@@ -0,0 +1,48 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
set -o pipefail
# Claude Code deliberately refuses bypass-permissions mode when its effective UID is 0.
# The add-on historically defaults PUID to 0, so switch the shared `abc` desktop user to
# an unused non-root UID before storage ownership and Selkies runtime directories are set up.
# Keep abc's configured primary group (commonly group 0) so existing group-based access to
# Home Assistant mounts is preserved. Strict and auto permission modes are unchanged.
if [ "$(bashio::config 'permission_mode')" != "bypass" ]; then
exit 0
fi
CURRENT_UID="$(id -u abc)"
if [ "$CURRENT_UID" -ne 0 ]; then
bashio::log.info "Claude bypass runtime already uses non-root UID ${CURRENT_UID}"
exit 0
fi
find_available_uid() {
local candidate owner
for candidate in 1000 911 $(seq 1001 1099); do
owner="$(getent passwd "$candidate" | cut -d: -f1 || true)"
if [ -z "$owner" ] || [ "$owner" = "abc" ]; then
printf '%s' "$candidate"
return 0
fi
done
return 1
}
TARGET_UID="$(find_available_uid || true)"
if [ -z "$TARGET_UID" ]; then
bashio::exit.nok "Claude bypass mode requires a non-root runtime user, but no free fallback UID was found"
fi
usermod --uid "$TARGET_UID" abc
if [ "$(id -u abc)" -eq 0 ]; then
bashio::exit.nok "Unable to switch the Claude Desktop runtime away from root for bypass mode"
fi
mkdir -p /run/s6/container_environment
printf '%s' "$TARGET_UID" > /run/s6/container_environment/CLAUDE_RUNTIME_UID
printf '%s' "$(id -g abc)" > /run/s6/container_environment/CLAUDE_RUNTIME_GID
bashio::log.warning "Claude bypass mode cannot run as root; remapped abc from UID 0 to UID ${TARGET_UID} (GID $(id -g abc))"

View File

@@ -3,9 +3,10 @@
# shellcheck disable=SC2046 # shellcheck disable=SC2046
set -e set -e
# Define user # Use the effective shared desktop user identity. In bypass mode an earlier init script may
PUID=$(bashio::config "PUID") # remap abc away from UID 0 because Claude Code rejects bypass permissions when run as root.
PGID=$(bashio::config "PGID") PUID="$(id -u abc)"
PGID="$(id -g abc)"
# Check data location # Check data location
LOCATION="$(bashio::config 'data_location')" LOCATION="$(bashio::config 'data_location')"

View File

@@ -24,7 +24,12 @@ fi
if bashio::config.has_value 'additional_pip'; then if bashio::config.has_value 'additional_pip'; then
for p in $(bashio::config 'additional_pip' | tr ',' ' '); do for p in $(bashio::config 'additional_pip' | tr ',' ' '); do
bashio::log.green "... pip: $p" bashio::log.green "... pip: $p"
pip3 install --break-system-packages "$p" || bashio::log.fatal "Error: pip package $p failed" # Prefer uv (much faster resolver/installer); fall back to pip3 when unavailable.
if command -v uv &> /dev/null; then
uv pip install --system --break-system-packages "$p" || bashio::log.fatal "Error: pip package $p failed"
else
pip3 install --break-system-packages "$p" || bashio::log.fatal "Error: pip package $p failed"
fi
done done
fi fi

View File

@@ -2,11 +2,9 @@
# shellcheck shell=bash # shellcheck shell=bash
set -e set -e
if bashio::config.true 'auto_update'; then bashio::log.info "Checking for Claude Desktop updates..."
bashio::log.info "Checking for Claude Desktop updates..." if apt-get update -o Acquire::http::Timeout=10 -o Acquire::https::Timeout=10 &> /dev/null && apt-get install -y --only-upgrade claude-desktop &> /dev/null; then
if apt-get update -o Acquire::http::Timeout=10 -o Acquire::https::Timeout=10 &> /dev/null && apt-get install -y --only-upgrade claude-desktop &> /dev/null; then bashio::log.info "Claude Desktop version: $(dpkg-query -W -f='${Version}' claude-desktop)"
bashio::log.info "Claude Desktop version: $(dpkg-query -W -f='${Version}' claude-desktop)" else
else bashio::log.warning "Update check failed (offline?), keeping current version"
bashio::log.warning "Update check failed (offline?), keeping current version"
fi
fi fi

View File

@@ -0,0 +1,36 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
set -o pipefail
if ! bashio::config.true 'install_tokensave' || ! command -v git > /dev/null 2>&1; then
exit 0
fi
declare -A REPOS_SEEN=()
while IFS= read -r configured_path; do
configured_path="${configured_path#"${configured_path%%[![:space:]]*}"}"
configured_path="${configured_path%"${configured_path##*[![:space:]]}"}"
[ -n "$configured_path" ] || continue
case "$configured_path" in
/*) ;;
*) continue ;;
esac
[ -d "$configured_path" ] || continue
# The one-shot safe.directory override is used only to discover the repository root.
# Persist the resolved root in the shared runtime user's Git config before 82-claude_tools.sh
# performs normal repository detection, avoiding Git's dubious-ownership rejection.
repo_root="$(s6-setuidgid abc env HOME="$HOME" \
git -c safe.directory='*' -C "$configured_path" rev-parse --show-toplevel 2> /dev/null || true)"
[ -n "$repo_root" ] && [ "$repo_root" != "/" ] || continue
[[ -z "${REPOS_SEEN[$repo_root]:-}" ]] || continue
REPOS_SEEN[$repo_root]=1
if ! s6-setuidgid abc env HOME="$HOME" git config --global --get-all safe.directory \
| grep -Fxq -- "$repo_root"; then
s6-setuidgid abc env HOME="$HOME" git config --global --add safe.directory "$repo_root"
bashio::log.info "Marked TokenSave repository as safe for Git: ${repo_root}"
fi
done < <(bashio::config.array 'tokensave_project_paths')

View File

@@ -7,69 +7,210 @@ PUID="$(if bashio::config.has_value 'PUID'; then bashio::config 'PUID'; else ech
PGID="$(if bashio::config.has_value 'PGID'; then bashio::config 'PGID'; else echo '0'; fi)" PGID="$(if bashio::config.has_value 'PGID'; then bashio::config 'PGID'; else echo '0'; fi)"
mkdir -p "$HOME/.claude" mkdir -p "$HOME/.claude"
run_as_runtime_user() {
s6-setuidgid abc env HOME="$HOME" "$@"
}
CLAUDE_DESKTOP_COMMAND_FILE="/tmp/claude-desktop-command" CLAUDE_DESKTOP_COMMAND_FILE="/tmp/claude-desktop-command"
DEFAULT_CLAUDE_DESKTOP_COMMAND='claude-desktop --no-sandbox --disable-dev-shm-usage --password-store=gnome-libsecret' DEFAULT_CLAUDE_DESKTOP_COMMAND='claude-desktop --no-sandbox --disable-dev-shm-usage --password-store=gnome-libsecret'
printf '%s\n' "$DEFAULT_CLAUDE_DESKTOP_COMMAND" > "$CLAUDE_DESKTOP_COMMAND_FILE" printf '%s\n' "$DEFAULT_CLAUDE_DESKTOP_COMMAND" > "$CLAUDE_DESKTOP_COMMAND_FILE"
# headroom's "wrap"/proxy routing works by setting ANTHROPIC_BASE_URL, which the Claude Desktop # Headroom's proxy routing works by setting ANTHROPIC_BASE_URL, which the Claude Desktop
# Electron app force-overrides to the production endpoint (headroom #869), so transparent # Electron app force-overrides to the production endpoint (headroom #869). Desktop therefore
# compression cannot be applied to the desktop launch. The integration that does work with # uses Headroom's MCP tools. Claude Code launches that resolve `claude` through PATH use the
# Claude Desktop is headroom's MCP server, which exposes the headroom_compress/headroom_retrieve/ # add-on's /usr/local/bin/claude wrapper and can be transparently proxied when enabled.
# headroom_stats tools inside the app. Register it in Claude Desktop's MCP config, leaving the #
# plain launch untouched. The merge is idempotent and preserves any other MCP servers. # Register the add-on-managed MCP servers (headroom, tokensave, homeassistant) in both Claude
# Desktop's config and Claude Code's user config (used by Desktop cowork/dispatch sessions).
# The merge is idempotent, preserves any other MCP servers, never overwrites a user-customized
# entry with a different command, and removes only add-on-managed entries when disabled.
CLAUDE_DESKTOP_CONFIG="$HOME/.config/Claude/claude_desktop_config.json" CLAUDE_DESKTOP_CONFIG="$HOME/.config/Claude/claude_desktop_config.json"
CLAUDE_CODE_CONFIG="$HOME/.claude.json"
HEADROOM_ENABLED=false
if bashio::config.true 'install_headroom'; then if bashio::config.true 'install_headroom'; then
if command -v headroom &> /dev/null; then if command -v headroom &> /dev/null; then
bashio::log.info "headroom $(headroom --version 2> /dev/null || true) available; registering the headroom MCP server for Claude Desktop" HEADROOM_ENABLED=true
HEADROOM_BIN="$(command -v headroom)" CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_CONFIG" python3 - <<'PY' || bashio::log.warning "Unable to register the headroom MCP server automatically" bashio::log.info "headroom $(headroom --version 2> /dev/null || true) available; registering the headroom MCP server"
import json
import os
from pathlib import Path
path = Path(os.environ["CLAUDE_DESKTOP_CONFIG"])
try:
data = json.loads(path.read_text()) if path.exists() else {}
if not isinstance(data, dict):
data = {}
except Exception:
if path.exists():
path.rename(path.with_suffix(path.suffix + ".bak"))
data = {}
servers = data.get("mcpServers")
if not isinstance(servers, dict):
servers = {}
data["mcpServers"] = servers
servers["headroom"] = {"command": os.environ.get("HEADROOM_BIN", "headroom"), "args": ["mcp", "serve"]}
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data, indent=2) + "\n")
PY
else else
bashio::log.warning "headroom is not available" bashio::log.warning "headroom is not available"
fi fi
elif [ -f "$CLAUDE_DESKTOP_CONFIG" ]; then fi
bashio::log.info "Removing the headroom MCP server from Claude Desktop"
CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_CONFIG" python3 - <<'PY' || bashio::log.warning "Unable to remove the headroom MCP server automatically" TOKENSAVE_ENABLED=false
if bashio::config.true 'install_tokensave'; then
if command -v tokensave &> /dev/null; then
TOKENSAVE_ENABLED=true
bashio::log.info "tokensave $(tokensave --version 2> /dev/null || true) available; configuring the complete Claude Code integration"
# The upstream installer adds the MCP entry, PreToolUse/UserPromptSubmit/Stop hooks,
# MCP permissions, global CLAUDE.md rules, and the global post-commit/checkout sync hook.
run_as_runtime_user tokensave install --agent claude --git-hook yes \
|| bashio::log.warning "tokensave Claude Code integration setup failed"
else
bashio::log.warning "tokensave is not available"
fi
elif command -v tokensave &> /dev/null; then
bashio::log.info "Removing the tokensave Claude Code integration"
run_as_runtime_user tokensave uninstall --agent claude \
|| bashio::log.warning "tokensave Claude Code integration removal failed"
fi
HA_MCP_ENABLED=false
HA_MCP_URL=""
HA_MCP_TOKEN=""
if bashio::config.true 'enable_ha_mcp'; then
HA_MCP_URL="$(bashio::config 'ha_mcp_url' 'http://homeassistant:8123/api/mcp')"
if bashio::config.has_value 'ha_mcp_token'; then
HA_MCP_TOKEN="$(bashio::config 'ha_mcp_token')"
fi
if [ -z "$HA_MCP_TOKEN" ]; then
bashio::log.warning "enable_ha_mcp is on but ha_mcp_token is empty; set a Home Assistant long-lived access token (Profile -> Security) and enable the 'Model Context Protocol Server' integration"
elif ! command -v mcp-proxy &> /dev/null; then
bashio::log.warning "mcp-proxy is not available; cannot register the Home Assistant MCP server"
else
HA_MCP_ENABLED=true
bashio::log.info "Registering the Home Assistant MCP server (${HA_MCP_URL})"
fi
fi
HEADROOM_ENABLED="$HEADROOM_ENABLED" HEADROOM_BIN="$(command -v headroom || echo headroom)" \
TOKENSAVE_ENABLED="$TOKENSAVE_ENABLED" TOKENSAVE_BIN="$(command -v tokensave || echo tokensave)" \
HA_MCP_ENABLED="$HA_MCP_ENABLED" HA_MCP_URL="$HA_MCP_URL" HA_MCP_TOKEN="$HA_MCP_TOKEN" \
MCP_PROXY_BIN="$(command -v mcp-proxy || echo mcp-proxy)" \
CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_CONFIG" CLAUDE_CODE_CONFIG="$CLAUDE_CODE_CONFIG" \
python3 - <<'PY' || bashio::log.warning "Unable to update the MCP server registrations automatically"
import json import json
import os import os
from pathlib import Path from pathlib import Path
path = Path(os.environ["CLAUDE_DESKTOP_CONFIG"]) MANAGED_BASENAMES = {
data = json.loads(path.read_text()) "headroom": "headroom",
if isinstance(data, dict): "tokensave": "tokensave",
"homeassistant": "mcp-proxy",
}
desired = {}
if os.environ["HEADROOM_ENABLED"] == "true":
desired["headroom"] = {
"command": os.environ["HEADROOM_BIN"],
"args": ["mcp", "serve", "--proxy-url", "http://127.0.0.1:8787"],
}
if os.environ["TOKENSAVE_ENABLED"] == "true":
desired["tokensave"] = {"command": os.environ["TOKENSAVE_BIN"], "args": ["serve"]}
if os.environ["HA_MCP_ENABLED"] == "true":
# Home Assistant's MCP Server integration speaks stateless Streamable HTTP on /api/mcp;
# mcp-proxy defaults to SSE, so the transport flags are required.
desired["homeassistant"] = {
"command": os.environ["MCP_PROXY_BIN"],
"args": ["--transport=streamablehttp", "--stateless", os.environ["HA_MCP_URL"]],
"env": {"API_ACCESS_TOKEN": os.environ["HA_MCP_TOKEN"]},
}
# An entry is add-on-managed when its command is one of our binaries living outside the
# persistent home. Matching on the basename (rather than the exact path recorded at write
# time) keeps entries updatable when a base-image upgrade moves the binary, while commands
# under $HOME stay untouched because those are user-installed.
HOME_PREFIX = os.path.expanduser("~") + os.sep
def is_managed(name, entry):
if not isinstance(entry, dict):
return False
command = entry.get("command")
if not isinstance(command, str) or command.startswith(HOME_PREFIX):
return False
return os.path.basename(command) == MANAGED_BASENAMES[name]
for config_var, stdio_type in (("CLAUDE_DESKTOP_CONFIG", False), ("CLAUDE_CODE_CONFIG", True)):
path = Path(os.environ[config_var])
try:
data = json.loads(path.read_text()) if path.exists() else {}
if not isinstance(data, dict):
data = {}
except Exception:
if path.exists():
path.rename(path.with_suffix(path.suffix + ".bak"))
data = {}
servers = data.get("mcpServers") servers = data.get("mcpServers")
if isinstance(servers, dict) and servers.pop("headroom", None) is not None: if not isinstance(servers, dict):
if not servers: servers = {}
data.pop("mcpServers", None) changed = False
path.write_text(json.dumps(data, indent=2) + "\n") for name in MANAGED_BASENAMES:
existing = servers.get(name)
if name in desired:
entry = dict(desired[name])
if stdio_type:
entry["type"] = "stdio"
if existing is None or is_managed(name, existing):
if existing != entry:
servers[name] = entry
changed = True
elif existing is not None and is_managed(name, existing):
del servers[name]
changed = True
if not changed:
continue
if servers:
data["mcpServers"] = servers
else:
data.pop("mcpServers", None)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data, indent=2) + "\n")
# The Home Assistant long-lived access token is stored here in clear text.
path.chmod(0o600)
PY PY
# Initialize or incrementally sync only explicitly configured repositories. TokenSave deliberately
# requires one-time per-project opt-in; an empty list therefore has no startup or storage cost.
if $TOKENSAVE_ENABLED; then
declare -A TOKENSAVE_REPOS_SEEN=()
while IFS= read -r configured_path; do
# Trim surrounding whitespace while preserving spaces inside paths.
configured_path="${configured_path#"${configured_path%%[![:space:]]*}"}"
configured_path="${configured_path%"${configured_path##*[![:space:]]}"}"
[ -n "$configured_path" ] || continue
case "$configured_path" in
/*) ;;
*)
bashio::log.warning "Skipping non-absolute tokensave_project_paths entry: ${configured_path}"
continue
;;
esac
if [ ! -d "$configured_path" ]; then
bashio::log.warning "Skipping missing TokenSave project path: ${configured_path}"
continue
fi
repo_root="$(git -C "$configured_path" rev-parse --show-toplevel 2> /dev/null || true)"
if [ -z "$repo_root" ] || [ "$repo_root" = "/" ]; then
bashio::log.warning "Skipping TokenSave path that is not a supported Git repository: ${configured_path}"
continue
fi
if [[ -n "${TOKENSAVE_REPOS_SEEN[$repo_root]:-}" ]]; then
continue
fi
TOKENSAVE_REPOS_SEEN[$repo_root]=1
if [ -f "$repo_root/.tokensave/tokensave.db" ]; then
bashio::log.info "Synchronizing TokenSave index: ${repo_root}"
run_as_runtime_user tokensave sync "$repo_root" \
|| bashio::log.warning "TokenSave sync failed for ${repo_root}"
else
bashio::log.info "Initializing TokenSave index: ${repo_root}"
run_as_runtime_user tokensave init "$repo_root" \
|| bashio::log.warning "TokenSave initialization failed for ${repo_root}"
fi
done < <(bashio::config.array 'tokensave_project_paths')
fi fi
# Guide Claude to actually use the headroom compression tools so the MCP integration produces # Guide Claude to actually use the Headroom compression tools so the MCP integration produces
# real savings (otherwise the tools sit unused and `headroom savings` stays empty). Managed, # real savings when transparent proxying is unavailable. Managed, idempotent block appended to
# idempotent block appended to the user's global CLAUDE.md; removed when headroom is disabled. # the user's global CLAUDE.md; removed when Headroom is disabled.
CLAUDE_MD="$HOME/.claude/CLAUDE.md" CLAUDE_MD="$HOME/.claude/CLAUDE.md"
HEADROOM_GUIDE_BEGIN="<!-- BEGIN headroom (managed by claude_desktop addon) -->" HEADROOM_GUIDE_BEGIN="<!-- BEGIN headroom (managed by claude_desktop addon) -->"
if bashio::config.true 'install_headroom'; then if $HEADROOM_ENABLED; then
mkdir -p "$(dirname "$CLAUDE_MD")" mkdir -p "$(dirname "$CLAUDE_MD")"
if ! { [ -f "$CLAUDE_MD" ] && grep -qF "$HEADROOM_GUIDE_BEGIN" "$CLAUDE_MD"; }; then if ! { [ -f "$CLAUDE_MD" ] && grep -qF "$HEADROOM_GUIDE_BEGIN" "$CLAUDE_MD"; }; then
bashio::log.info "Adding headroom usage guidance to CLAUDE.md" bashio::log.info "Adding headroom usage guidance to CLAUDE.md"
@@ -112,14 +253,13 @@ fi
if bashio::config.true 'install_rtk'; then if bashio::config.true 'install_rtk'; then
if command -v rtk &> /dev/null; then if command -v rtk &> /dev/null; then
if [ -f "$HOME/.claude/settings.json" ] && grep -q 'rtk hook claude' "$HOME/.claude/settings.json"; then bashio::log.info "Configuring rtk Claude Code integration"
bashio::log.info "rtk Claude Code hook already configured" run_as_runtime_user env RTK_NONINTERACTIVE=1 rtk init -g \
else || bashio::log.warning "rtk global files configuration failed"
bashio::log.info "Configuring rtk Claude Code hook" python3 - <<'PY' || bashio::log.warning "Unable to configure rtk hook automatically"
RTK_NONINTERACTIVE=1 rtk init -g || bashio::log.warning "rtk global files configuration failed"
python3 - <<'PY' || bashio::log.warning "Unable to configure rtk hook automatically"
import json import json
from pathlib import Path from pathlib import Path
path = Path.home() / ".claude" / "settings.json" path = Path.home() / ".claude" / "settings.json"
try: try:
data = json.loads(path.read_text()) if path.exists() else {} data = json.loads(path.read_text()) if path.exists() else {}
@@ -137,7 +277,6 @@ if not any("rtk hook claude" in json.dumps(entry) for entry in pre if isinstance
path.parent.mkdir(parents=True, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data, indent=2) + "\n") path.write_text(json.dumps(data, indent=2) + "\n")
PY PY
fi
else else
bashio::log.warning "rtk is not available" bashio::log.warning "rtk is not available"
fi fi
@@ -209,16 +348,17 @@ if bashio::config.true 'install_caveman'; then
bashio::log.info "caveman Claude Code plugin already configured" bashio::log.info "caveman Claude Code plugin already configured"
else else
bashio::log.info "Installing caveman Claude Code plugin" bashio::log.info "Installing caveman Claude Code plugin"
curl --connect-timeout 10 --max-time 60 -fsSL https://raw.githubusercontent.com/JuliusBrussee/caveman/main/install.sh | bash >/dev/null || bashio::log.warning "caveman install failed (offline?)" curl --connect-timeout 10 --max-time 60 -fsSL https://raw.githubusercontent.com/JuliusBrussee/caveman/main/install.sh | bash > /dev/null \
|| bashio::log.warning "caveman install failed (offline?)"
fi fi
else else
bashio::log.info "Disabling caveman Claude Code plugin" bashio::log.info "Disabling caveman Claude Code plugin"
find "$HOME/.claude" -maxdepth 4 -iname '*caveman*' -exec rm -rf {} + 2> /dev/null || true find "$HOME/.claude" -maxdepth 4 -iname '*caveman*' -exec rm -rf {} + 2> /dev/null || true
fi fi
# Startup configuration runs as root, while Claude Desktop and the web terminal run as abc. # Startup configuration runs as root, while Claude Desktop runs as abc. Return managed
# Return managed persistent files to the configured runtime UID/GID after all writes complete. # persistent files to the configured runtime UID/GID after all writes complete.
for managed_path in "$HOME/.claude" "$HOME/.config/Claude"; do for managed_path in "$HOME/.claude" "$HOME/.claude.json" "$HOME/.config/Claude"; do
if [ -e "$managed_path" ]; then if [ -e "$managed_path" ]; then
chown -R -- "${PUID}:${PGID}" "$managed_path" || bashio::log.warning "Unable to set ownership on $managed_path" chown -R -- "${PUID}:${PGID}" "$managed_path" || bashio::log.warning "Unable to set ownership on $managed_path"
fi fi

View File

@@ -0,0 +1,92 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
set -o pipefail
PUID="$(if bashio::config.has_value 'PUID'; then bashio::config 'PUID'; else echo '0'; fi)"
PGID="$(if bashio::config.has_value 'PGID'; then bashio::config 'PGID'; else echo '0'; fi)"
PERMISSION_MODE="$(bashio::config 'permission_mode')"
SETTINGS_PATH="$HOME/.claude/settings.json"
STATE_PATH="$HOME/.claude/.addon-permission-mode.json"
case "$PERMISSION_MODE" in
strict|auto|bypass) ;;
*)
bashio::log.warning "Unknown permission_mode '${PERMISSION_MODE}'; falling back to strict"
PERMISSION_MODE="strict"
;;
esac
mkdir -p "$(dirname "$SETTINGS_PATH")"
PERMISSION_MODE="$PERMISSION_MODE" SETTINGS_PATH="$SETTINGS_PATH" STATE_PATH="$STATE_PATH" python3 - <<'PY'
import json
import os
from pathlib import Path
mode = os.environ["PERMISSION_MODE"]
settings_path = Path(os.environ["SETTINGS_PATH"])
state_path = Path(os.environ["STATE_PATH"])
try:
settings = json.loads(settings_path.read_text()) if settings_path.exists() else {}
except (OSError, json.JSONDecodeError):
if settings_path.exists():
settings_path.rename(settings_path.with_suffix(settings_path.suffix + ".bak"))
settings = {}
if not isinstance(settings, dict):
settings = {}
try:
state = json.loads(state_path.read_text()) if state_path.exists() else None
except (OSError, json.JSONDecodeError):
state = None
if not isinstance(state, dict):
state = None
permissions = settings.get("permissions")
if not isinstance(permissions, dict):
permissions = {}
if mode == "strict":
# Restore the value that existed before the add-on first managed this setting.
if state is not None:
if state.get("previous_exists"):
permissions["defaultMode"] = state.get("previous_value")
else:
permissions.pop("defaultMode", None)
state_path.unlink(missing_ok=True)
else:
if state is None:
state = {
"previous_exists": "defaultMode" in permissions,
"previous_value": permissions.get("defaultMode"),
}
state_path.write_text(json.dumps(state, indent=2) + "\n")
state_path.chmod(0o600)
permissions["defaultMode"] = "auto" if mode == "auto" else "bypassPermissions"
if permissions:
settings["permissions"] = permissions
else:
settings.pop("permissions", None)
settings_path.write_text(json.dumps(settings, indent=2) + "\n")
settings_path.chmod(0o600)
PY
case "$PERMISSION_MODE" in
strict)
bashio::log.info "Claude Code permission mode: strict (normal prompts)"
;;
auto)
bashio::log.info "Claude Code permission mode: auto (safe actions approved automatically)"
;;
bypass)
bashio::log.warning "Claude Code permission mode: bypass (permission checks disabled for mounted data and available tools)"
;;
esac
chown -- "${PUID}:${PGID}" "$SETTINGS_PATH" 2> /dev/null || true
if [ -e "$STATE_PATH" ]; then
chown -- "${PUID}:${PGID}" "$STATE_PATH" 2> /dev/null || true
fi

View File

@@ -0,0 +1,17 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# Earlier configuration scripts intentionally run as root and may use the configured PUID/PGID
# values when returning files to the runtime user. In bypass mode PUID can still be configured as
# 0 even though 19-claude_bypass_runtime.sh remapped abc to a non-root UID. Reconcile ownership
# with the effective desktop identity after all Claude configuration writes are complete.
RUNTIME_UID="$(id -u abc)"
RUNTIME_GID="$(id -g abc)"
for managed_path in "$HOME/.claude" "$HOME/.claude.json" "$HOME/.config/Claude"; do
if [ -e "$managed_path" ]; then
chown -R -- "${RUNTIME_UID}:${RUNTIME_GID}" "$managed_path" \
|| bashio::log.warning "Unable to set effective runtime ownership on $managed_path"
fi
done

View File

@@ -1,101 +0,0 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
set -o pipefail
declare port=7681
declare username
declare password=""
declare workspace
declare canonical_workspace
export PATH="${HOME:-/data/data}/.local/bin:/usr/local/bin:/usr/bin:/bin:${PATH:-}"
if bashio::config.has_value 'enable_terminal' && ! bashio::config.true 'enable_terminal'; then
bashio::log.info "svc-claude-terminal: terminal disabled; idling"
exec sleep infinity
fi
if [ -z "${HOME:-}" ]; then
bashio::log.error "svc-claude-terminal: HOME is not initialized; idling"
exec sleep infinity
fi
if ! command -v ttyd >/dev/null 2>&1 || ! command -v tmux >/dev/null 2>&1 || ! command -v claude >/dev/null 2>&1; then
bashio::log.error "svc-claude-terminal: ttyd, tmux, or Claude Code is missing; idling"
exec sleep infinity
fi
username="claude"
if bashio::config.has_value 'terminal_username'; then
username="$(bashio::config 'terminal_username')"
fi
if bashio::config.has_value 'terminal_password'; then
password="$(bashio::config 'terminal_password')"
elif bashio::config.has_value 'PASSWORD'; then
bashio::log.warning "svc-claude-terminal: using PASSWORD as fallback for terminal authentication; prefer a unique terminal_password"
password="$(bashio::config 'PASSWORD')"
fi
if [ -z "$password" ]; then
bashio::log.warning "svc-claude-terminal: set terminal_password (or PASSWORD) before mapping port ${port}; terminal will remain disabled"
exec sleep infinity
fi
workspace="${HOME}/workspace"
if bashio::config.has_value 'terminal_workspace'; then
workspace="$(bashio::config 'terminal_workspace')"
fi
if [[ "$workspace" != /* ]]; then
bashio::log.error "svc-claude-terminal: terminal_workspace must be an absolute path; idling"
exec sleep infinity
fi
if [ -L "$workspace" ]; then
bashio::log.error "svc-claude-terminal: terminal_workspace must not be a symbolic link; idling"
exec sleep infinity
fi
if ! canonical_workspace="$(realpath -m -- "$workspace")"; then
bashio::log.error "svc-claude-terminal: unable to resolve terminal_workspace '$workspace'; idling"
exec sleep infinity
fi
workspace="$canonical_workspace"
case "$workspace" in
"$HOME" | "$HOME"/* | /share/* | /media/* | /mnt/* | /data/* | /config/*)
;;
*)
bashio::log.error "svc-claude-terminal: terminal_workspace must be the configured data_location or a subdirectory of /share, /media, /mnt, /data, or /config; idling"
exec sleep infinity
;;
esac
if [ ! -e "$workspace" ]; then
if ! install -d -m 0750 -o abc -g abc -- "$workspace"; then
bashio::log.error "svc-claude-terminal: failed to create workspace '$workspace'; idling"
exec sleep infinity
fi
elif [ ! -d "$workspace" ]; then
bashio::log.error "svc-claude-terminal: terminal_workspace '$workspace' is not a directory; idling"
exec sleep infinity
fi
if ! s6-setuidgid abc test -r "$workspace" ||
! s6-setuidgid abc test -w "$workspace" ||
! s6-setuidgid abc test -x "$workspace"; then
bashio::log.error "svc-claude-terminal: workspace '$workspace' must be readable, writable, and searchable by user abc; idling"
exec sleep infinity
fi
export CLAUDE_TERMINAL_WORKSPACE="$workspace"
bashio::log.info "svc-claude-terminal: starting authenticated ttyd terminal on port ${port}; workspace=${workspace}"
exec s6-setuidgid abc ttyd \
-p "$port" \
-W \
-O \
-c "${username}:${password}" \
/usr/local/bin/claude-terminal-shell

View File

@@ -3,7 +3,13 @@
declare port=8787 declare port=8787
declare host=127.0.0.1 declare host=127.0.0.1
if bashio::config.true 'install_headroom' && command -v headroom >/dev/null 2>&1; then # The dashboard is unauthenticated. Keep it container-local by default and bind all
# interfaces only when the user explicitly opts in and maps port 8787.
if bashio::config.true 'expose_headroom_dashboard'; then
host=0.0.0.0
fi
if bashio::config.true 'install_headroom' && command -v headroom > /dev/null 2>&1; then
bashio::log.info "svc-headroom: starting local Headroom proxy on ${host}:${port}" bashio::log.info "svc-headroom: starting local Headroom proxy on ${host}:${port}"
exec s6-setuidgid abc headroom proxy --host "${host}" --port "${port}" --code-aware exec s6-setuidgid abc headroom proxy --host "${host}" --port "${port}" --code-aware
fi fi

View File

@@ -0,0 +1,53 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -o pipefail
REAL_CLAUDE="/usr/bin/claude"
HEADROOM_BIN="/usr/local/bin/headroom"
HEADROOM_URL="http://127.0.0.1:8787"
PERMISSION_MODE="$(bashio::config 'permission_mode')"
declare -a CLAUDE_PERMISSION_ARGS=()
case "$PERMISSION_MODE" in
bypass)
CLAUDE_PERMISSION_ARGS+=("--dangerously-skip-permissions")
;;
auto)
CLAUDE_PERMISSION_ARGS+=("--permission-mode" "auto")
;;
strict|"")
;;
*)
echo "claude wrapper: unknown permission_mode '${PERMISSION_MODE}', using strict mode" >&2
;;
esac
if [ ! -x "$REAL_CLAUDE" ]; then
echo "claude wrapper: ${REAL_CLAUDE} is unavailable" >&2
exit 127
fi
# Claude Code rejects bypass mode when the effective UID is 0. Normal Desktop sessions run
# as abc, which startup remaps to a non-root UID when bypass is selected. Also handle a user
# invoking this wrapper directly from a root container console by dropping to abc here.
if [ "$PERMISSION_MODE" = "bypass" ] && [ "$(id -u)" -eq 0 ]; then
if command -v s6-setuidgid > /dev/null 2>&1 && [ "$(id -u abc)" -ne 0 ]; then
exec s6-setuidgid abc "$0" "$@"
fi
echo "claude wrapper: bypass mode requires a non-root runtime user, but abc is still UID 0" >&2
exit 1
fi
if bashio::config.true 'install_headroom' && bashio::config.true 'headroom_wrap_claude_code'; then
if [ -x "$HEADROOM_BIN" ] && curl -fsS --max-time 2 "${HEADROOM_URL}/health" > /dev/null 2>&1; then
# Put /usr/bin before /usr/local/bin while Headroom resolves its upstream `claude`
# executable; otherwise it would resolve this wrapper recursively.
export HEADROOM_CONTEXT_TOOL="rtk"
exec env PATH="/usr/bin:/bin:/usr/local/bin" \
"$HEADROOM_BIN" wrap claude --no-proxy -- \
"${CLAUDE_PERMISSION_ARGS[@]}" "$@"
fi
echo "claude wrapper: Headroom proxy is unavailable; launching Claude Code directly" >&2
fi
exec "$REAL_CLAUDE" "${CLAUDE_PERMISSION_ARGS[@]}" "$@"

View File

@@ -1,4 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
exec claude "$@"

View File

@@ -1,34 +1,44 @@
#!/usr/bin/with-contenv bashio #!/usr/bin/with-contenv bashio
# Hourly rtk + headroom token-savings snapshot for the add-on log. # Hourly RTK + Headroom + TokenSave token-savings snapshot for the add-on log.
# Invoked by cron (see /defaults/crontabs/root); its stdout is redirected to /proc/1/fd/1, # Invoked by cron (see /defaults/crontabs/root); stdout is redirected to /proc/1/fd/1.
# so the report appears in the add-on log. Doubles as a heartbeat: if the numbers stop # Each tool is reported independently so enabling Headroom cannot hide RTK or TokenSave data.
# growing, the corresponding tool has stopped working. # with-contenv supplies the configured persistent HOME.
# with-contenv supplies HOME from the s6 envdir, so this honors a custom `data_location` export NO_COLOR=1
# (see 20-folders.sh) instead of hardcoding /data/data; it also makes bashio::config
# available for the install_headroom gate below.
export NO_COLOR=1 # keep the add-on log free of ANSI color codes
export PATH="/lsiopy/bin:/usr/local/bin:/usr/bin:/bin:${PATH}" export PATH="/lsiopy/bin:/usr/local/bin:/usr/bin:/bin:${PATH}"
have_rtk=false; command -v rtk >/dev/null 2>&1 && have_rtk=true if ! bashio::config.true 'enable_tools_health_report'; then
have_headroom=false; command -v headroom >/dev/null 2>&1 && have_headroom=true exit 0
# headroom is pip-installed unconditionally at build time, so its binary is on PATH even
# when install_headroom is off — gate on the same config svc-headroom checks, and only
# fall back to have_headroom as a secondary availability guard.
headroom_enabled=false
if bashio::config.true 'install_headroom' && $have_headroom; then
headroom_enabled=true
fi fi
# Nothing to report if neither tool is active — stay quiet. rtk_enabled=false
if ! $have_rtk && ! $headroom_enabled; then exit 0; fi headroom_enabled=false
tokensave_enabled=false
echo "===== claude gains report $(date '+%Y-%m-%d %H:%M:%S') =====" if bashio::config.true 'install_rtk' && command -v rtk > /dev/null 2>&1; then
rtk_enabled=true
fi
if bashio::config.true 'install_headroom' && command -v headroom > /dev/null 2>&1; then
headroom_enabled=true
fi
if bashio::config.true 'install_tokensave' && command -v tokensave > /dev/null 2>&1; then
tokensave_enabled=true
fi
if ! $rtk_enabled && ! $headroom_enabled && ! $tokensave_enabled; then
exit 0
fi
echo "===== claude tools report $(date '+%Y-%m-%d %H:%M:%S') ====="
if $headroom_enabled; then if $headroom_enabled; then
echo "--- headroom savings ---" echo "--- headroom savings ---"
headroom savings 2>&1 || echo "[warn] headroom savings failed" headroom savings 2>&1 || echo "[warn] headroom savings failed"
elif $have_rtk; then fi
if $rtk_enabled; then
echo "--- rtk gain ---" echo "--- rtk gain ---"
rtk gain 2>&1 || echo "[warn] rtk gain failed" rtk gain 2>&1 || echo "[warn] rtk gain failed"
fi fi
echo "===== end gains report =====" if $tokensave_enabled; then
echo "--- tokensave gain ---"
tokensave gain --all --range 30d 2>&1 || echo "[warn] tokensave gain failed"
fi
echo "===== end claude tools report ====="

View File

@@ -1,21 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
if ! command -v claude >/dev/null 2>&1; then
echo "Claude Code is not installed or is not on PATH." >&2
exit 127
fi
if ! command -v headroom >/dev/null 2>&1; then
echo "Headroom is unavailable; start Claude Code directly with claude-direct." >&2
exit 127
fi
if ! curl -fsS --max-time 3 "http://127.0.0.1:8787/readyz" >/dev/null; then
echo "The supervised Headroom proxy is not ready on 127.0.0.1:8787. Ensure install_headroom is enabled and check the add-on log." >&2
exit 1
fi
# Reuse the s6-supervised proxy instead of starting a competing proxy. RTK is already managed
# through the persistent Claude Code PreToolUse hook, so Headroom must not reinstall it.
exec headroom wrap claude --port 8787 --no-proxy --no-rtk -- "$@"

View File

@@ -1,24 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
if [ -z "${HOME:-}" ]; then
echo "Claude terminal: HOME is not initialized." >&2
exit 1
fi
export SHELL="/bin/bash"
export PATH="${HOME}/.local/bin:/usr/local/bin:/usr/bin:/bin:${PATH:-}"
workspace="${CLAUDE_TERMINAL_WORKSPACE:-${HOME}/workspace}"
session_name="${CLAUDE_TMUX_SESSION:-claude}"
if [ ! -d "$workspace" ]; then
echo "Claude terminal: workspace does not exist: $workspace" >&2
exit 1
fi
cd -- "$workspace"
# Reattach every browser connection to the same terminal session. Closing the browser detaches
# the client but leaves Claude Code and other commands running inside tmux.
exec tmux new-session -A -s "$session_name" -c "$workspace"

View File

@@ -0,0 +1,174 @@
#!/usr/bin/with-contenv bashio
# Diagnose installation, registration, routing, indexing, permissions, and recorded savings without
# printing MCP environment values (which may contain the Home Assistant access token).
# shellcheck shell=bash
set +e
set -o pipefail
export NO_COLOR=1
export PATH="/lsiopy/bin:/usr/local/bin:/usr/bin:/bin:${PATH}"
section() {
printf '\n=== %s ===\n' "$1"
}
section "Installed binaries"
for tool in claude claude-desktop headroom rtk tokensave git gh rg jq shellcheck yamllint hadolint actionlint; do
resolved="$(command -v "$tool" 2> /dev/null || true)"
if [ -n "$resolved" ]; then
printf '%-16s %s\n' "$tool" "$resolved"
else
printf '%-16s %s\n' "$tool" "MISSING"
fi
done
section "Configured switches"
for option in permission_mode install_headroom headroom_wrap_claude_code expose_headroom_dashboard install_rtk install_tokensave install_caveman enable_tools_health_report; do
printf '%-30s %s\n' "$option" "$(bashio::config "$option")"
done
section "Runtime identity"
printf '%-30s %s\n' "configured PUID:PGID" "$(bashio::config 'PUID'):$(bashio::config 'PGID')"
printf '%-30s %s\n' "effective abc UID:GID" "$(id -u abc):$(id -g abc)"
printf '%-30s %s\n' "current process UID:GID" "$(id -u):$(id -g)"
if [ "$(bashio::config 'permission_mode')" = "bypass" ]; then
if [ "$(id -u abc)" -eq 0 ]; then
echo "bypass runtime: ERROR - Claude Code will reject bypass permissions while abc is root"
else
echo "bypass runtime: OK - Claude Desktop and Cowork run as a non-root UID"
fi
fi
section "Claude Code permission state"
python3 - <<'PY'
import json
from pathlib import Path
path = Path.home() / ".claude/settings.json"
try:
data = json.loads(path.read_text())
except FileNotFoundError:
print("settings: MISSING")
except Exception as exc:
print(f"settings: INVALID: {exc}")
else:
permissions = data.get("permissions", {})
if isinstance(permissions, dict):
print(f"permissions.defaultMode: {permissions.get('defaultMode', '<upstream default>')}")
else:
print("permissions: INVALID")
print(f"managed-state marker: {(Path.home() / '.claude/.addon-permission-mode.json').exists()}")
PY
section "MCP registrations (environment values redacted)"
python3 - <<'PY'
import json
from pathlib import Path
paths = [
Path.home() / ".claude.json",
Path.home() / ".config/Claude/claude_desktop_config.json",
]
for path in paths:
print(path)
try:
data = json.loads(path.read_text())
except FileNotFoundError:
print(" MISSING")
continue
except Exception as exc:
print(f" INVALID: {exc}")
continue
servers = data.get("mcpServers", {})
if not isinstance(servers, dict) or not servers:
print(" no MCP servers")
continue
for name, spec in sorted(servers.items()):
if not isinstance(spec, dict):
print(f" {name}: invalid entry")
continue
command = spec.get("command", "?")
args = spec.get("args", [])
server_type = spec.get("type", "")
suffix = f" type={server_type}" if server_type else ""
print(f" {name}: {command} {args}{suffix}")
if spec.get("env"):
print(" env: <redacted>")
PY
section "Claude Code hooks"
python3 - <<'PY'
import json
from pathlib import Path
path = Path.home() / ".claude/settings.json"
try:
data = json.loads(path.read_text())
except FileNotFoundError:
print("MISSING")
raise SystemExit(0)
except Exception as exc:
print(f"INVALID: {exc}")
raise SystemExit(0)
hooks = data.get("hooks", {})
if not isinstance(hooks, dict) or not hooks:
print("no hooks")
raise SystemExit(0)
for event, entries in hooks.items():
print(event)
if not isinstance(entries, list):
print(" invalid entries")
continue
for entry in entries:
matcher = entry.get("matcher", "*") if isinstance(entry, dict) else "?"
commands = entry.get("hooks", []) if isinstance(entry, dict) else []
rendered = []
for command in commands if isinstance(commands, list) else []:
if isinstance(command, dict):
rendered.append(" ".join([str(command.get("command", "?")), *map(str, command.get("args", []))]))
print(f" matcher={matcher}: {', '.join(rendered) or 'no command'}")
PY
section "Headroom"
if bashio::config.true 'install_headroom'; then
curl -fsS --max-time 2 http://127.0.0.1:8787/health && echo || echo "proxy health: FAILED"
headroom mcp status || true
headroom savings || true
else
echo "disabled"
fi
section "RTK"
if bashio::config.true 'install_rtk'; then
rtk gain || true
else
echo "disabled"
fi
section "TokenSave"
if bashio::config.true 'install_tokensave'; then
tokensave doctor --agent claude || true
tokensave gain --all --range 30d || true
while IFS= read -r configured_path; do
[ -n "$configured_path" ] || continue
repo_root="$(s6-setuidgid abc env HOME="$HOME" git -c safe.directory='*' -C "$configured_path" rev-parse --show-toplevel 2> /dev/null || true)"
if [ -z "$repo_root" ]; then
echo "${configured_path}: not a Git repository"
elif [ -f "$repo_root/.tokensave/tokensave.db" ]; then
s6-setuidgid abc env HOME="$HOME" tokensave status "$repo_root" --short || true
else
echo "${repo_root}: NOT INITIALIZED"
fi
done < <(bashio::config.array 'tokensave_project_paths')
else
echo "disabled"
fi
section "Claude routing"
printf 'PATH claude: %s\n' "$(command -v claude 2> /dev/null || true)"
printf 'real claude: %s\n' "$([ -x /usr/bin/claude ] && echo /usr/bin/claude || echo MISSING)"
if bashio::config.true 'headroom_wrap_claude_code'; then
echo "PATH-based Claude Code launches are configured for Headroom wrapping."
else
echo "Claude Code Headroom wrapping is disabled; Headroom remains available through MCP."
fi

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -3,5 +3,7 @@
"upstream_repo": "linuxserver/docker-baseimage-selkies", "upstream_repo": "linuxserver/docker-baseimage-selkies",
"github_fulltag": true, "github_fulltag": true,
"slug": "claude_desktop", "slug": "claude_desktop",
"paused": false "paused": false,
"upstream_version": "ubunturesolute-version-6dc44b0e",
"last_update": "2026-07-13"
} }

View File

@@ -1,4 +1,7 @@
## 2.9.16 (2026-07-11)
- Update to latest version from Cleanuparr/Cleanuparr (changelog : https://github.com/Cleanuparr/Cleanuparr/releases)
## 2.9.14 (2026-06-20) ## 2.9.14 (2026-06-20)
- Update to latest version from Cleanuparr/Cleanuparr (changelog : https://github.com/Cleanuparr/Cleanuparr/releases) - Update to latest version from Cleanuparr/Cleanuparr (changelog : https://github.com/Cleanuparr/Cleanuparr/releases)

View File

@@ -11,7 +11,7 @@
#=== Home Assistant Addon ===# #=== Home Assistant Addon ===#
# ARGs used in FROM must be declared before any FROM instruction # ARGs used in FROM must be declared before any FROM instruction
ARG BUILD_UPSTREAM="2.9.14" ARG BUILD_UPSTREAM="2.9.16"
################# #################
# 1 Build Image # # 1 Build Image #

View File

@@ -91,5 +91,5 @@ schema:
TZ: str? TZ: str?
slug: cleanuparr slug: cleanuparr
url: https://github.com/alexbelgium/hassio-addons/tree/master/cleanuparr url: https://github.com/alexbelgium/hassio-addons/tree/master/cleanuparr
version: "2.9.14" version: "2.9.16"
webui: "[PROTO:ssl]://[HOST]:[PORT:11011]" webui: "[PROTO:ssl]://[HOST]:[PORT:11011]"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,8 +1,8 @@
{ {
"last_update": "2026-06-20", "last_update": "2026-07-11",
"repository": "alexbelgium/hassio-addons", "repository": "alexbelgium/hassio-addons",
"slug": "cleanuparr", "slug": "cleanuparr",
"source": "github", "source": "github",
"upstream_repo": "Cleanuparr/Cleanuparr", "upstream_repo": "Cleanuparr/Cleanuparr",
"upstream_version": "2.9.14" "upstream_version": "2.9.16"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,4 +1,7 @@
## 2.1.2 (2026-07-11)
- Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases)
## 2.1.0 (2026-07-04) ## 2.1.0 (2026-07-04)
- Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases)

View File

@@ -101,4 +101,4 @@ schema:
slug: codex slug: codex
udev: true udev: true
url: https://github.com/alexbelgium/hassio-addons url: https://github.com/alexbelgium/hassio-addons
version: "2.1.0" version: "2.1.2"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,9 +1,9 @@
{ {
"github_beta": "true", "github_beta": "true",
"last_update": "2026-07-04", "last_update": "2026-07-11",
"repository": "alexbelgium/hassio-addons", "repository": "alexbelgium/hassio-addons",
"slug": "codex", "slug": "codex",
"source": "github", "source": "github",
"upstream_repo": "ajslater/codex", "upstream_repo": "ajslater/codex",
"upstream_version": "2.1.0" "upstream_version": "2.1.2"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,3 +1,9 @@
## 8.19.18-3 (14-07-2026)
- Force a fresh image pull for users left on a stale cached image (some upgrades kept running the old Elasticsearch 7.17.9 image, failing with `mv: cannot move '/data/config' ... Permission denied` and `AccessDeniedException[/usr/share/elasticsearch/data/nodes/0]`). Fully stop and update the add-on so Home Assistant pulls this build.
- Replaced the cryptic `Permission denied` failure with a clear message when the add-on is not running as root (the state that caused the failure above).
## 8.19.18-2 (14-07-2026)
- Minor bugs fixed
## 8.19.18 (2026-07-14) ## 8.19.18 (2026-07-14)
- Upgrade to Elasticsearch 8.19.18 (#2849). Note: despite the previous add-on version reading `8.14.3`, the shipped image was still Elasticsearch 7.17.9 — the Dockerfile upstream version was never bumped. This release actually delivers 8.x, making the add-on compatible with the `homeassistant-elasticsearch` integration (requires 8.14+). - Upgrade to Elasticsearch 8.19.18 (#2849). Note: despite the previous add-on version reading `8.14.3`, the shipped image was still Elasticsearch 7.17.9 — the Dockerfile upstream version was never bumped. This release actually delivers 8.x, making the add-on compatible with the `homeassistant-elasticsearch` integration (requires 8.14+).
@@ -8,9 +14,10 @@
- Removed the `ingest-attachment` plugin install: it is a bundled module since Elasticsearch 8.0. - Removed the `ingest-attachment` plugin install: it is a bundled module since Elasticsearch 8.0.
- Startup persistence logic rewritten as a proper init script (`/usr/local/bin/addon-init.sh`) instead of line-number-based entrypoint patching. - Startup persistence logic rewritten as a proper init script (`/usr/local/bin/addon-init.sh`) instead of line-number-based entrypoint patching.
- Added `updater.json` so upstream 8.19.x releases are tracked automatically (pinned to the 8.19 line: 9.x cannot read indices created in 7.x). - Added `updater.json` so upstream 8.19.x releases are tracked automatically (pinned to the 8.19 line: 9.x cannot read indices created in 7.x).
- The upstream 8.x image ends the build as a non-root user with a read-only entrypoint; the Dockerfile now switches to root for the build steps that patch/install into it. The image stays root at runtime too (unchanged from 7.17.9): the upstream entrypoint no longer drops privileges itself, and `addon-init.sh` needs to chown/move pre-existing `/data` content that may be owned by root from earlier installs. - The upstream 8.x image ends the build as a non-root user with a read-only entrypoint; the Dockerfile now switches to root for the build steps that patch/install into it. The container also starts as root (unchanged from 7.17.9) so `addon-init.sh` can chown/move pre-existing `/data` content that may be owned by root from earlier installs; unlike 7.17.9's own entrypoint, the upstream 8.x entrypoint no longer drops privileges before starting Elasticsearch (which refuses to run as root), so `addon-init.sh` now does that itself via `chroot --userspec=1000:0` once its root-only work is done.
- `env_vars` names starting with a digit are now rejected before export instead of crashing the entrypoint. - `env_vars` names starting with a digit are now rejected before export instead of crashing the entrypoint.
- Fixed a startup failure (`mv: cannot move '/data/config' ... Permission denied`) on upgrade from an existing 7.17.9 install, caused by an earlier fix in this same release that switched the runtime user to non-root before this fix was in place. - Fixed a startup failure (`mv: cannot move '/data/config' ... Permission denied`) on upgrade from an existing 7.17.9 install, caused by an earlier fix in this same release that switched the runtime user to non-root before this fix was in place.
- Fixed a second regression from that same fix: without a privilege drop before starting Elasticsearch, both fresh installs and upgrades would fail Elasticsearch's own root-check ("can not run elasticsearch as root").
## 8.14.3-3 (2026-06-19) ## 8.14.3-3 (2026-06-19)
- Fix startup failing with `chroot: cannot change root directory` by allowing `capability sys_chroot` in the AppArmor profile (#2709) - Fix startup failing with `chroot: cannot change root directory` by allowing `capability sys_chroot` in the AppArmor profile (#2709)

View File

@@ -141,9 +141,10 @@ HEALTHCHECK \
--timeout=25s \ --timeout=25s \
CMD curl -A "HealthCheck: Docker/1.0" -s -f "http://127.0.0.1:${HEALTH_PORT}${HEALTH_URL}" &>/dev/null || exit 1 CMD curl -A "HealthCheck: Docker/1.0" -s -f "http://127.0.0.1:${HEALTH_PORT}${HEALTH_URL}" &>/dev/null || exit 1
# Stay root at runtime: addon-init.sh must chown/mv pre-existing /data # Start as root: addon-init.sh needs it to chown/move pre-existing /data
# content that may be owned by root from earlier installs, and the upstream # content that may be owned by root from earlier installs. It drops to
# entrypoint no longer drops privileges itself, so a non-root container # uid 1000 itself (via chroot --userspec) before Elasticsearch actually
# can't touch that data at all. This matches the addon's own AppArmor # starts, since Elasticsearch refuses to run as root and the upstream 8.x
# profile (chown, setuid, setgid, sys_chroot, mount capabilities), which # entrypoint no longer does that drop on its own (7.x's did). This matches
# assumes a root process. # the addon's own AppArmor profile (chown, setuid, setgid, sys_chroot,
# mount capabilities).

View File

@@ -90,4 +90,4 @@ slug: elasticsearch
startup: services startup: services
udev: true udev: true
url: https://github.com/alexbelgium/hassio-addons/tree/master/elasticsearch url: https://github.com/alexbelgium/hassio-addons/tree/master/elasticsearch
version: 8.19.18 version: 8.19.18-3

47
elasticsearch/rootfs/usr/local/bin/addon-init.sh Normal file → Executable file
View File

@@ -1,15 +1,25 @@
#!/bin/bash #!/bin/bash
# shellcheck shell=bash # shellcheck shell=bash
# Sourced by /usr/local/bin/docker-entrypoint.sh (right after "set -e"), # Sourced by /usr/local/bin/docker-entrypoint.sh (right after "set -e"),
# before Elasticsearch starts. Runs as root (the image stays root at # before Elasticsearch starts. The container starts as root (see
# runtime - see Dockerfile); the official entrypoint does not drop # Dockerfile) so this script can chown/move pre-existing /data content
# privileges itself, and Elasticsearch ends up running as root too. # that may be owned by root from earlier installs. Elasticsearch itself
# refuses to run as root, and unlike 7.x the upstream 8.x entrypoint no
# longer drops privileges on its own, so this script does it at the end
# (section 6) by re-execing the entrypoint as uid 1000. On that re-exec'd
# pass this script just returns immediately (see the guard right below).
# #
# Responsibilities: # Responsibilities:
# 1. Export user env_vars from /data/options.json # 1. Export user env_vars from /data/options.json
# 2. Default xpack.security.enabled=false (7.x behavior) unless user overrides # 2. Default xpack.security.enabled=false (7.x behavior) unless user overrides
# 3. Relocate data & config to /data for persistence (idempotent) # 3. Relocate data & config to /data for persistence (idempotent)
# 4. Guard major-version data migrations (7.x -> 8.x is automatic) # 4. Guard major-version data migrations (7.x -> 8.x is automatic)
# 5. Record the running version once Elasticsearch is confirmed healthy
# 6. Drop root privileges before Elasticsearch actually starts
if [ -n "${_ADDON_INIT_REEXEC:-}" ]; then
return 0
fi
echo "-----------------------------------------------------------" echo "-----------------------------------------------------------"
echo " Add-on: Elasticsearch server" echo " Add-on: Elasticsearch server"
@@ -21,6 +31,17 @@ PERSISTENT_HOME="/data"
VERSION_MARKER="$PERSISTENT_HOME/.addon-upstream-version" VERSION_MARKER="$PERSISTENT_HOME/.addon-upstream-version"
OPTIONS_JSON="/data/options.json" OPTIONS_JSON="/data/options.json"
# This first pass must be root so it can relocate and take ownership of
# pre-existing /data content written by an earlier (root) install. If it
# is not root (e.g. an old cached image that pinned USER 1000:0, or the
# container being forced to another user), the moves/chowns below fail
# with a cryptic "Permission denied"; fail loudly with the real reason.
if [ "$(id -u)" -ne 0 ]; then
echo "FATAL: the Elasticsearch add-on must start as root (currently uid $(id -u))."
echo "If you upgraded from an older version, the running image is likely stale - fully stop and update/reinstall the add-on so Home Assistant pulls the current image."
exit 1
fi
############################ ############################
# 1 Export user env_vars # # 1 Export user env_vars #
############################ ############################
@@ -84,7 +105,11 @@ if [ -n "$data_version" ] && [[ $current_major =~ ^[0-9]+$ ]]; then
if [ -d "$PERSISTENT_HOME/config" ] && [ ! -L "$PERSISTENT_HOME/config" ]; then if [ -d "$PERSISTENT_HOME/config" ] && [ ! -L "$PERSISTENT_HOME/config" ]; then
config_backup="$PERSISTENT_HOME/config.bak-$data_version" config_backup="$PERSISTENT_HOME/config.bak-$data_version"
if [ ! -e "$config_backup" ]; then if [ ! -e "$config_backup" ]; then
mv "$PERSISTENT_HOME/config" "$config_backup" if ! mv "$PERSISTENT_HOME/config" "$config_backup"; then
echo "FATAL: could not archive the old config to $config_backup."
echo "This add-on must run as root to migrate a previous install. Restore a Home Assistant backup and ensure the add-on is not forced to a non-root user."
exit 1
fi
echo "NOTICE: previous config archived to $config_backup. Re-apply any custom settings to the new config." echo "NOTICE: previous config archived to $config_backup. Re-apply any custom settings to the new config."
fi fi
fi fi
@@ -141,3 +166,17 @@ if [ "$data_version" != "$current_version" ]; then
done done
) & ) &
fi fi
############################
# 6 Drop privileges #
############################
# Elasticsearch refuses to start as root ("can not run elasticsearch as
# root"). 7.x's own entrypoint dropped to uid 1000 via chroot before
# launching Elasticsearch; 8.x no longer does that, so do it here instead,
# then let the entrypoint continue as uid 1000 (matches the sys_chroot /
# setuid / setgid capabilities already granted in the AppArmor profile).
if [ "$(id -u)" -eq 0 ]; then
export _ADDON_INIT_REEXEC=1
exec chroot --userspec=1000:0 / /usr/local/bin/docker-entrypoint.sh "$@"
fi

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,4 +1,10 @@
## 4.10.0.19 (2026-07-13)
- Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases)
## 4.10.0.18 (2026-07-11)
- Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases)
## 4.10.0.17 (2026-07-04) ## 4.10.0.17 (2026-07-04)
- Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases)

View File

@@ -16,7 +16,7 @@
ARG BUILD_FROM ARG BUILD_FROM
ARG BUILD_VERSION ARG BUILD_VERSION
ARG BUILD_UPSTREAM="4.10.0.17" ARG BUILD_UPSTREAM="4.10.0.19"
FROM ${BUILD_FROM} FROM ${BUILD_FROM}
################## ##################

View File

@@ -122,5 +122,5 @@ schema:
slug: emby_nas slug: emby_nas
udev: true udev: true
url: https://github.com/alexbelgium/hassio-addons/tree/master/emby url: https://github.com/alexbelgium/hassio-addons/tree/master/emby
version: "4.10.0.17" version: "4.10.0.19"
video: true video: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,9 +1,9 @@
{ {
"github_beta": "true", "github_beta": "true",
"last_update": "2026-07-04", "last_update": "2026-07-13",
"repository": "alexbelgium/hassio-addons", "repository": "alexbelgium/hassio-addons",
"slug": "emby", "slug": "emby",
"source": "github", "source": "github",
"upstream_repo": "linuxserver/docker-emby", "upstream_repo": "linuxserver/docker-emby",
"upstream_version": "4.10.0.17" "upstream_version": "4.10.0.19"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Some files were not shown because too many files have changed in this diff Show More