* checkout_pr: refuse unconditionally on dirty working tree
drop the live-HEAD comparison from the guard introduced in #796. any
checkout_pr call with staged or unstaged changes now throws, even when
HEAD is already on pr-N. no stashing, no idempotent escape hatch.
motivation is the zed-industries/cloud (2026-05-18) incident: shared-cwd
subagents make "carry edits along" semantics dangerous, and the
HEAD-equality predicate let a re-checkout silently inherit working-tree
state from a sibling agent. forcing commit/discard before any
PR-context operation eliminates the entire carry-forward failure class.
error names the PR number, lists dirty paths, and tells the agent to
commit/push/restore/clean before retrying.
* improve dirty-tree error: precise discard commands
copilot caught two sloppy bits in the error string:
- "push" alone does not clean a dirty tree (needs commit first)
- bare `git clean` is a no-op without `-fd`
reword to "commit (then push if needed), or discard with
`git restore --staged --worktree .` / `git clean -fd`" so the
guidance is actually actionable.
* checkout_pr: initial-branch invariant
setupGit captures `toolState.initialBranch` at run start via live
`git rev-parse --abbrev-ref HEAD`. checkout_pr refuses unless current
HEAD matches the run-entry branch or the target `pr-N` (idempotent
same-PR re-checkout). uses live rev-parse, not toolState.issueNumber
(poisonable per the PR #796 review).
refusal error names the current branch, target PR, recovery path
(`git checkout <initialBranch>` with the literal branch name), and
explicitly states routing around via the `git` tool is not sanctioned.
closes the zed-industries/cloud (2026-05-18) shape where a subagent
parked HEAD on someone else's `pr-X` and the orchestrator's next
checkout_pr inherited that position.
* reviewfrog: enforce canonical diff + pre-commit halt; align Build dispatch
extend REVIEWER_SYSTEM_PROMPT with two prepended HARD CONSTRAINTS:
- first action MUST be `git diff origin/<base>` (single-rev, captures
uncommitted). no other diff first; no checkout_pr; no alt-ref fetches;
no branch listing; no `gh pr list`.
- empty canonical diff + claimed-changes dispatch ⇒ reply exactly with
`no changes detected — likely pre-commit Build self-review;
orchestrator should commit then re-dispatch` and stop. do not guess
PR numbers (the zed thrash that ended in `checkout_pr({2582})`).
reshape Build mode reviewfrog dispatch step around a verbatim template
that names: (a) the situation is pre-commit, (b) canonical diff command,
(c) halt-on-empty-diff rule. orchestrator side now says the same thing
as the reviewer's baked-in prompt. delegation-discipline bullets and
orchestrator-evaluation guidance kept intact.
* checkout_pr: handle detached-HEAD entry in initial-branch invariant
pullfrog incremental review caught a defense-in-depth gap: `git
rev-parse --abbrev-ref HEAD` returns the sentinel string `"HEAD"` on
detached entry, which is the default `actions/checkout` state for
`pull_request` events. with the previous string-typed `initialBranch`,
both the captured value and the live probe would equal `"HEAD"` on
any detached state, trivially satisfying the invariant — including a
subagent doing `git checkout --detach <sha>`.
discriminate the captured HEAD: probe `git symbolic-ref --short HEAD`
first (works on named branches), fall back to `git rev-parse HEAD`
(SHA) on detached entry. store as
`{ kind: "branch"; name } | { kind: "detached"; sha }`. checkout_pr
runs the identical probe at call time and compares like-with-like
(branch name vs branch name, SHA vs SHA).
refusal error renders both heads via a small `describeHead` helper and
chooses the right `git checkout` recovery target (branch name or SHA).
no inline-discriminant `as` casts — uses a top-level `headsEqual` that
narrows via the discriminator.
Pullfrog is a GitHub bot that brings the full power of your favorite coding agents into GitHub. It's open source and powered by GitHub Actions.
Tag @pullfrog — Tag @pullfrog in a comment anywhere in your repo. It will pull in any relevant context using the action's internal MCP server and perform the appropriate task.
Prompt from the web — Trigger arbitrary tasks from the Pullfrog dashboard
Automated triggers — Configure Pullfrog to trigger agent runs in response to specific events. Each of these triggers can be associated with custom prompt instructions.
issue created
issue labeled
PR created
PR review created
PR review requested
and more...
Pullfrog is the bridge between your preferred coding agents and GitHub. Use it for:
🤖 Coding tasks — Tell @pullfrog to implement something and it'll spin up a PR. If CI fails, it'll read the logs and attempt a fix automatically. It'll automatically address any PR reviews too.
🔍 PR review — Coding agents are great at reviewing PRs. Using the "PR created" trigger, you can configure Pullfrog to auto-review new PRs.
🤙 Issue management — Via the "issue created" trigger, Pullfrog can automatically respond to common questions, create implementation plans, and link to related issues/PRs. Or (if you're feeling lucky) you can prompt it to immediately attempt a PR addressing new issues.
Literally whatever — Want to have the agent automatically add docs to all new PRs? Cut a new release with agent-written notes on every commit to main? Pullfrog lets you do it.
Standalone Usage
You can also use pullfrog/pullfrog as a step in your own workflows. The action exposes a result output that can be consumed by subsequent steps.
Example: Auto-generate release notes on new tags
name:Releaseon:push:tags:['v*']permissions:contents:writejobs:release:runs-on:ubuntu-lateststeps:- name:Checkoutuses:actions/checkout@v4with:fetch-depth:0- name:Generate release notesid:notesuses:pullfrog/pullfrog@v0with:prompt:| Generate release notes for ${{ github.ref_name }}.
Compare commits between this tag and the previous tag.
Format as markdown: summary paragraph, then ### Features, ### Fixes, ### Breaking Changes sections.
Omit empty sections. Be concise.env:ANTHROPIC_API_KEY:${{ secrets.ANTHROPIC_API_KEY }}# write to file to avoid shell escaping issues with special characters- name:Create GitHub releaserun:| notesfile="$RUNNER_TEMP/release-notes-$GITHUB_RUN_ID.md"
printf '%s' "$NOTES" > "$notesfile"
gh release create ${{ github.ref_name }} --title "${{ github.ref_name }}" --notes-file "$notesfile"env:GH_TOKEN:${{ github.token }}NOTES:${{ steps.notes.outputs.result }}
Example: Structured Output with Zod Schema
You can force the agent to return structured JSON output by providing a JSON schema. This allows you to reliably parse and use the agent's response in subsequent workflow steps.
You can define your JSON schema directly or uou can use any validation library that converts to JSON Schema. Here's an example using Zod:
name:Release Checkon:pull_request:types:[closed]jobs:check-release:if:github.event.pull_request.merged == trueruns-on:ubuntu-lateststeps:- uses:actions/checkout@v4- name:Install dependenciesrun:npm install --no-save --no-package-lock zod @actions/core- name:Generate Schemaid:schemarun:| node -e '
import { z } from "zod";
import { setOutput } from "@actions/core";
const schema = z.object({
version: z.string().describe("Semantic version number (e.g. 1.0.0)"),
isBreaking: z.boolean().describe("Whether this release contains breaking changes"),
changelog: z.array(z.string()).describe("List of changes in this release"),
});
setOutput("schema", JSON.stringify(z.toJSONSchema(schema)));
'- name:Analyze PRid:analysisuses:pullfrog/pullfrog@v0with:prompt:| Analyze this PR and determine semantic versioning impact.
Return a JSON object matching the provided schema.output_schema:${{ steps.schema.outputs.schema }}env:ANTHROPIC_API_KEY:${{ secrets.ANTHROPIC_API_KEY }}- name:Process Resultrun:| # Parse the JSON result using fromJSON()
echo "Version: ${{ fromJSON(steps.analysis.outputs.result).version }}"
echo "Breaking: ${{ fromJSON(steps.analysis.outputs.result).isBreaking }}"