feat(generic): add generic mode with prompt_file input - #34
Conversation
Adds a fourth mode for a scripted, no-tools, no-GitHub-entity call: a caller has already built its own complete prompt (from data only it has -- a PR list, a diffstat, a style reference) and wants Claude Code purely as a text/JSON generator, with none of review/triage/interactive's assumption that the model fetches its own context via granted tools. prompt_file points at a file on the runner whose content becomes the entire prompt verbatim, bypassing prompts/shared/base.md, the mode fragment, and the generated "This run" facts block entirely -- the same full-override philosophy claude_args already applies to CLI arguments, extended here to the prompt itself. The tool allowlist defaults to empty (Write/Edit/NotebookEdit denied explicitly too), matching a plain `claude --print --allowedTools ""` call, and stays fully overridable via extra_claude_args. "Validate inputs" rejects mode: generic outright when prompt_file is unset, since generic mode has no fragment or generated prompt of its own to fall back to.
Deliberately no examples/claude-generic.yml (reusable-workflow) counterpart and no reusable generic.yml workflow: the three existing reusable workflows centralise event-trigger gating (label/mention/author-association checks for pull-request and issue events), and generic mode has no event-trigger semantics of its own -- it is called imperatively from inside a job a caller already has, not dispatched off a GitHub event. The demo summarises the repository's own CHANGELOG.md into a validated JSON object via --json-schema, standing in for "build a prompt file from data only your job has, then read structured_output back."
Adds a row to the top mode table and "What each mode is allowed to do", a note under "Adopting it in a repository" explaining the deliberate absence of a reusable-workflow form, a prompt_file blurb under "Calling the action directly" and "Extended options", and a closing note on "Layout" describing the composition bypass.
…p-token minting Generic mode makes no GitHub API calls of its own, so there is nothing for a minted GitHub App token to do -- but the upstream action attempts that mint unconditionally when github_token is unset, regardless of mode. On a workflow file GitHub has not yet seen on the repository's default branch, that OIDC exchange fails workflow-content validation outright rather than degrading gracefully, which the "Calling the action directly" section already documents as a general omit-github_token cost. Passing the job's own token avoids it.
Its job is done: it confirmed mode validation, tool-permission resolution (empty allowlist), and prompt-file composition all work correctly, and surfaced the github_token/OIDC-mint fix folded into the real example in the previous commit. The live Claude call itself hit the shared account's weekly quota rather than completing end-to-end -- documented on the PR.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
…alls resume_sessions defaults to true and resumes whichever session file was most recently modified under the job's own local cache directory, with no awareness of mode, entity, or prompt_file. A job that calls generic mode more than once -- the release-pipeline use case this mode exists for -- will silently feed an earlier call's unrelated conversation into the next one's context unless resume_sessions: false is set on each call, as the example already does without explaining why.
|
Addressed the resume_sessions finding: both README.md's "Generic mode's prompt" paragraph and prompt_file's own description in action.yml now warn explicitly that resume_sessions defaults to true, is scoped only to the job's local cache directory (not mode/entity/prompt_file), and needs resume_sessions: false on every call when a job invokes generic mode more than once -- exactly the release-pipeline shape this mode exists for. Resolving the thread. Left the wrap-up-on-turn-limit tool-permission gap as noted -- it's pre-existing across every mode, not introduced by this diff, and fixing it means touching shared wrap-up logic outside this PR's scope. |
Superseded by re-review on the latest commit.
Every other reusable-workflow and direct-example call site spells the job's ambient token as secrets.GITHUB_TOKEN, never github.token -- both resolve to the same value, but this keeps the example consistent with review.yml/triage.yml/interactive.yml's own examples.
Superseded by re-review on the latest commit.
There was a problem hiding this comment.
Re-review on the latest commit (f1b758a → d1aacc5). This is sound to merge.
The only change since my last review is the single-line fix for the github.token → secrets.GITHUB_TOKEN nit I raised previously (examples/direct/claude-generic.yml), matching the spelling convention used everywhere else in the repo. Both of my prior threads (the resume_sessions Should-fix and the github_token Nit) are confirmed resolved in the current diff and have been left resolved.
I re-read the full diff (README, action.yml, and the new examples/direct/claude-generic.yml) rather than relying solely on the delta:
mode: generic's validation, theprompt_fileverbatim-bypass branch in "Compose prompt" (including its earlyexit 0and thetext<<delimheredoc format), and thegenericcase in "Resolve tool permissions" (ALLOWED="",Write/Edit/NotebookEditdenied) are all consistent with the rest of the file's conventions and with the PR description's claims.- The
actions/checkoutSHA pinned in the new example (3d3c42e5aac5ba805825da76410c181273ba90b1) matches tagv7.0.1on the upstream repo. PROMPT_FILEisn't accidentally caught by the review-only-input guard (action.yml:498), and the "Post progress comment" step degrades sensibly for generic mode (falls into the genericVERBcase and no-ops when there's no PR/issue number, matching the example'spost_progress_comment: false).
Nothing else stood out. I dismissed my prior stale review (state was still live APPROVED on an old commit) and cleared its body per the re-review cleanup convention.
|
🎉 This PR is included in version 1.2.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
generic, for a scripted, no-tools, no-GitHub-entity call: a caller has already built its own complete prompt (from data only it has) and wants Claude Code purely as a text/JSON generator.prompt_fileinput: a path to a file on the runner whose content becomes the entire prompt verbatim, bypassingprompts/shared/base.md, the mode fragment, and the generated "This run" facts block entirely -- the same full-override philosophyclaude_argsalready applies to CLI arguments, extended to the prompt itself.genericmode's tool allowlist defaults to empty (Write/Edit/NotebookEditdenied explicitly too), matching a plainclaude --print --allowedTools ""call, and stays fully overridable viaextra_claude_args. Credential fallback,modelpinning,--json-schema/structured_output,resume_sessions, andwrap_up_on_turn_limitare all mode-agnostic already and apply togenericunchanged.prompts/generic/directory (nothing would read from it) and no reusablegeneric.ymlworkflow /examples/claude-generic.yml-- deliberate: the three existing reusable workflows centralise event-trigger gating (label/mention/author-association checks), andgenericmode has no event-trigger semantics of its own. Addedexamples/direct/claude-generic.ymlinstead, demonstrating direct composite-action usage.github_tokenexplicitly -- discovered live (see Test plan) that omitting it makes the upstream action try to mint a GitHub App token via OIDC regardless of mode, which fails workflow-content validation outright on a workflow file not yet on the default branch. Generic mode never needs GitHub API access, so there's no reason to pay that cost.Motivation
adpeak/adpeak-mono'srelease.ymlhas three call sites that invoke the Claude Code CLI directly via raw bash (npx -y @anthropic-ai/claude-code@latest ...), each with a single hardcoded credential and no fallback -- unlike this action's up-to-5-credential fallback chain. None ofreview/triage/interactivefit that shape (a scripted, pre-built-prompt, zero-tool call with no PR/issue in context), hence this mode. Full context: a real CI failure diagnosis where the raw-CLI step's own stdout was redirected to a file and swallowed on failure, discovered via a siblingclaude-review.ymlrun hitting the account's session limit.Test plan
npm run lint && npm run typecheck && npm run format:checkall clean; CI green.action.yml's changedruns.stepsvalidated by wrapping in a syntheticworkflow_callreusable workflow (mirroring real inputs) and runningactionlintagainst it -- zero new findings versus the same technique run against the pre-change file (same 25 pre-existing shellcheck info/style findings on unrelated, unchanged lines, just line-shifted).actionlint examples/direct/claude-generic.ymlclean.pull_request-triggered copy of the demo against this branch (removed before merge, see commit history). Confirmed directly from the run log: "Validate inputs" passesmode: genericcleanly (no unbound-variable failure); "Resolve tool permissions" logsMode 'generic' allowlist:(empty); "Compose prompt" logsComposed prompt: verbatim from <path> (18856 bytes, 168 lines)matching the input file exactly; the composedclaude_argscorrectly resolved to--allowedTools "" --disallowedTools "Write,Edit,NotebookEdit" --model "sonnet"plus the appended--json-schema; the call reached the real Anthropic API (a genuine429response came back, not a parse/validation error).structured_outputpopulated from a successful (non-rate-limited) call. The live test above hit the shared org credential's weekly quota ("You've hit your weekly limit · resets Sep 6, 1am (UTC)") before a clean run completed. Every other mechanic generic mode depends on is confirmed working; only the final "did a successful call's JSON actually round-trip throughstructured_output" step is still unverified, and that mechanism is shared, unmodified code already exercised by review mode's ownstructured_review_summary-- worth a quick manual confirmation once quota resets, not blocking on it given everything upstream of it is now confirmed correct.