Compare commits
6 Commits
cc8ebcfe7e
...
docs/skill
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9b92f4e70 | ||
|
|
9e5405fadc | ||
|
|
f70fbe9705 | ||
|
|
9204b31af8 | ||
|
|
c697ed2c06 | ||
|
|
1d70eca70a |
@@ -29,8 +29,8 @@ Triage first, then one of two paths:
|
||||
resolve bot comments.
|
||||
- **Full loop** — performance/RAM/CPU work, diagnosis, anything changing a shipped default,
|
||||
ladder levels 4-6, or an explicit Codex-check request: scope → measure → plan → Codex reviews
|
||||
the plan → implement → simplify → Codex reviews the code → PR → resolve comments → verify in
|
||||
production → report.
|
||||
the plan → implement → simplify → Codex reviews the code → **simplify again** → PR → resolve
|
||||
comments → verify in production → report.
|
||||
|
||||
Escalate mid-flight if a light task grows — touches a default, needs a new script or service, or
|
||||
reveals a deeper problem.
|
||||
@@ -42,7 +42,10 @@ where every add-on solves a problem the same way is worth more than a locally ni
|
||||
design. Prefer reusing or extending over adding a parallel implementation, and when you must add
|
||||
something new, spell it the way the rest of the repo spells it (naming, option names, script
|
||||
numbering, file layout). Complexity is bought only by a **measurement** showing a concrete,
|
||||
user-visible cost on a real host — never by reasoning about hypothetical performance.
|
||||
user-visible cost on a real host — never by reasoning about hypothetical performance, and never by
|
||||
reasoning about a hypothetical *host* either. A defensive branch is complexity like any other: name
|
||||
the input that reaches it and the image or host where that happens, or delete it and let the case
|
||||
fail visibly instead.
|
||||
|
||||
**Repo layout.** `alexbelgium/hassio-addons`; each add-on is a top-level directory. This skill is
|
||||
checked in at `.claude/skills/hassio-addon-workflow/` (canonical copy). Set the skill root once,
|
||||
@@ -113,6 +116,9 @@ Attack your own plan before implementing:
|
||||
- What is the **blast radius** if the assumption underneath it is wrong?
|
||||
- What am I **inferring** that I could instead **detect at runtime** or **record explicitly**?
|
||||
Highest-yield question here — see `references/evidence.md`'s failure-mode section.
|
||||
- For every branch that exists **only to survive something going wrong**: what input reaches it,
|
||||
on which image? Go and look. A fallback for a configuration you cannot find an instance of is
|
||||
not robustness, it is a second code path nobody will ever exercise or notice rotting.
|
||||
|
||||
Full loop only, before writing code: get Codex's independent read on the plan. Spawn a subagent
|
||||
whose prompt includes the path `references/codex-review.md` and tells it to follow that file's
|
||||
@@ -140,11 +146,18 @@ justify the divergence in the PR body — but never at the cost of an isolation
|
||||
numbered script, not an edit. Case studies of what happens when this check is skipped:
|
||||
`references/simplify.md`.
|
||||
|
||||
## 6. Codex attacks the code (full loop only)
|
||||
## 6. Codex attacks the code, then simplify what the review added (full loop only)
|
||||
|
||||
Same delegated invocation, pointed at `git diff origin/master...HEAD` plus your reasoning per
|
||||
hunk. Details in `references/codex-review.md`.
|
||||
|
||||
Then run step 5's checks again over the hunks the review changed. Adversarial review only ever
|
||||
argues *for* another branch — that is its job — so accepting objections ratchets the diff upward,
|
||||
and nothing else in the loop walks it back down. For each accepted objection: is the case it
|
||||
defends one you have now demonstrated, or one you have merely been told about? Taking a
|
||||
correctness objection often deletes the code that made it necessary, and a fix that collapses back
|
||||
to fewer lines than you started the review with is the normal outcome, not a suspicious one.
|
||||
|
||||
## 7. Open the PR
|
||||
|
||||
CI gates on a PR: **`CHANGELOG.md` updated** (hard fail), the **HA add-on linter**
|
||||
|
||||
@@ -39,3 +39,10 @@ codex exec --model gpt-5.6-sol --sandbox read-only --skip-git-repo-check \
|
||||
**Codex agrees with confident premises.** It has confirmed a wrong conclusion stated too
|
||||
confidently, and separately caught a genuine methodology error in the same review. Treat its
|
||||
confirmations with the same scepticism as its objections — especially about the build.
|
||||
|
||||
**Its objections ratchet complexity upward.** An adversarial reviewer is asked to find what could
|
||||
go wrong, so its output is a list of arguments for more code; it is never asked whether the branch
|
||||
it wants is reachable. Separate "this is wrong" from "this is undefended" before you write
|
||||
anything: the first is a bug and you fix it, the second is a claim about some host, and it needs
|
||||
the same demonstration you would demand of a measurement. That is what step 6's second simplify
|
||||
pass is for.
|
||||
|
||||
@@ -13,6 +13,15 @@ Being able to build the complicated thing is not a reason to.
|
||||
- A resolution cap shipped as a **new init script writing an s6 envdir** — the wrong mechanism
|
||||
entirely (ladder level 4). Renaming the option to the env var the service already reads
|
||||
(level 1) would have worked, and the new script did not.
|
||||
- A `.templates/ha_entrypoint.sh` fix went to review at 25 lines of code and merged at 10. Two
|
||||
sources of the excess, and neither was caught by the loop: a **pure-bash fallback** written at
|
||||
implement time for images shipping `with-contenv` but not `s6-dumpenv` — reasoned from the two
|
||||
binaries living in different s6 packages, never demonstrated on any real image, and the case it
|
||||
defended would have degraded to the pre-fix behaviour anyway — and a **helper function plus a
|
||||
second reset** that existed only to serve that fallback. Deleting the fallback deleted all of
|
||||
it. The rest of the review's objections were correct and cost two tokens on an existing line.
|
||||
It took the maintainer asking "is this the simplest way possible?" to run the pass that step 6
|
||||
now requires.
|
||||
|
||||
## Checks worth running against your own diff
|
||||
|
||||
@@ -25,6 +34,11 @@ Being able to build the complicated thing is not a reason to.
|
||||
A removal that depends on a host default still needs the same verification as an addition.
|
||||
- **Is the fix bigger than the thing it fixes?** That is a smell, not a rule — but it usually
|
||||
means the problem was framed one level too deep.
|
||||
- **For each defensive branch: what input reaches it, on which image or host?** Go and check,
|
||||
the way you would check a measurement. If you cannot produce the case, delete the branch — the
|
||||
situation then fails the way it already fails today, visibly, instead of through a second path
|
||||
that is never exercised and silently rots as the base images move. Write down in the PR body
|
||||
what you cut and why, so the next person does not re-add it from the same reasoning.
|
||||
- **How does this fail in three years**, when the base image, Electron, or upstream has moved?
|
||||
Code that reads a documented knob keeps working. Code that reaches into private internals
|
||||
does not.
|
||||
|
||||
BIN
.github/stargazer_map.png
vendored
|
Before Width: | Height: | Size: 404 KiB After Width: | Height: | Size: 68 KiB |
BIN
.github/stats.png
vendored
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
.github/stats_addons.png
vendored
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.2 KiB |
BIN
aurral/stats.png
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
baikal/stats.png
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
bazarr/stats.png
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -1,4 +1,10 @@
|
||||
|
||||
## 0.6.27.2 (2026-08-23)
|
||||
- Fix: trust the whole supervisor network range for the ingress auth header instead of the addon's own address, which changes across restarts. The list is only written when that range is missing, so an entry added in the calibre-web admin page is no longer erased on every start (https://github.com/alexbelgium/hassio-addons/pull/3010)
|
||||
|
||||
## 0.6.27.1 (2026-08-23)
|
||||
- Fix: Ingress login was rejected since 0.6.27, which only accepts the reverse proxy auth header from trusted source addresses. The addon now adds its own ip to that list (https://github.com/alexbelgium/hassio-addons/issues/3003)
|
||||
|
||||
## 0.6.27 (2026-08-13)
|
||||
- Update to latest version from linuxserver/docker-calibre-web (changelog : https://github.com/linuxserver/docker-calibre-web/releases)
|
||||
|
||||
|
||||
@@ -116,5 +116,5 @@ schema:
|
||||
slug: calibre-web
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons/tree/master/calibre_web
|
||||
version: "0.6.27"
|
||||
version: "0.6.27.2"
|
||||
video: true
|
||||
|
||||
@@ -18,6 +18,20 @@ if [ ! -f /config/app.db ]; then
|
||||
bashio::log.warning "First boot : disabling Ingress until addon restart"
|
||||
else
|
||||
sqlite3 /config/app.db 'update settings set config_reverse_proxy_login_header_name="X-WebAuth-User",config_allow_reverse_proxy_header_login=1'
|
||||
|
||||
# Calibre-web 0.6.27 only accepts that header from a trusted source address, and defaults the
|
||||
# list to "127.0.0.1,::1". Ingress reaches calibre-web from the addon's own address on the
|
||||
# supervisor network (proxy_bind $server_addr in ingress.conf) and calibre-web listens
|
||||
# dual-stack, so it sees ::ffff:<addon ip> and drops the header. The supervisor range is
|
||||
# listed in both forms because an ipv4 entry never matches an ipv4-mapped address.
|
||||
# Prepended to whatever is already there, and only when the mapped form is missing : that form
|
||||
# is the one ingress needs and the one nobody types by hand, so it doubles as the marker that
|
||||
# this already ran. Anything the user added is kept, the statement runs at most once, and the
|
||||
# duplicates it can leave behind are entries calibre-web skips or already trusts.
|
||||
# The column only exists once calibre-web 0.6.27+ has migrated app.db and cont-init runs
|
||||
# before calibre-web, so a failure here is not fatal : the next start applies it.
|
||||
trusted_ips_error=$(sqlite3 /config/app.db "update settings set config_reverse_proxy_trusted_ips='127.0.0.1,::1,::ffff:127.0.0.1,172.30.32.0/23,::ffff:172.30.32.0/119,'||coalesce(config_reverse_proxy_trusted_ips,'') where coalesce(config_reverse_proxy_trusted_ips,'') not like '%::ffff:172.30.32.0/119%'" 2>&1) ||
|
||||
bashio::log.warning "Could not set the ingress trusted ip list, it will be applied at next start (${trusted_ips_error})"
|
||||
fi
|
||||
|
||||
bashio::log.info "Default username:password is admin:admin123"
|
||||
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
codex/stats.png
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
emby/stats.png
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
ente/stats.png
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
gitea/stats.png
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
grav/stats.png
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
immich/stats.png
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
inadyn/stats.png
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
joal/stats.png
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
joplin/stats.png
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
kometa/stats.png
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
komga/stats.png
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
lidarr/stats.png
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
mealie/stats.png
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
monica/stats.png
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
mylar3/stats.png
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
nzbget/stats.png
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
piwigo/stats.png
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
plex/stats.png
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -1,3 +1,13 @@
|
||||
## 2.44.0 (2026-08-23)
|
||||
|
||||
- Fix: Use `portainer/agent:alpine-sts` to match the STS release channel configured in `updater.json`
|
||||
- Fix: Align add-on versioning with Portainer STS releases
|
||||
|
||||
## 2025.12.7 (2026-08-23)
|
||||
|
||||
- Fix: Docker reported the addon as `unhealthy` in Portainer. The healthcheck script could never run because its shebang required the s6-overlay environment, which this addon's entrypoint does not set up (https://github.com/alexbelgium/hassio-addons/issues/3002)
|
||||
- Remove the unused and broken `wait-for-signal` script; nothing invoked it
|
||||
|
||||
## 2025.12.6 (2026-08-01)
|
||||
|
||||
- Version renamed from `2025.12-6`, which Home Assistant could not order and therefore could not reliably offer as an update: every number of the previous version is kept, as a section of its own. The addon itself and the upstream version it tracks are unchanged
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
ARG BUILD_FROM
|
||||
|
||||
# Get agent
|
||||
FROM portainer/agent:alpine as original_agent
|
||||
FROM portainer/agent:alpine-sts as original_agent
|
||||
ENV PORTAINER_AGENT_ARGS=""
|
||||
|
||||
# Build using base
|
||||
@@ -81,8 +81,7 @@ RUN chmod 777 /ha_entrypoint.sh
|
||||
COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh
|
||||
RUN chmod 0755 /usr/local/lib/bashio-standalone.sh
|
||||
|
||||
RUN chmod a+x /usr/sbin/healthcheck && \
|
||||
chmod a+x /usr/sbin/wait-for-signal
|
||||
RUN chmod a+x /usr/sbin/healthcheck
|
||||
WORKDIR "/app"
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/env" ]
|
||||
|
||||
@@ -41,4 +41,4 @@ schema:
|
||||
slug: portainer_agent
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
version: "2025.12.6"
|
||||
version: "2.44.0"
|
||||
@@ -1,4 +1,8 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# Plain bash on purpose : ha_entrypoint.sh replaces s6-overlay's /init, so
|
||||
# /run/s6/container_environment is never created and a with-contenv shebang
|
||||
# would fail before this script runs. Nothing here needs the s6 environment.
|
||||
|
||||
if [ -f "/tmp/healthcheck-signal" ]; then
|
||||
curl -k --fail https://127.0.0.1:9001/ping || exit 1
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
|
||||
START_TIME="$(date +%s)"
|
||||
|
||||
echo "Waiting for first healthcheck execution (max $FIRST_HEALTHCHECK_TIMEOUT seconds)..."
|
||||
|
||||
while [ ! -f "/tmp/healthcheck-signal" ];
|
||||
do
|
||||
sleep 1
|
||||
|
||||
ELAPSED_TIME="$(expr \date +%s\ - $START_TIME)"
|
||||
|
||||
if [ $ELAPSED_TIME -gt $FIRST_HEALTHCHECK_TIMEOUT ]
|
||||
then
|
||||
echo "Signal from healthcheck not received in time, failing the execution..."
|
||||
exit 20
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Signal from healthcheck received"
|
||||
exit 0
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"github_tagfilter": "alpine",
|
||||
"last_update": "24-12-2025",
|
||||
"github_tagfilter": "sts",
|
||||
"last_update": "23-08-2026",
|
||||
"repository": "alexbelgium/hassio-addons",
|
||||
"slug": "portainer_agent",
|
||||
"source": "dockerhub",
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.5 KiB |