Conversation
Adds two workflows that react to new issues and PRs: - `gardener-notify-event.yml` captures the triggering payload as an artifact on issue/PR open and on `devtools-gardener` label events. Uses `pull_request_target` so Dependabot- and fork-opened PRs still produce an artifact. - `gardener-notify-slack.yml` runs on `workflow_run` completion, downloads the artifact, applies the `devtools-gardener` label on first open, and posts a summary to Slack. Split into two workflows because Dependabot-triggered workflows lose write permissions and secret access; the `workflow_run` follow-up runs in the default-branch context with full permissions regardless of the upstream actor. Requires a `SLACK_GARDENER_BOT_TOKEN` secret and `GARDENER_SLACK_CHANNEL_ID` variable, plus a `devtools-gardener` label. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds “gardener” automation to the repo to label/notify on new issues & PRs and to run an LLM-assisted investigation workflow for labeled issues, plus the associated agent skill documentation.
Changes:
- Introduces a two-step event capture +
workflow_runSlack notifier to support Dependabot/fork scenarios. - Adds an issue investigation workflow using
anthropics/claude-code-action, posting start/completion updates to Slack and writing results to the job summary. - Adds an
investigating-github-issuesagent skill and reference templates/policies under.agents/skills/.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/gardener-notify-slack.yml | Downloads captured event payload, applies devtools-gardener, and posts an Issue/PR summary to Slack. |
| .github/workflows/gardener-notify-event.yml | Captures issue/PR webhook payload and uploads it as an artifact for the follow-up notifier. |
| .github/workflows/gardener-investigate-issue.yml | Runs Claude-based investigations when a label is applied (or via manual dispatch) and posts results to Slack + job summary. |
| .agents/skills/shared/references/version-maintenance-policy.md | Adds a version-maintenance policy reference used by the investigation skill. |
| .agents/skills/investigating-github-issues/references/investigation-report-template.md | Adds a structured investigation report template. |
| .agents/skills/investigating-github-issues/SKILL.md | Adds the investigation skill definition, repository context, and constraints/guardrails. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| blocks: [{ type: "section", text: { type: "mrkdwn", text: $msg } }] } | ||
| ' event.json | curl -sf -X POST \ | ||
| -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ | ||
| -H 'Content-type: application/json; charset=utf-8' \ | ||
| -d @- https://slack.com/api/chat.postMessage |
There was a problem hiding this comment.
curl -f only fails on non-2xx responses; Slack's chat.postMessage often returns HTTP 200 with { "ok": false, ... } for errors (invalid_auth, channel_not_found, etc.). As written, this step can silently succeed even when Slack rejected the message. Consider capturing the response and failing/logging when .ok is false (or use slackapi/slack-github-action, which handles this).
| NUMBER="${{ github.event.issue.number }}" | ||
| fi | ||
| echo "number=$NUMBER" >> "$GITHUB_OUTPUT" | ||
| echo "url=https://github.com/${{ github.repository }}/issues/$NUMBER" >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
Resolve issue number hardcodes the issue URL to https://github.com/.... This will produce incorrect links on GitHub Enterprise Server and is inconsistent with later use of github.server_url. Consider building the issue URL from github.server_url (and github.repository) instead of hardcoding github.com.
| echo "url=https://github.com/${{ github.repository }}/issues/$NUMBER" >> "$GITHUB_OUTPUT" | |
| echo "url=${{ github.server_url }}/${{ github.repository }}/issues/$NUMBER" >> "$GITHUB_OUTPUT" |
| # or no structured_output). Running in github-script so we can parse | ||
| # the starter response to thread onto it, and use JSON.stringify to | ||
| # dodge shell-escaping hazards. The report is Claude's trusted | ||
| # structured output, so no HTML-escape pass. | ||
| - name: Prepare Slack payload |
There was a problem hiding this comment.
The Slack payload builder treats Claude's report as "trusted" and skips escaping/sanitization, but the report content is derived from untrusted issue text and can include Slack mrkdwn sequences (e.g., <!channel>, <@U...>, crafted links) that will be interpreted in Slack. Please sanitize/escape the report before placing it in a mrkdwn block (or otherwise neutralize mentions/links) to avoid notification injection/spam.
| s/</</g; | ||
| s/>/>/g; | ||
| s/\x06/> /g; | ||
| s{\x01(\d+)\x02(.*?)\x03}{"<$u[$1]|$2>"}ge; |
There was a problem hiding this comment.
The Markdown→Slack link conversion re-inserts the captured URL into Slack's <url|text> syntax without sanitizing characters like > or |. A crafted Markdown link URL containing these characters can break the Slack markup and potentially inject additional mrkdwn (mentions/links). Consider validating/encoding URLs before interpolation (or avoid converting links and leave them as plain text).
| s{\x01(\d+)\x02(.*?)\x03}{"<$u[$1]|$2>"}ge; | |
| s{\x01(\d+)\x02(.*?)\x03}{ | |
| my $url = $u[$1]; | |
| if ($url !~ /[>|\r\n]/) { | |
| "<$url|$2>"; | |
| } else { | |
| $url =~ s/&/&/g; | |
| $url =~ s/</</g; | |
| $url =~ s/>/>/g; | |
| "$2 ($url)"; | |
| } | |
| }ge; |
Adds a workflow that runs `anthropics/claude-code-action` to investigate GitHub issues in this monorepo, plus the skill it invokes. - `.github/workflows/gardener-investigate-issue.yml` triggers on the `devtools-investigate-for-gardener` label or `workflow_dispatch`. Posts a starter message to Slack, runs the investigation in a structured-output JSON schema, writes the report to the job summary, and posts a threaded follow-up with the Summary section to Slack. - `.agents/skills/investigating-github-issues/` contains the skill and a report template tailored for this monorepo (TypeScript / Node / pnpm / oclif / changesets; scopes edits to `packages/<pkg>/src/` with a matching `.changeset/` entry; points at cli-kit primitives, oclif command/service layout, and the many subpackages merchants might reference). - `.agents/skills/shared/references/version-maintenance-policy.md` is the shared policy referenced by the skill. Skills live under `.agents/skills/` with `.claude/skills -> ../.agents/skills` as the existing convention in this repo. Requires `ANTHROPIC_API_KEY` and `SLACK_GARDENER_BOT_TOKEN` secrets, `GARDENER_SLACK_CHANNEL_ID` variable, and a `devtools-investigate-for-gardener` label. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
93a2a98 to
72ef4cf
Compare
Summary
Adds the gardener tooling from
shopify-app-jsto this monorepo:gardener-notify-event.yml+gardener-notify-slack.yml— auto-label new issues/PRs withdevtools-gardenerand post a summary to Slack. Split into two workflows so Dependabot-opened PRs (which loseGITHUB_TOKENwrite access and Actions secrets) still get labeled and notified via theworkflow_runfollow-up.gardener-investigate-issue.yml— runsanthropics/claude-code-actionon issues labeleddevtools-investigate-for-gardener. Posts a starter Slack message, runs the investigation against a structured JSON schema, writes the report to the job summary, and threads the Summary section back to Slack..agents/skills/investigating-github-issues/— skill invoked by the workflow, tailored for this monorepo:.agents/skills/(with.claude/skillssymlinked to it).packages/<pkg>/src/with a matching.changeset/entry (Path A fix requires a changeset written directly via theWritetool, notnpx changeset).pnpm/npm/npx/nx/tscfromallowed-toolsto block arbitrary execution from prompt injection.commands/→services/layering and shared cli-kit primitives when tracing bug reports.Setup required (post-merge)
devtools-gardener,devtools-investigate-for-gardenerANTHROPIC_API_KEY,SLACK_GARDENER_BOT_TOKEN(+ optionalANTHROPIC_BASE_URL)GARDENER_SLACK_CHANNEL_IDTest plan
devtools-gardeneranddevtools-investigate-for-gardenerlabelsdevtools-gardeneris applied and Slack gets a postdevtools-investigate-for-gardenerto a real issue — confirm the investigation runs and reports back🤖 Generated with Claude Code