Compare commits

...

13 Commits

Author SHA1 Message Date
Alexandre
0073339f8c Merge pull request #2829 from alexbelgium/claude_desktop/hourly-gains-and-headroom-backend
Claude Desktop: hourly rtk + headroom gains report + headroom proxy backend
2026-07-07 22:10:45 +02:00
alexbelgium
e1a0f01fb9 claude_desktop: fix gains report headroom gating + data_location
- Gate the headroom section on install_headroom (bashio::config.true), same
  as svc-headroom, instead of only checking whether the binary is on PATH
  (it's pip-installed unconditionally at build time, so it's always
  present). have_headroom is now just a secondary availability guard.
  Fixes noisy/stale headroom output when the option is disabled.
- Switch the shebang to with-contenv bashio so HOME comes from the s6
  envdir instead of a hardcoded /data/data. 20-folders.sh only rewrites
  /data/data references under /defaults, /etc/cont-init.d,
  /etc/services.d and /etc/s6-overlay/s6-rc.d — not /usr/local/bin — so
  a custom data_location previously left this script reading/writing the
  wrong home directory.

Verified live: real cron firing confirms with-contenv correctly resolves
HOME and bashio::config from the s6 envdir when invoked by cron; isolated
gating-logic test covers all four enabled/binary-present combinations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 22:09:11 +02:00
alexbelgium
66b91278b9 claude_desktop: hourly rtk+headroom gains report + headroom proxy backend
- Add claude-gains-report.sh + /defaults/crontabs/root: an hourly rtk gain +
  headroom savings snapshot to the add-on log (heartbeat + accumulated gains).
- Add svc-headroom longrun: run the headroom proxy as a local MCP backend
  (127.0.0.1:8787, no client routing) so headroom_compress/headroom_retrieve
  actually store/retrieve content and record savings. Backend only, so the
  Claude Desktop app's traffic is untouched (headroom #869).
- Nudge headroom tool usage via a managed, idempotent CLAUDE.md block.
- Bump version 1.6 -> 1.7 and update CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 21:49:58 +02:00
github-actions
a70bf0f0f4 GitHub bot : README updated 2026-07-07 17:38:51 +00:00
Alexandre
1a128d62f2 Suppress output during caveman plugin installation
Redirect output of caveman plugin installation to /dev/null.
2026-07-07 18:11:29 +02:00
Alexandre
0fc40f339c Merge pull request #2827 from alexbelgium/claude/desktop-headroom-wrap-fix-r4qaqe
claude_desktop: don't wrap desktop launch with invalid headroom command
2026-07-07 16:52:41 +02:00
Claude
86395a85a0 claude_desktop: surface headroom MCP removal failures instead of swallowing them
The removal block's json.loads() was wrapped in a bare try/except that set
data = None on any parse error, then silently no-op'd (isinstance(data, dict)
is False) with exit 0 -- so a malformed claude_desktop_config.json meant the
headroom entry was never removed and bashio::log.warning never fired.

Drop the try/except so parse errors propagate naturally and the script exits
non-zero, matching the sibling rtk removal block's existing convention and
triggering the bashio::log.warning fallback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgMcG1QjsSHcDQBxgPpRUw
2026-07-07 14:35:52 +00:00
Claude
a9cf84077b claude_desktop: register headroom MCP server instead of proxy launch
headroom's proxy/wrap routing relies on ANTHROPIC_BASE_URL, which Claude
Desktop force-overrides (headroom #869), so it cannot transparently compress
the desktop app. Register headroom's MCP server (headroom mcp serve) in Claude
Desktop's claude_desktop_config.json instead -- the supported integration --
exposing the headroom_compress/headroom_retrieve/headroom_stats tools inside
the app. The plain desktop launch is left untouched.

The JSON merge is idempotent, preserves any other MCP servers and top-level
keys, backs up malformed config, and removes the entry again when
install_headroom is disabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgMcG1QjsSHcDQBxgPpRUw
2026-07-07 14:24:38 +00:00
Claude
f65d5af969 claude_desktop: launch through headroom proxy instead of invalid wrap
headroom "wrap" only accepts coding-agent CLIs (claude, codex, cursor, ...)
with agent args after "--", so it cannot wrap the claude-desktop Electron app.
Route the launch through headroom's standalone compression proxy instead: the
command file now starts "headroom proxy" and points Claude Desktop at it via
ANTHROPIC_BASE_URL, while the autostart still falls back to a plain launch if
that fails.

Claude Desktop currently force-overrides ANTHROPIC_BASE_URL (headroom #869), so
transparent compression only engages once upstream adds Desktop support; until
then the app launches normally. Update the README/CHANGELOG accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgMcG1QjsSHcDQBxgPpRUw
2026-07-07 14:05:53 +00:00
Claude
74e25ba41b claude_desktop: don't wrap desktop launch with invalid headroom command
install_headroom defaults to true and headroom is baked into the image, so
82-claude_tools.sh rewrote the desktop launch to "headroom wrap claude-desktop
--no-sandbox ...". headroom "wrap" only accepts coding-agent CLIs (claude,
codex, cursor, ...) and expects agent arguments after a "--" separator, so
"claude-desktop" plus the Electron flags is an invalid wrap target/options.
The autostart ran only that command with no fallback, leaving the desktop app
unlaunched for default users.

- Keep the plain claude-desktop launch; just expose headroom with a usage hint
  (matches the documented "make headroom available and log a usage hint").
- Harden autostart to fall back to the default launch if a custom/wrapped
  command fails to start.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgMcG1QjsSHcDQBxgPpRUw
2026-07-07 13:18:11 +00:00
Alexandre
4d768ae1fa Merge pull request #2826 from alexbelgium/codex/fix-default-settings-for-claude-addon
Fix Claude Desktop optional tool startup
2026-07-07 15:03:18 +02:00
Alexandre
cc5d04c0f5 Fix Claude Desktop optional tool startup 2026-07-07 15:02:51 +02:00
Alexandre
f4343a6af4 Update Dockerfile 2026-07-07 14:42:25 +02:00
14 changed files with 216 additions and 14 deletions

View File

@@ -56,7 +56,7 @@ If you want to do add the repository manually, please follow the procedure highl
### Number of addons
- In the repository : 134
- In the repository : 135
- Installed : 508490
### Top 3
@@ -247,6 +247,14 @@ If you want to do add the repository manually, please follow the procedure highl
![amd64][amd64-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
&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)
![aarch64][aarch64-badge]
![amd64][amd64-badge]
![ingress][ingress-badge]
&#10003; ![image](https://api.iconify.design/mdi/movie-search.svg) [Cleanuparr](cleanuparr/) : Automatically removes stuck and unwanted downloads from your *arr and download clients
&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%2Fcleanuparr%2Fconfig.yaml)

View File

@@ -1,3 +1,14 @@
## 1.7 (07-07-2026)
- Add an hourly rtk + headroom token-savings report to the add-on log (`claude-gains-report.sh`, seeded via `/defaults/crontabs/root` and run by the base image's cron). Lets you confirm at a glance that both tools keep running and see accumulated gains — if the numbers stop growing, the tool has stopped working.
- Run the Headroom optimization proxy as a supervised local backend (`svc-headroom` on 127.0.0.1:8787) so the `headroom_compress`/`headroom_retrieve` MCP tools can actually store/retrieve compressed content and record savings. It is a **backend only** — no client's `ANTHROPIC_BASE_URL` is routed through it, so the Claude Desktop app (which force-overrides it, [headroom #869](https://github.com/headroomlabs-ai/headroom/issues/869)) is unaffected. Previously the MCP server was registered but had no backend, so it recorded no savings.
- Nudge Claude to use the headroom compression tools via a managed, idempotent block appended to the user's `CLAUDE.md` (removed automatically when `install_headroom` is disabled).
## 1.6 (07-07-2026)
- Fix default desktop launch failing when `install_headroom` is enabled (the default): the code rewrote the launch to `headroom wrap claude-desktop …`, but `headroom wrap` only supports coding-agent CLIs (`claude`, `codex`, ...) with arguments after `--`, so it produced an invalid command that left the app unlaunched. Leave the plain launch intact and instead register the `headroom` MCP server (`headroom mcp serve`) in Claude Desktop's config, exposing the `headroom_compress`/`headroom_retrieve`/`headroom_stats` tools inside the app. This is the supported headroom integration for Desktop, which overrides `ANTHROPIC_BASE_URL` so transparent proxy compression is not possible ([headroom #869](https://github.com/headroomlabs-ai/headroom/issues/869)). Disabling the option removes the entry again.
- Make the autostart resilient: if the launch command fails to start, fall back to the plain Claude Desktop launch so the app always comes up.
## 1.5 (07-07-2026)
- Change the default Claude Desktop data location to `/data/data`.

View File

@@ -59,7 +59,6 @@ RUN curl -fsSLo /usr/share/keyrings/claude-desktop-archive-keyring.asc https://d
apt-get install -y --no-install-recommends \
claude-desktop \
python3-pip \
gnome-keyring \
libsecret-1-0 \
dbus-x11 \
git gh && \

View File

@@ -38,7 +38,7 @@ Claude Desktop sign-in requires a claude.ai plan that supports the Desktop app.
| `DRINODE` | | Optional GPU device override for Selkies. |
| `DNS_server` | `8.8.8.8` | DNS server used by the standard DNS module. |
| `auto_update` | `true` | Check Anthropic's apt repository and upgrade `claude-desktop` at add-on startup. |
| `install_headroom` | `true` | Make the baked-in `headroom` command available and log a usage hint. |
| `install_headroom` | `true` | Register the baked-in `headroom` MCP server in Claude Desktop, exposing its `headroom_compress`/`headroom_retrieve`/`headroom_stats` context-compression tools inside the app. (Claude Desktop overrides `ANTHROPIC_BASE_URL`, so transparent proxy compression is not possible — MCP is the supported path; see [headroom #869](https://github.com/headroomlabs-ai/headroom/issues/869).) Disabling removes the entry again. |
| `install_rtk` | `true` | Configure the rtk Claude Code `PreToolUse` hook in the persistent Claude Code settings. |
| `install_caveman` | `true` | Install the caveman Claude Code plugin into the persistent Claude Code home. |
| `install_github_cli` | `true` | Enable first-start checks and setup for the baked-in `git` and `gh` commands. |

View File

@@ -90,5 +90,5 @@ slug: claude_desktop
tmpfs: true
udev: true
url: https://github.com/alexbelgium/hassio-addons
version: "1.5"
version: "1.7"
video: true

View File

@@ -13,4 +13,19 @@ dbus-update-activation-environment --all >/dev/null 2>&1 || true
# --password-store=gnome-libsecret forces Electron onto the libsecret backend instead of
# falling back to plaintext (and warning that the sign-in will not be saved).
claude-desktop --no-sandbox --disable-dev-shm-usage --password-store=gnome-libsecret
CLAUDE_DESKTOP_COMMAND_FILE="/tmp/claude-desktop-command"
DEFAULT_CLAUDE_DESKTOP_COMMAND="claude-desktop --no-sandbox --disable-dev-shm-usage --password-store=gnome-libsecret"
if [ -s "$CLAUDE_DESKTOP_COMMAND_FILE" ]; then
CLAUDE_DESKTOP_COMMAND="$(cat "$CLAUDE_DESKTOP_COMMAND_FILE")"
else
CLAUDE_DESKTOP_COMMAND="$DEFAULT_CLAUDE_DESKTOP_COMMAND"
fi
# Launch the configured command. If a custom/wrapped command fails to start, fall back to
# the plain Claude Desktop launch so the desktop app still comes up for the user.
if ! sh -c "$CLAUDE_DESKTOP_COMMAND"; then
if [ "$CLAUDE_DESKTOP_COMMAND" != "$DEFAULT_CLAUDE_DESKTOP_COMMAND" ]; then
echo "autostart: '$CLAUDE_DESKTOP_COMMAND' failed; falling back to default Claude Desktop launch" >&2
exec sh -c "$DEFAULT_CLAUDE_DESKTOP_COMMAND"
fi
fi

View File

@@ -0,0 +1,4 @@
# Hourly rtk + headroom token-savings report to the add-on log (heartbeat + gains).
# 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.
0 * * * * /usr/local/bin/claude-gains-report.sh > /proc/1/fd/1 2>&1

View File

@@ -4,21 +4,136 @@ set -e
set -o pipefail
mkdir -p "$HOME/.claude"
CLAUDE_DESKTOP_COMMAND_FILE="/tmp/claude-desktop-command"
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"
# headroom's "wrap"/proxy routing works by setting ANTHROPIC_BASE_URL, which the Claude Desktop
# Electron app force-overrides to the production endpoint (headroom #869), so transparent
# compression cannot be applied to the desktop launch. The integration that does work with
# Claude Desktop is headroom's MCP server, which exposes the headroom_compress/headroom_retrieve/
# 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.
CLAUDE_DESKTOP_CONFIG="$HOME/.config/Claude/claude_desktop_config.json"
if bashio::config.true 'install_headroom'; then
if command -v headroom &> /dev/null; then
bashio::log.info "headroom $(headroom --version 2> /dev/null || true) available. Use 'headroom wrap claude' or MCP mode from Claude Code."
bashio::log.info "headroom $(headroom --version 2> /dev/null || true) available; registering the headroom MCP server for Claude Desktop"
HEADROOM_BIN="$(command -v headroom)" CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_CONFIG" python3 - <<'PY' || bashio::log.warning "Unable to register the headroom MCP server automatically"
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
bashio::log.warning "headroom is not available"
fi
elif [ -f "$CLAUDE_DESKTOP_CONFIG" ]; then
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"
import json
import os
from pathlib import Path
path = Path(os.environ["CLAUDE_DESKTOP_CONFIG"])
data = json.loads(path.read_text())
if isinstance(data, dict):
servers = data.get("mcpServers")
if isinstance(servers, dict) and servers.pop("headroom", None) is not None:
if not servers:
data.pop("mcpServers", None)
path.write_text(json.dumps(data, indent=2) + "\n")
PY
fi
# 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,
# idempotent block appended to the user's global CLAUDE.md; removed when headroom is disabled.
CLAUDE_MD="$HOME/.claude/CLAUDE.md"
HEADROOM_GUIDE_BEGIN="<!-- BEGIN headroom (managed by claude_desktop addon) -->"
if bashio::config.true 'install_headroom'; then
mkdir -p "$(dirname "$CLAUDE_MD")"
if ! { [ -f "$CLAUDE_MD" ] && grep -qF "$HEADROOM_GUIDE_BEGIN" "$CLAUDE_MD"; }; then
bashio::log.info "Adding headroom usage guidance to CLAUDE.md"
{
[ -s "$CLAUDE_MD" ] && printf '\n'
cat <<'MD'
<!-- BEGIN headroom (managed by claude_desktop addon) -->
## Headroom context compression
A local Headroom proxy (127.0.0.1:8787) backs the `headroom` MCP tools. To save context tokens:
when you produce or read a **large, structured** blob you will keep referring to — file listings,
search results, JSON/config dumps, big command outputs, roughly >500 tokens — call
`mcp__headroom__headroom_compress` on it and keep the returned compressed text + `hash` instead of
the raw content. Call `mcp__headroom__headroom_retrieve` with that hash when you need the full
original back. Skip compression for error/stack-trace output (Headroom deliberately protects it)
and for small or one-off content. Use `mcp__headroom__headroom_stats` to check savings.
<!-- END headroom (managed by claude_desktop addon) -->
MD
} >> "$CLAUDE_MD"
fi
elif [ -f "$CLAUDE_MD" ] && grep -qF "$HEADROOM_GUIDE_BEGIN" "$CLAUDE_MD"; then
bashio::log.info "Removing headroom usage guidance from CLAUDE.md"
CLAUDE_MD="$CLAUDE_MD" python3 - <<'PY' || bashio::log.warning "Unable to remove headroom guidance automatically"
import os
import re
from pathlib import Path
path = Path(os.environ["CLAUDE_MD"])
text = path.read_text()
pattern = re.compile(
r"\n*<!-- BEGIN headroom \(managed by claude_desktop addon\) -->.*?"
r"<!-- END headroom \(managed by claude_desktop addon\) -->\n?",
re.DOTALL,
)
new = pattern.sub("", text)
if new != text:
path.write_text(new)
PY
fi
if bashio::config.true 'install_rtk'; then
if command -v rtk &> /dev/null; then
if [ -f "$HOME/.claude/settings.json" ] && grep -q 'rtk' "$HOME/.claude/settings.json"; then
if [ -f "$HOME/.claude/settings.json" ] && grep -q 'rtk hook claude' "$HOME/.claude/settings.json"; then
bashio::log.info "rtk Claude Code hook already configured"
else
bashio::log.info "Configuring rtk Claude Code hook"
rtk init -g || bashio::log.warning "rtk hook configuration failed"
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
from pathlib import Path
path = Path.home() / ".claude" / "settings.json"
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 = {}
hooks = data.setdefault("hooks", {})
pre = hooks.setdefault("PreToolUse", [])
rtk_entry = {"matcher": "Bash", "hooks": [{"type": "command", "command": "rtk hook claude"}]}
if not any("rtk hook claude" in json.dumps(entry) for entry in pre if isinstance(entry, dict)):
pre.append(rtk_entry)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data, indent=2) + "\n")
PY
fi
else
bashio::log.warning "rtk is not available"
@@ -49,7 +164,7 @@ if bashio::config.true 'install_caveman'; then
bashio::log.info "caveman Claude Code plugin already configured"
else
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 || 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
else
bashio::log.info "Disabling caveman Claude Code plugin"

View File

@@ -29,15 +29,13 @@ if bashio::config.has_value 'github_token'; then
token="$(bashio::config 'github_token')"
mkdir -p "$HOME/.config/gh"
chmod 700 "$HOME/.config/gh"
export GH_TOKEN="$token"
export GITHUB_TOKEN="$token"
if gh auth status --hostname github.com > /dev/null 2>&1; then
if env -u GH_TOKEN -u GITHUB_TOKEN gh auth status --hostname github.com > /dev/null 2>&1; then
bashio::log.info "GitHub CLI already authenticated for github.com"
else
bashio::log.info "Configuring GitHub CLI authentication for github.com"
printf '%s\n' "$token" | gh auth login --hostname github.com --with-token || bashio::log.warning "GitHub CLI authentication failed"
printf '%s\n' "$token" | env -u GH_TOKEN -u GITHUB_TOKEN gh auth login --hostname github.com --with-token || bashio::log.warning "GitHub CLI authentication failed"
fi
gh auth setup-git --hostname github.com || bashio::log.warning "GitHub CLI git credential setup failed"
env -u GH_TOKEN -u GITHUB_TOKEN gh auth setup-git --hostname github.com || bashio::log.warning "GitHub CLI git credential setup failed"
else
bashio::log.info "GitHub CLI available. Set github_token to authenticate gh and git operations."
fi

View File

@@ -0,0 +1,16 @@
#!/usr/bin/with-contenv bashio
# Headroom optimization proxy — runs ONLY as a local backend for the headroom MCP tools
# (headroom_compress / headroom_retrieve, registered in 82-claude_tools.sh). It is NOT a
# traffic router: no client's ANTHROPIC_BASE_URL is pointed at it, so the Claude Desktop
# Electron app (which force-overrides ANTHROPIC_BASE_URL — headroom #869) and every other
# client are unaffected. Without this backend the MCP tools cannot store/retrieve compressed
# content and no savings are ever recorded.
declare port=8787
if bashio::config.true 'install_headroom' && command -v headroom >/dev/null 2>&1; then
bashio::log.info "svc-headroom: starting headroom proxy on 127.0.0.1:${port} (MCP backend only; no client routing)"
exec headroom proxy --host 127.0.0.1 --port "${port}"
fi
bashio::log.info "svc-headroom: install_headroom disabled or headroom not found; idling"
exec sleep infinity

View File

@@ -0,0 +1 @@
longrun

View File

@@ -0,0 +1,35 @@
#!/usr/bin/with-contenv bashio
# Hourly rtk + headroom token-savings snapshot for the add-on log.
# Invoked by cron (see /defaults/crontabs/root); its 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
# growing, the corresponding tool has stopped working.
# with-contenv supplies HOME from the s6 envdir, so this honors a custom `data_location`
# (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}"
have_rtk=false; command -v rtk >/dev/null 2>&1 && have_rtk=true
have_headroom=false; command -v headroom >/dev/null 2>&1 && have_headroom=true
# 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
# Nothing to report if neither tool is active — stay quiet.
if ! $have_rtk && ! $headroom_enabled; then exit 0; fi
echo "===== claude gains report $(date '+%Y-%m-%d %H:%M:%S') ====="
if $have_rtk; then
echo "--- rtk gain ---"
rtk gain 2>&1 || echo "[warn] rtk gain failed"
fi
if $headroom_enabled; then
echo "--- headroom savings ---"
headroom savings 2>&1 || echo "[warn] headroom savings failed"
fi
echo "===== end gains report ====="