Context
agent-image.yml builds only when agent/** changes on main (plus manual workflow_dispatch), resolving the latest Claude Code version at build time and tagging the image with it. Watchtower keeps :latest deployed. The image also bundles pinned third-party binaries (docker CLI, gh, ttyd, PowerShell, npm) whose currency is the main CVE-clearing mechanism per the repo docs.
Problem
- Claude Code staleness: Claude Code releases frequently, but a new release only reaches the fleet when something in
agent/** happens to change or someone remembers to hit dispatch. Since every session on every host runs this binary, the fleet silently falls behind — new CLI features (some of which other issues here depend on, e.g. resume flags) and fixes arrive late.
- CVE drift: Trivy gates run on PRs, but between merges the published image accumulates base-image and npm CVEs with no rebuild to pick up upstream fixes. The
.trivyignore review cycle ("revisit entries when the upstream fix reaches our base image") has no mechanism prompting the revisit.
- The version-resolve step already runs in a throwaway
node:24-alpine container, so the runner constraints (no npm on PATH) are solved.
Proposal
- Add a
schedule: trigger (e.g. daily) to agent-image.yml with a gate step: resolve latest @anthropic-ai/claude-code via the existing throwaway-container pattern, compare against the newest GHCR tag (query GHCR's API with the GITHUB_TOKEN — pushes are authenticated already; if the runner's pull-auth limitation extends to the tags API, skopeo list-tags in a container or the GitHub Packages REST API from the hosted context both work), and skip the build when unchanged.
- Weekly forced rebuild regardless of version delta (a
refresh dispatch input or separate schedule) so base-image/apt/npm fixes flow into :latest — this is what actually keeps the published image's CVE count down, given ignore-unfixed gating on PRs.
- Optionally run Trivy against the rebuilt image in the same job and open/ping an issue when NEW high/critical findings appear that aren't in
.trivyignore — turning the triage-list revisit into an automated prompt.
- Same treatment for
agent-hub-image.yml (weekly refresh only; it has no upstream package to track).
Touchpoints
.github/workflows/agent-image.yml, agent-hub-image.yml
- Notes in CLAUDE.md's Build & Deploy section
Context
agent-image.ymlbuilds only whenagent/**changes on main (plus manualworkflow_dispatch), resolving the latest Claude Code version at build time and tagging the image with it. Watchtower keeps:latestdeployed. The image also bundles pinned third-party binaries (docker CLI, gh, ttyd, PowerShell, npm) whose currency is the main CVE-clearing mechanism per the repo docs.Problem
agent/**happens to change or someone remembers to hit dispatch. Since every session on every host runs this binary, the fleet silently falls behind — new CLI features (some of which other issues here depend on, e.g. resume flags) and fixes arrive late..trivyignorereview cycle ("revisit entries when the upstream fix reaches our base image") has no mechanism prompting the revisit.node:24-alpinecontainer, so the runner constraints (no npm on PATH) are solved.Proposal
schedule:trigger (e.g. daily) toagent-image.ymlwith a gate step: resolve latest@anthropic-ai/claude-codevia the existing throwaway-container pattern, compare against the newest GHCR tag (query GHCR's API with theGITHUB_TOKEN— pushes are authenticated already; if the runner's pull-auth limitation extends to the tags API,skopeo list-tagsin a container or the GitHub Packages REST API from the hosted context both work), and skip the build when unchanged.refreshdispatch input or separate schedule) so base-image/apt/npm fixes flow into:latest— this is what actually keeps the published image's CVE count down, givenignore-unfixedgating on PRs..trivyignore— turning the triage-list revisit into an automated prompt.agent-hub-image.yml(weekly refresh only; it has no upstream package to track).Touchpoints
.github/workflows/agent-image.yml,agent-hub-image.yml