Skip to content

feat(generic): add generic mode with prompt_file input - #34

Merged
Mearman merged 12 commits into
mainfrom
feat/generic-mode
Sep 4, 2026
Merged

feat(generic): add generic mode with prompt_file input#34
Mearman merged 12 commits into
mainfrom
feat/generic-mode

Conversation

@Mearman

@Mearman Mearman commented Sep 4, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds a fourth mode, 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.
  • New prompt_file input: a path to 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 to the prompt itself.
  • generic mode's 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. Credential fallback, model pinning, --json-schema/structured_output, resume_sessions, and wrap_up_on_turn_limit are all mode-agnostic already and apply to generic unchanged.
  • No prompts/generic/ directory (nothing would read from it) and no reusable generic.yml workflow / examples/claude-generic.yml -- deliberate: the three existing reusable workflows centralise event-trigger gating (label/mention/author-association checks), and generic mode has no event-trigger semantics of its own. Added examples/direct/claude-generic.yml instead, demonstrating direct composite-action usage.
  • README updated: mode table, "What each mode is allowed to do", "Adopting it in a repository", "Calling the action directly", "Extended options", "Layout".
  • The example also passes github_token explicitly -- 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's release.yml has 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 of review/triage/interactive fit 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 sibling claude-review.yml run hitting the account's session limit.

Test plan

  • npm run lint && npm run typecheck && npm run format:check all clean; CI green.
  • action.yml's changed runs.steps validated by wrapping in a synthetic workflow_call reusable workflow (mirroring real inputs) and running actionlint against 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.yml clean.
  • Live-fired a temporary pull_request-triggered copy of the demo against this branch (removed before merge, see commit history). Confirmed directly from the run log: "Validate inputs" passes mode: generic cleanly (no unbound-variable failure); "Resolve tool permissions" logs Mode 'generic' allowlist: (empty); "Compose prompt" logs Composed prompt: verbatim from <path> (18856 bytes, 168 lines) matching the input file exactly; the composed claude_args correctly resolved to --allowedTools "" --disallowedTools "Write,Edit,NotebookEdit" --model "sonnet" plus the appended --json-schema; the call reached the real Anthropic API (a genuine 429 response came back, not a parse/validation error).
  • Not yet confirmed end-to-end: a real structured_output populated 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 through structured_output" step is still unverified, and that mechanism is shared, unmodified code already exercised by review mode's own structured_review_summary -- worth a quick manual confirmation once quota resets, not blocking on it given everything upstream of it is now confirmed correct.

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.
@Mearman
Mearman marked this pull request as ready for review September 4, 2026 14:36
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review Completed 2026-09-04T14:44:47.147557Z 6677341 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

claude[bot]
claude Bot previously requested changes Sep 4, 2026
Comment thread README.md Outdated
…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.
@Mearman

Mearman commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

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.

@claude
claude Bot dismissed their stale review September 4, 2026 14:48

Superseded by re-review on the latest commit.

claude[bot]
claude Bot previously approved these changes Sep 4, 2026
Comment thread examples/direct/claude-generic.yml Outdated
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.
@claude
claude Bot dismissed their stale review September 4, 2026 14:53

Superseded by re-review on the latest commit.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review on the latest commit (f1b758ad1aacc5). This is sound to merge.

The only change since my last review is the single-line fix for the github.tokensecrets.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, the prompt_file verbatim-bypass branch in "Compose prompt" (including its early exit 0 and the text<<delim heredoc format), and the generic case in "Resolve tool permissions" (ALLOWED="", Write/Edit/NotebookEdit denied) are all consistent with the rest of the file's conventions and with the PR description's claims.
  • The actions/checkout SHA pinned in the new example (3d3c42e5aac5ba805825da76410c181273ba90b1) matches tag v7.0.1 on the upstream repo.
  • PROMPT_FILE isn'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 generic VERB case and no-ops when there's no PR/issue number, matching the example's post_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.

@Mearman
Mearman merged commit d174231 into main Sep 4, 2026
13 checks passed
@Mearman
Mearman deleted the feat/generic-mode branch September 4, 2026 14:54
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.2.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant