* mcp: embed example calls in top-level tool descriptions
agents (esp. claude sonnet) hallucinate param names from training-data
priors — `pr_number` instead of `pull_number`, `summary` instead of
`body`, full subcommand strings jammed into `git({command})` like it
were `shell({command})`. each error burns a tool round-trip plus a
follow-up ToolSearch, ~40+ events / 24h, no observable recovery cost
to us but visible to users in agent logs.
cheapest fix: add a sample formatted function call to every affected
tool's top-level description. example anchors are more reliable than
schema descriptions alone because the model treats descriptions as
narrative but call examples as canonical structure. for `git` and
`shell` (whose `command` fields collide), include explicit
counter-examples disambiguating which tool owns which shape.
no schema aliases / coercion yet — try the cheap thing first; if the
next audit window still shows the same hallucination rate, layer
aliases on top per #585's recommendation.
closes#585, closes#701
* mcp: drop negative anchors from tool descriptions
negation is a footgun in tool descriptions — telling the model "NOT
pr_number" makes pr_number more salient, not less. let the positive
example carry the schema and trust the model to read it.
removes:
- "the parameter is pull_number (a number), NOT pr_number" and
similar across checkout_pr, get_pull_request, list_pull_request_reviews,
get_review_comments, create_pull_request_review
- "NOT summary, message, or content" on report_progress
- "WRONG: git({ command: 'log --oneline' })" counter-example on git
- redundant param-type restatements after the example (e.g. "depth is a
number, not a string" on git_fetch, "description is required" on shell)
keeps a single positive example per tool. for tools with multiple call
shapes (git, git_fetch, push_branch), two positive examples instead of
one + a counter-example.
makes debugging easier by emitting a single `» <verb> <kind> <id>` line
after every successful GitHub write (and upload) the agent performs via
the Pullfrog MCP, mirroring the chevron convention used elsewhere.
`mcp/checkout.test.ts` and `mcp/reviewComments.test.ts` previously hit
live GitHub on every run via `acquireNewToken()`, requiring `GH_TOKEN`
or `GITHUB_APP_ID` + `GITHUB_PRIVATE_KEY` in the env. that made them:
- cred-gated — the action runtime filters `_KEY$` / `_TOKEN$` from
subprocess env, so the husky pre-push hook (which runs
`pnpm -r test`) blocked Pullfrog agents from pushing branches. issues
#562, #563, #564, #566 all hit this exact blocker and never got their
fixes pushed.
- non-deterministic and slow (network round-trips for a snapshot test).
both tests are really snapshot tests of pure formatters
(`formatFilesWithLineNumbers`, plus `parseFilePatches` /
`buildThreadBlocks` / `formatReviewThreads` for review data). the live
fetches were just an inefficient way to obtain fixtures.
changes:
1. extract a pure `formatReviewData({ review, threads, prFiles, ... })`
from `getReviewData` in `mcp/reviewComments.ts`. `getReviewData`
becomes thin orchestration: fetch + call formatter. preserves the
"skip listFiles when no threads" perf optimization.
2. add `action/mcp/__fixtures__/` with checked-in JSON captures for the
three fixture test cases (pullfrog/test-repo#1 listFiles,
pullfrog/scratch#49 review 3485940013, pullfrog/scratch#64 review
3531000326). ~14KB total. fixtures store only the fields the
formatter reads — volatile fields (sha, blob_url, etc.) are dropped.
3. rewrite both test files to load the fixtures and call the pure
formatters directly. snapshot keys updated; snapshot content
unchanged (verified by running existing snapshots against the
refactored tests).
4. add `action/scripts/refresh-test-fixtures.ts` to re-fetch the
fixtures from live GitHub on demand:
`node action/scripts/refresh-test-fixtures.ts` (with creds in
`.env` or env). re-run when the GitHub API response shape changes
and review the snapshot diff.
trade-off: a silent change to GitHub's `pulls.listFiles` /
`pulls.getReview` / GraphQL `reviewThreads` response shape would no
longer break this test on every push. that tradeoff is worth it: shape
drift on those endpoints is rare (years between changes), and a
dedicated cron that runs the refresh script and opens a PR on diff is
a far better signal than a flaky cred-gated pre-push hook.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Update waitlist, run ralph experiments
* fix PR files pagination: use octokit.paginate() for >100 files
* fix garbled FAQ answer on landing page
* track cache read/write tokens in OpenCode agent usage
* wrap dispatch() calls in try/catch to prevent webhook retries on transient failures
* replace raw error messages with generic responses in API routes
* guard request.json() calls with try-catch returning 400 on malformed bodies
* log warning when GraphQL review thread/comment counts hit pagination limits
* reduce review comment cache TTL from 24 hours to 10 minutes
* use select instead of include for proxyKey in workflow run queries
* align Claude agent activity timeout to 5 minutes to match OpenCode agent
* add in-memory dedup for PR close webhooks to prevent duplicate indexing
* extract isPullfrogLogin() helper for shared Pullfrog detection logic
* check response.ok on log fetch in checkSuite.ts
* add 10s timeouts to checkSuite API calls and log fetch
* parallelize proxy key usage API calls with Promise.allSettled
* fix three typos on landing page: colleage, dectects, reponse
* move MAX_STDERR_LINES constant to shared.ts
* add indexes on Repo.accountId and PFUser.accountId FK columns
* remove unused Permission enum from Prisma schema
* populate author and keywords in action/package.json
* use crypto.timingSafeEqual for all secret comparisons
* add missing env vars to globals.ts: R2, webhook, and API secrets
* remove commented-out UserRepo model from Prisma schema
* replace console.log/error with log utility in production API routes
* replace catch(error: any) with proper type guards in getUserRole
* remove stale TODO comment on console page
* handle repository_transferred webhook to update owner
* show toast.error instead of console.error on mode/workflow mutation failures
* add Space key handler for keyboard navigation on workflow run links
* replace role=link spans with button elements for proper accessibility
* add root 404 page with Pullfrog branding
* update ISSUES.md: mark completed items
* mark remaining low-priority UX items as addressed
* add error logging alongside toasts, add check script, update ralph commands
* address review feedback: squash migrations, fix try/catch scope, wire up globals consumers
- squash drop_permission_enum migration into add_indexes migration (one migration per PR)
- move getPullRequest() outside try/catch in mention handler so errors aren't mislogged as "dispatch failed"
- restore key ID in proxyKeys.ts Promise.allSettled error log
- remove accidental asdf.txt and ralph.md files
- wire up globals.ts exports to consumers (r2-uploads, r2-private, verifyHookdeckSignature, sync-usage, forwardPreviewWebhook, dispatch-workflow)
Made-with: Cursor
* update model snapshot (qwen3.6-plus-preview renamed to qwen3.6-plus)
Made-with: Cursor
* Standardize on top-level `triggerer` property
- Rename `triggeringUser` → `triggerer` as the single top-level payload property
- Remove redundant `triggerer` from `FixReviewEvent`, add `approvedOnly` boolean
- Auto-apply `approved_by` filtering in `get_review_comments` when `approvedOnly` is set
- Auto-assign created PRs to the triggerer
- Simplify `AddressReviews` mode prompt
- Accept both `triggerer` and `triggeringUser` in schema for backward compat
* Address review feedback: simplify approved_only, remove addAssignees, drop approved_by param
* Fix formatting in `action/mcp/pr.ts`
* re-add triggeringUser backward-compat fallback in payload schema
* auto-assign created PRs to the triggerer
* Revert "auto-assign created PRs to the triggerer"
This reverts commit c088c425fea33793eb299a001ffd253798d2c674.
* Revert "re-add triggeringUser backward-compat fallback in payload schema"
This reverts commit ae5b3cb3f1377cd4a634b2d48962c785c31013f3.
* backend compat
* tweak prompt to ensure compat
* Address review feedback
* chore: remove triggeringUser fallback
---------
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
* Add "Fix it" link for body-only PR reviews
When a PR review has only body-level feedback (no inline comments),
the footer now includes a "Fix it" link that triggers the fix flow.
Also fetches the review body in the fix action's prompt so the agent
can address body-level feedback even when there are no inline comments.
* Move review body fetching into `get_review_comments` tool
Instead of fetching the review body in the trigger page and appending
it to the prompt, the `get_review_comments` MCP tool now fetches the
review body via the GitHub API and includes it in its markdown output
under a "Review Body" section. This keeps the trigger page simple and
lets the tool provide all review context in one place.
* fetch body early
* get reviewer from a better place
* cleanup structure to reuse more in test
* simplify
* simplify
* typecheck
* fetch review body via REST API; skip listFiles for body-only reviews
* update snapshot
* formatting
* cleanup
* fix line counting with `countNewlines` utility using `indexOf` loop
* rename `countNewlines` to `countLines` with 1-based line counting
* suppress biome lint warning for assignment in while condition
* remove unused `body` field from GraphQL review query and type
* add `approved` parameter to `create_pull_request_review` and skip fix links for approvals
* vibe instructions
* tighten up prompting
---------
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
* Stop using command-based logs for warnings and errors
Co-authored-by: Cursor <cursoragent@cursor.com>
* revert
* tweak
* de-noise
* Remove redundant ts() timestamp prefix from log calls
* Restore timestamped logging and refine debug output routing.
Bring back timestamp prefixes for standard logs and make log.debug emit via core.debug when runner debug is enabled, while still surfacing debug lines for --debug runs.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
* refactor get_review_comments to use reviewThreads graphql api with full thread context and proper diff extraction
* Improve get_review_comments output
* Improve tests and diffs
* GH_TOKEN
* Added back approved_by
* Fix CI