Repository navigation
Conversation
…ly until switched on Adds an unprompted first-response lane on `issues: [opened]`, the thing blakeblackshear/frigate gets from Inkeep: a stranger files an issue and receives a researched, cited reply without knowing a bot exists. `claude.yml` already fires on the same event but only when the reporter typed `@claude`, which nobody who has never used the repo will do. That is an on-demand assistant; this is a first responder. A guard on the `@claude` string keeps them mutually exclusive, or a mention would draw two replies to the same issue. Four decisions worth recording, since none of them are the obvious default: Newly opened issues, and only that. No `issue_comment`, no `discussion`, and no backfill - `opened` cannot reach the issues that already exist. Follow-ups are already served by `claude.yml`. Discussions are out by decision, not by omission: claude-code-action has no `discussion` trigger, and its own security.md lists Discussions access as requested-but-unused pending a future release, so a lane there would be bespoke GraphQL glue against an API the action is expected to grow. The ledger records what it would cost, so the question does not get reopened from scratch. Outside reporters only. The `if:` excludes OWNER/MEMBER/COLLABORATOR by `author_association`, because most issues here are opened by the maintainer - upstream mirrors and tracking items - and auto-answering your own tracking issue is noise and a paid run. The cost is that the lane cannot be triggered by its own author, so it ships untested; that is recorded in the ledger rather than papered over. Posting is off, on a repo variable rather than a commit. Until CLAUDE_ISSUE_AUTOREPLY is `true` the draft goes to the job summary and the issue is untouched. This mirrors Inkeep's preview mode, and matters most in the other direction: a bot answering badly on a stranger's bug report is silenced with one command, not a PR. Claude cannot write to the issue. It produces `draft-reply.md` with a read-only tool allowlist; a plain step posts the file. An issue body is attacker-controlled text, and this keeps it away from the write path entirely - the difference between granting arbitrary `gh` calls and granting a file whose contents are merely untrusted. The AI disclosure is appended by that step, not asked of the model, so it cannot be dropped or injected away. Same reasoning as the allowlist note already in claude-code-review.yml. No changelog entry: nothing here is observable to a user of the library. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dependency ReviewThe following issues were found:
License Issues.github/workflows/claude-issue-response.yml
OpenSSF Scorecard
Scanned Files
|
|
Claude finished @astubbs's task in 5m 15s —— View job Review of PR #256 — Issue First Response workflow
Note on verification scope: my sandbox in this session declined every Finding:
|
✅ Duplicate Code ReportTwo engines run in parallel for cross-validation. Each has its own thresholds tuned to its baseline - the real safety net is the per-engine "max increase vs base" check. ✅ PMD CPD
No new clones introduced by this PR. ✅ jscpd (language-agnostic)
No new clones introduced by this PR. Powered by astubbs/duplicate-code-cross-check |
✅ SpotBugs ReportNo bugs found (new bugs only — baseline from base branch excluded). |
…h silently 403s Review of #256 caught it. `Bash(gh pr view:*)` and `Bash(gh pr list:*)` are in the allowlist and the prompt makes "search merged PRs" step 2 of the research order - the step most likely to yield the single most useful reply a first responder can give, "that is already fixed in #NN, it just has not shipped yet". Declaring a `permissions:` block sets every unlisted scope to `none`, and the block listed only contents/issues/id-token. So every `gh pr` call would have returned 403, and Claude would have read the 403 and written its reply without that evidence: no job failure, no log line, just a quietly worse answer on every issue. The same green-does-not-mean-it-worked shape the workflow's own header warns about for a different step. claude-code-review.yml already grants the scope for the same tools, which is what confirmed the diagnosis rather than just the symptom. Also drops the header's "read-only" shorthand for the allowlist, which was imprecise now that it grants `Write` for the draft file. The property that actually matters is that no granted tool reaches the GitHub API for a write, so that is what the comment says. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed in
"read-only" allowlist - reworded. Correct catch: it grants On your verification-scope note - escalating it beyond this PR. You reported that every Not changed, for the record: the |
|
Claude finished @astubbs's task in 1m 28s —— View job Re-review of PR #256 — Issue First Response workflow (after
|
…hanges) Directory move only, so every path is 100% similar and git's exact-rename detection cannot fail on it. The content edits follow in the next commit. Generated by bin/rename-packages.sh.
Text edits only. No file moves in this commit, so it cannot dilute the rename detection in its parent. Generated by bin/rename-packages.sh.

Description
Adds an unprompted first-response lane on
issues: [opened]- the thing blakeblackshear/frigate getsfrom Inkeep. A stranger files an issue and receives a researched, cited reply without knowing a bot
exists.
claude.ymlalready fires on the same event, but only when the reporter typed@claude, whichnobody arriving at the repo for the first time will do. That is an on-demand assistant; this is a
first responder. A guard on the
@claudestring keeps the two mutually exclusive, or a mention woulddraw two replies to one issue.
Scope is deliberately narrow: newly opened issues, nothing else.
author_associationexcludes OWNER/MEMBER/COLLABORATOR)@claude- existingclaude.yml, unchangedopenedcannot reach themFour decisions worth reviewing
Outside reporters only. Most issues here are filed by the maintainer - upstream mirrors and
tracking items - and auto-answering your own tracking issue is noise plus a paid run. The cost is
real and is recorded rather than hidden: the
if:excludes OWNER, so the lane cannot be triggeredby its own author, and the first genuine run will be a real reporter after merge.
Posting is off, on a repo variable rather than a commit. Until
CLAUDE_ISSUE_AUTOREPLYistrue, the drafted reply goes to the Actions job summary and the issue is untouched. This isInkeep's preview mode, and a variable rather than a commit because the direction that matters is
turning it off: a bot answering badly on a stranger's bug report is silenced with one command, not
a PR.
Claude has no tool that can write to the issue. It produces
draft-reply.mdunder an enumerableallowlist whose every entry is read-only except
Write; a plain workflow step posts the file. An issue body is attacker-controlled text, and thisis the difference between granting arbitrary
ghcalls over that text and granting a file whosecontents are merely untrusted. The AI disclosure is appended by that step rather than asked of the
model, so it cannot be reworded or injected away. Same reasoning as the allowlist note already in
claude-code-review.yml.Discussions are out by decision, not omission.
claude-code-actionhas nodiscussiontrigger,and its own
docs/security.mdlists Discussions read/write as "requested but not yet actively used... will enable planned features in future releases". A lane there would be bespoke glue around the
addDiscussionCommentGraphQL mutation (discussion comments have no REST endpoint) against an APIthe action is expected to grow natively.
docs/inflight/ci-issue-autoresponder.mdrecords what itwould cost so the question does not get reopened from scratch.
Verification
actionlintclean on the new workflow. The two findings it reports repo-wide (maven.ymlconstantif: false,quarantine-lane.ymlSC2086) are pre-existing onmasterand untouched here.bin/check-action-versions.shpasses -actions/checkout@v6andanthropics/claude-code-action@v1match every other workflow.
run:steps were extracted from the YAML and executed locally against a present and an absentdraft-reply.md, confirming the summary output and that the footer heredoc lands unindented.if:expression, for thereason above.
Known limitation
A green run does not mean the issue was answered.
claude-code-actionreports its own skips assuccess -
docs/inflight/ci-review-agent.mdrecords this biting the review lane twice. The summarystep here therefore prints the draft-step outcome and says explicitly when no draft was produced,
but there is no gate equivalent to
bin/check-review-posted.sh, because this lane produces norequired check and gates nothing.
Checklist
AGENTS.mdCI section gains the workflow entry (what it does, who it answers,the live switch, and why Claude cannot reach the issues API); new ledger note
docs/inflight/ci-issue-autoresponder.mdcovers the untested-until-merge gap and theDiscussions decision. No
CHANGELOG.adocentry - nothing here is observable to a user of thelibrary, per the release-time generation policy.
N/A- CI workflow with no extractable logic. The eligibility rule is aGitHub
if:expression, which only GitHub evaluates; a JS unit test would exercise are-implementation rather than the expression that runs, which is worse than no test. What is
testable was tested: both
run:steps were extracted and executed locally (see Verification),and
actionlintcovers the rest. Same position as ci: cancel a PR's still-running CI when the PR closes #107 and ci(review): let the PR reviewer verify claims instead of trusting them #102, which could likewise only beexercised by their own merge.
ubuntu-latest, never a self-hostedrunner. Security is the main design constraint, covered above: the job reads attacker-controlled
text (issue title and body) while holding
CLAUDE_CODE_OAUTH_TOKEN, so the tool allowlist isenumerable and reaches no GitHub write API (
Writeto the draft file is its only mutation), theprompt interpolates the issue number and nothing else,
Writeoutput reaches the issue only via a fixed
gh issue comment --body-filein a plain step, andpersist-credentials: falseon the checkout since nothing here builds or runs repo code. Itnever executes PR- or reporter-authored code, which is the open concern for
claude-code-review.yml. Residual risk is that a drafted reply's content is influenced by acrafted issue - bounded by the disclosure footer, the off-by-default switch, and the prompt's
instruction to report injection attempts rather than follow them.