docs: a negative result is usually your own filter (skill + AGENTS.md)
Lint / hadolint (push) Successful in 13s
Lint / actionlint (push) Successful in 16s

Three false negatives in one session, all self-inflicted, all convincing
because the command "succeeded": a `| head -20` proved an SSH peer absent
that sits at line 454 of a ~500-line config; `ssh mac 'docker ps'` proved
the host had no Docker, when the non-interactive PATH simply lacks
/usr/local/bin; and `grep 'ssh '` proved no ControlMaster was running,
when those processes rename themselves to `ssh: <path> [mux]`. Same root
cause each time, so it goes in the skill rather than in a commit message:
a positive result carries its own evidence, absence has to be earned.

The skill (rootfs/, symlinked into ~/.agents/skills) is BAKED, so this is
an image change and is logged in CHANGELOG Unreleased accordingly. Its §3
also now records that a live ControlMaster socket makes later commands
authenticate not at all -- after editing a peer's authorized_keys, "it
still works" proves nothing; prove it with -o ControlPath=none, or the
breakage waits for a future session that has no memory of the edit.

AGENTS.md: corrected a stale CI claim while placing the pointer. It said a
tag push produces two runs including lint; lint.yml has since been scoped
to branches: ['**'], which excludes tag refs, and refs/tags/v1.8.4 duly
produced run 571 (publish) and nothing else. Kept the head_sha + workflow
path filter advice, which is cheap and guards against a future v*-triggered
workflow. Added a short section on verifying this repo from inside a
container, including that docker-compose.yml here is a TEMPLATE pinning
:latest while a real host runs its own per-machine file -- recreating from
the repo copy can silently move a host off :latest-studio.

Placement note: AGENTS.md is only auto-read when the cwd is this repo, so
the durable rule lives in the skill, which loads by description match in
any pi-devbox session.
This commit is contained in:
Joakim Persson
2026-08-22 22:56:41 +02:00
parent 2ebf00d6d4
commit fbc1f86612
3 changed files with 124 additions and 4 deletions
+37 -4
View File
@@ -76,10 +76,15 @@ re-brand of opencode-devbox's `pi-only` variant.
4. Push tag: `git tag vX.Y.Z && git push origin vX.Y.Z`.
5. Watch CI: smoke job builds amd64 only and asserts size + extensions +
pi version + new-base-tooling presence. Variant build is multi-arch
(amd64 + arm64) only after smoke passes. **A tag push produces two runs, not
one** — `lint.yml` fires on every push (including tag refs) and
`docker-publish.yml` fires on `v*` tags. Watch the **publish** run; see
*Gitea API access* below for how to find it without picking lint by mistake.
(amd64 + arm64) only after smoke passes. A tag push fires **only**
`docker-publish.yml` — `lint.yml` is scoped to `branches: ['**']`, which
excludes tag refs on purpose (the tagged tree was already linted when the
commit hit `main`, and a fast lint run sorting above the slow publish run
made releases look finished before anything shipped). Verified on v1.8.4:
`refs/tags/v1.8.4` produced run 571 (publish) and nothing else. Still filter
discovery on `head_sha` **and** the workflow `path` — see *Gitea API access*
below — because that guard costs nothing and a future workflow added on `v*`
would silently reintroduce the ambiguity.
6. Verify the Hub tags appear (latest + vX.Y.Z, the `-studio` pair, plus
base-latest if the base was rebuilt this run).
7. **Revoke any short-lived Gitea PAT** used during the release at
@@ -87,6 +92,34 @@ re-brand of opencode-devbox's `pi-only` variant.
`GITEA_ACCESS_TOKEN` env var instead (see *Gitea API access* below) —
its lifecycle is managed host-side, nothing to revoke.
## Verifying this repo's reality from inside a container
Most work on this repo happens **inside** a pi-devbox container, inspecting a
host or a peer over SSH. That setup manufactures convincing false negatives, so
when you are about to report that something is **absent, unreachable, or not
running**, suspect your own command first. Recurring instances:
- **`docker` is not on the host's non-interactive SSH `PATH`.** `ssh mac 'docker
ps'` says *command not found* on a host that plainly runs Docker; use
`/usr/local/bin/docker` (or `command -v docker` first). Every step in the
*Release-day checklist* that inspects a running container hits this.
- **Don't `| head -N` a search whose answer you don't already know.** The host's
`~/.ssh/config` is ~500 lines; a `head -20` "proved" a peer absent that was
defined at line 454.
- **The deployment compose file is not this repo's.** `docker-compose.yml` here
is a template pinning `:latest`; a real host runs its own per-machine file
(find it with `docker inspect <container> --format '{{ index .Config.Labels
"com.docker.compose.project.config_files" }}'`). Recreating from the repo copy
can silently move a host off `:latest-studio` onto `:latest`.
- **A live SSH ControlMaster hides remote auth changes** — after editing a
peer's `authorized_keys`, prove access with `-o ControlPath=none -o
ControlMaster=no`, or the breakage surfaces in a later session instead.
Depth and further mechanisms: the repo-authored `pi-devbox-environment` skill
(`rootfs/usr/local/share/pi-devbox/skills/pi-devbox-environment/SKILL.md`) §2
and §3 — that file is the one an agent actually loads mid-session, whereas this
`AGENTS.md` is only auto-read when the cwd *is* this repo.
## Gitea API access (env token)
`GITEA_ACCESS_TOKEN` + `GITEA_HOST` are passed into the container from the