The scheduled curation workflow adds operational complexity to an editorial task that requires human review.
Remove the automation and tune the retained skill to report decisions directly without workflow-specific handoff files.
Co-Authored-By: Claude <noreply@anthropic.com>
## Summary
Fix the Sonnet 5 request failure by removing the deprecated temperature
setting. Make daily curation incremental: skip the model when there are
no unseen merges or expired highlights, review only unseen merge dates
when work exists, and retain a manual full-window recalibration option.
Generated by Codex
## Summary
Replace the static Featured topics section with a data-driven Whatʼs new
timeline. Show the five most important launches by default and let
readers expand the full curated 30-day archive.
Run a daily Claude Sonnet 5 curator over a rolling 30-day window, with
manual dispatch support, deterministic validation, and bot-managed pull
requests. Package the editorial workflow as the reusable
`curate-whats-new` repository skill so Docker Agent and other Agent
Skills-compatible clients can invoke the same process.
Preserve the human-reviewed July 13 through August 11, 2026 result and
flexible selection criteria as a regression example outside the skillʼs
runtime context.
@netlify /
[Homepage
preview](https://deploy-preview-25729--docsdocker.netlify.app/)
Generated by Codex
PR review automation ran for draft transitions and unrelated reviewer requests. Review PRs when opened, upgrade docker-agent-action to v2.0.3, and rerun only when docker-agent is explicitly requested.
## Summary
The CloudFront redirect Lambda (`cloudfront-lambda-redirects.js`)
dropped the request query string when issuing 301 responses, so UTM tags
and other params were lost on redirected URLs. This appends the query
string to the `Location` header of both the exact-match and prefix
redirects (the directory/markdown rewrite branch already forwards the
request, so params survive there).
Adds unit tests (`node --test`, zero dependencies) that render the Go
template the same way `aws.go` does and exercise the handler. The tests
run in CI via a new `releaser-test` Dockerfile stage / bake target,
baked alongside `releaser-build` in the existing `releaser` job.
## Learnings
- The redirect Lambda source is a Go `text/template`
(`{{.RedirectsJSON}}` / `{{.RedirectsPrefixesJSON}}`), rendered and
zipped by `hack/releaser/aws.go`. To unit-test it, substitute the
placeholders the same way `aws.go` does, then evaluate the result as a
CommonJS module.
- `test-go-redirects` validates redirect *data* against the built
`public/` site, so it's the wrong host for a fast pure-JS test — the
`releaser` job, which already builds from `hack/releaser`, is the
natural home and has no Hugo dependency.
Generated by Claude Code
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Single-sources the Docker Agent documentation from the product repo via
a Hugo module mount, joining the pattern used by CLI, Buildx, Compose,
BuildKit, Model Runner, and the Moby API. Closes the docs.docker.com
side of docker/docker-agent#3371.
## Context
The pages under `content/manuals/ai/docker-agent/` were hand-authored
duplicates of the product repo docs and drifted on every upstream
change. The source docs were converted to portable Hugo-clean Markdown
and prepared for mounting in docker/docker-agent#3413 and
docker/docker-agent#3414, released in docker-agent v1.96.0.
## What changed
| Change | Detail |
|---|---|
| `go.mod` | `github.com/docker/docker-agent v1.96.0` added to `require`
and `tool` |
| `hugo.yaml` | `module.imports` mounts the eight docs sections and
`demo.gif` onto `content/manuals/ai/docker-agent/` |
| Content | The 16 hand-authored pages are removed; `_index.md` stays
hand-authored (landing page), with links rewritten to the mounted pages
|
| `_vendor/` | 99 vendored files from the module |
| `.github/workflows/sync-docker-agent-docs.yml` | Daily poll that
vendors the latest docker-agent release and opens a bot PR, modeled on
`sync-cli-docs.yml` |
## URL preservation
Every removed page keeps its URL: the mounted pages carry `aliases`
front matter (added upstream in docker/docker-agent#3414), and
`_index.md` keeps aliases for the removed section indexes
(`integrations/`, `reference/`, `reference/examples/`).
| Old URL | Redirects to |
|---|---|
| `/ai/docker-agent/tutorial/` | `.../getting-started/quickstart/` |
| `/ai/docker-agent/best-practices/` | `.../guides/tips/` |
| `/ai/docker-agent/evals/` | `.../features/evaluation/` |
| `/ai/docker-agent/local-models/` | `.../providers/local/` |
| `/ai/docker-agent/model-providers/` | `.../providers/overview/` |
| `/ai/docker-agent/rag/` | `.../tools/rag/` |
| `/ai/docker-agent/sharing-agents/` | `.../concepts/distribution/` |
| `/ai/docker-agent/integrations/{a2a,acp,mcp}/` | `.../features/a2a/`,
`.../features/acp/`, `.../tools/mcp/` |
| `/ai/docker-agent/reference/{cli,config,toolsets}/` |
`.../features/cli/`, `.../configuration/overview/`,
`.../configuration/tools/` |
| `/ai/docker-agent/integrations/`, `/ai/docker-agent/reference/`,
`/ai/docker-agent/reference/examples/` | `/ai/docker-agent/` |
## Mount scope
All eight sections are mounted rather than a core subset:
`refLinksErrorLevel: ERROR` makes partial mounts fail the build for any
relative link into an unmounted page, and the link closure from the core
sections already pulls in 68 of the 90 pages. Mounting everything keeps
the build link-safe and removes all drift.
## Keeping the pin fresh
On each docker-agent release, `sync-docker-agent-docs.yml` (daily poll,
mirrors `sync-cli-docs.yml`) compares the latest release tag against the
pinned version and opens a bot PR with the re-vendored module.
docker/docker-agent also runs `validate-upstream.yml` on every docs PR,
so upstream changes that would break this site fail CI before they merge
(two source-side issues were caught exactly this way while preparing
this change).
## Validation
`docker buildx bake validate` passes on this branch:
| Target | Result |
|---|---|
| test (Hugo build + htmltest) | pass (3196 pages, 1515 aliases, 3110
documents tested) |
| lint | pass |
| unused-media | pass |
| test-go-redirects | pass |
| validate-vendor | pass |
| dockerfile-lint | pass |
`actionlint` passes on the new workflow.
## Summary
`docker/cagent-action` has moved to a new repository:
`docker/docker-agent-action`.
GitHub Actions `uses:` references must be updated explicitly, so this PR
migrates all references and pins them to
[v2.0.0](https://github.com/docker/docker-agent-action/releases/tag/v2.0.0).
- **New repository**: `docker/docker-agent-action`
- **Pinned commit**: `3c0fa9d282c3f84d08dfd70ab0a28b151d11db70`
- **Version**: `v2.0.0`
ℹ️ The old `docker/cagent-action` repo remains functional, so there is
no deadline — merge whenever convenient. New features and fixes land in
the new repo, which is where you'll want to be going forward.
> Auto-generated by the
[migrate-consumers](https://github.com/docker/docker-agent-action/actions/runs/28023540082)
workflow.
Note in AGENTS.md and the PR review workflow that
content/reference/api/ai-governance/api.yaml is a verbatim copy of the
upstream OpenAPI spec, vendored from the private docker/governor-services
repo via hack/sync-governance-api.sh, and should not be hand-edited.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
<!--Delete sections as needed -->
## Description
Fix stale action not closing PRs due to missing `actions: write`
permission
The stale action uses GitHub Actions cache to persist state between
runs. Without `actions: write`, it can't delete its `_state` cache entry
(fails with 403), so the old state accumulates and PRs in that cached
state are permanently skipped with `processed during the previous run`,
meaning they never get evaluated for closing.
Confirmed via Actions logs: PR #23598 was marked stale on April 24 but
has never been evaluated for closing because it appears in the stuck
cache state every run.
## Related issues or tickets
<!-- Related issues, pull requests, or Jira tickets -->
## Reviews
<!-- Notes for reviewers here -->
<!-- List applicable reviews (optionally @tag reviewers) -->
- [ ] Technical review
- [ ] Editorial review
- [ ] Product review
Signed-off-by: Craig Osterhout <craig.osterhout@docker.com>
## Summary
An audit of docker-agent review comments across recent merged PRs
surfaced two
recurring false positives, both traced to their source:
- The bot's prompt (`.github/workflows/pr-review.yml`) instructed it to
flag
lines over 80 characters, but no such rule exists — markdownlint MD013
is
disabled and STYLE.md never mentions it. The bot itself conceded this
mid-review on a past PR. Removed the instruction.
- STYLE.md's word list banned "enable" yet used it in a ✅ example, so
the bot
flagged every "enable"/"disable" as a violation. Added a note clarifying
that
"turn on/off" is for UI toggles while "enable/disable" is fine in
general
prose.
## Learnings
- The docker-agent PR reviewer is driven by the `additional-prompt`
block in
`.github/workflows/pr-review.yml` (via `docker/cagent-action`), plus
`STYLE.md` and `COMPONENTS.md` loaded as prompt files. That prompt — not
just
the style guides — is the source of truth for what the bot flags, so
review
noise can be tuned there directly.
Generated by Claude Code
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Problem
The labeler workflow has been silently skipping labels on some PRs. The
runs show up as `cancelled` rather than `success`.
Root cause is the concurrency config:
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
```
The workflow triggers on `pull_request_target`, and for that event
`github.ref` resolves to the **base branch** (`refs/heads/main`), not
the PR head ref. So every labeler run across **all** open PRs lands in
the same concurrency group (`labeler-refs/heads/main`), and
`cancel-in-progress: true` kills whichever run is in flight as soon as
another PR triggers the workflow.
When several PRs are created or updated within seconds of each other,
the earlier runs get cancelled before they finish labeling. Example from
recent runs:
- `sbx-policy-recipes` (cancelled) ← cancelled by `remove-api-header`
(success) seconds later
- `sbx-linux-keychain` (cancelled) ← cancelled by `storage-drivers`
(success) seconds later
## Fix
Key the concurrency group on the PR number instead, falling back to
`github.ref` for non-PR contexts, so each PR gets its own group and runs
no longer cancel each other.
```yaml
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
```
> [!NOTE]
> A separate, rarer class of labeler failures (genuine `failure` status)
was caused by transient GitHub infrastructure errors downloading the
pinned action tarball at the "Set up job" step. Those are not addressed
here as they only need a re-run.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The PR-review bot's prompt instructed it to flag lines over 80 characters,
but no such rule exists in the repo (markdownlint MD013 is disabled and
STYLE.md never mentions it). Remove that instruction from pr-review.yml.
Also clarify the STYLE.md word list so "turn on/off" applies to UI toggles
while "enable/disable" stays acceptable in general prose, matching STYLE.md's
own example. This stops the bot from flagging every "enable" as a violation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v1.5.2's review-pr/action.yml has a YAML parse error at line 822 that
breaks the PR review workflow. Tracking upstream at
docker/cagent-action#205.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switch trigger from workflow_dispatch back to pull_request_target.
The workflow does not check out PR code so pull_request_target is safe.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
<!--Delete sections as needed -->
## Description
Link to contribute guide no longer exists.
Updated message to remove link or point to relevant link.
## Related issues or tickets
<!-- Related issues, pull requests, or Jira tickets -->
## Reviews
<!-- Notes for reviewers here -->
<!-- List applicable reviews (optionally @tag reviewers) -->
- [ ] Editorial review
Signed-off-by: Craig Osterhout <craig.osterhout@docker.com>
<!--Delete sections as needed -->
## Description
This PR adds a GitHub Actions workflow to automatically mark and close
stale issues and PRs, helping maintainers focus on active items. The old
app/bot stopped working around mid 2025 and was disabled. This
reimplements it using a GitHub Action with additional slash command
functionality.
### Timeframes
- **Mark as stale**: After **180 days** (6 months) of inactivity
- **Close stale issues**: After **14 additional days** of no activity
- **Close stale PRs**: After **30 additional days** of no activity
### Exempt Labels
Issues and PRs with any of these labels will never be marked as stale:
- `kind/help-wanted`
- `status/need-more-info`
- `status/needs-analysis`
- `lifecycle/frozen`
### How to Keep Issues/PRs Active
To prevent an issue or PR from being marked as stale or closed:
**Anyone can:**
1. **Add a comment** - any comment resets the inactivity timer
2. **Use `/lifecycle active`** - removes the stale label via slash
command
**Maintainers can also:**
3. **Use `/lifecycle frozen`** - prevents the issue/PR from ever being
marked stale
4. **Add exempt labels** - manually apply one of the labels listed above
5. **Make any update** - editing the description, adding labels, or any
activity resets the timer
### Slash Commands
The workflow supports these lifecycle commands (comment them on any
issue/PR):
| Command | Access | Description |
|---------|--------|-------------|
| `/lifecycle active` | Anyone | Removes the stale label |
| `/lifecycle frozen` | Write access required | Prevents stale marking |
| `/lifecycle stale` | Write access required | Manually marks as stale |
| `/remove-lifecycle frozen` | Write access required | Removes frozen
label |
| `/remove-lifecycle stale` | Anyone | Removes stale label |
Commands respond with a 👍 reaction when successful, 👎 when permission is
denied.
### Messages
When marked as stale, issues and PRs receive a friendly comment
explaining:
- The situation and timeline for closure (14-30 days)
- How to remove the stale label using `/lifecycle active`
- How maintainers can freeze with `/lifecycle frozen`
### Debug Mode
The workflow is currently set to **debug mode** for both components:
**Stale action** (`debug-only: true`):
- ✅ Runs and logs what actions it would take
- ❌ No actual changes will be made (no labels, comments, or closures)
**Lifecycle commands** (`DEBUG_ONLY: 'true'`):
- ✅ Logs what would happen when slash commands are used
- ❌ No labels added, removed, or permission checks enforced
## Related issues
- #19050
---------
Signed-off-by: Craig Osterhout <craig.osterhout@docker.com>
The CloudFront Lambda rewrote `/` with `Accept: text/markdown` to an
invalid `.md` URI, causing a 502 LambdaValidationError. Homepage has no
flattened markdown equivalent, so route to `/llms.txt` — the
agent-oriented markdown index of the site. Same handling for
`/index.html`.
Also set `Content-Type: text/markdown` on `llms.txt` at upload time, so
content negotiation responses and direct requests both advertise the
correct media type.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
## Description
The `release-notes-pr-trigger` workflow was interpolating PR context
values
(`html_url`, `title`, `user.login`) directly into a shell heredoc. A
specially crafted PR title or author name could break out of the JSON
string
and execute arbitrary commands.
This change moves the GitHub context values into environment variables
and
uses `jq` to safely construct the JSON artifact, eliminating the
injection
vector.
## Related issues or tickets
None
## Reviews
- [x] Technical review
Signed-off-by: Lorena Rangel <lorena.rangel@docker.com>
## Description
The Slack notification workflow for Desktop release notes PRs fails when
the PR is opened from a fork because GitHub doesn't expose repository
secrets to `pull_request` events from forks.
This PR splits the workflow into two:
1. **Release Notes PR Trigger** — runs on `pull_request`, saves PR
details (URL, title, author) as an artifact. No secrets needed.
2. **Notify Slack on Desktop Release Notes PR** — runs on `workflow_run`
after the trigger completes, downloads the artifact, and sends the
Slack notification. Has access to secrets since `workflow_run` runs in
the context of the base repository.
## Related issues or tickets
Fixes the `SlackError: Missing input! A token must be provided` error
in the notify-release-notes-pr workflow.
## Reviews
- [x] Technical review
Signed-off-by: Lorena Rangel <lorena.rangel@docker.com>
<!--Delete sections as needed -->
## Description
Adds a GitHub Actions workflow that posts a Slack notification when a
pull request is opened that modifies the Desktop release notes page
(content/manuals/desktop/release-notes.md).
The workflow uses slackapi/slack-github-action v3.0.1 and sends a
message with a link to the PR and the author's GitHub profile to the
configured Slack channel.
Will need to add the secrets.
## Related issues or tickets
n/a
## Reviews
<!-- Notes for reviewers here -->
<!-- List applicable reviews (optionally @tag reviewers) -->
- [x] Technical review
- [ ] Editorial review
- [ ] Product review
Signed-off-by: Lorena Rangel <lorena.rangel@docker.com>
pr-review: drop pull_request_target (auto-review on open/ready_for_review).
Manual /review via issue_comment is preserved and unaffected.
labeler: replace pull_request_target with workflow_dispatch to disable
automatic fork-PR labeling. Can be re-enabled by reverting this change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All mutable action tags replaced with verified commit SHAs to prevent
supply-chain attacks via tag mutation. package.json ^ ranges replaced
with exact versions from package-lock.json.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>