Imported from Cloudflare-Studio/ask-bonk (
AGENTS.md). Install upstream withnpx skills add Cloudflare-Studio/ask-bonk. Copyright stays with the author.
AGENTS.md
Last verified: 2026-07-03.
GitHub code review bot built on Cloudflare Workers, Flue, Hono, Durable Objects, and TypeScript. Use bun only.
Commands
bun install --frozen-lockfile # CI install; use after dependency changes to verify lockfile
bun install # update bun.lock after package.json changes
bun update # update dependencies within package.json ranges
bun run tsc --noEmit # typecheck Worker app
bun run test # Vitest in Workers pool; do not use `bun test`
bun run test -- test/index.spec.ts # focused test file
bun run lint # oxlint
bun run build # flue build --target cloudflare -> dist/ask_bonk
bunx wrangler types --check # verify worker-configuration.d.ts is current
bunx wrangler types # regenerate Worker bindings after wrangler/config changes
bunx wrangler deploy --dry-run --config dist/ask_bonk/wrangler.json --var BONK_VERSION:ci --var BONK_COMMIT:local
bun run dev # Flue local dev server
bun run cli # interactive installer/workflow CLI
Before considering a code change complete, run at least bun run tsc --noEmit, bun run test, and bun run lint. For Flue, Worker config, dependency, or deploy-path changes, also run bun run build, bunx wrangler types --check, and the generated-config dry-run deploy above.
When package.json changes, run bun install and commit package.json with bun.lock. CI uses bun install --frozen-lockfile.
Dependency Updates
- Use
bun updatefor routine dependency refreshes. Keep updates within the existingpackage.jsonranges unless the task explicitly asks for range or major-version changes. - Commit both
package.jsonandbun.lockwhenever resolved dependency versions change. Ifpackage.jsonwas edited manually, runbun installto refreshbun.lockbefore validation. - For dependency PR summaries, list the packages that changed, call out major/minor changes and any packages intentionally excluded, and note source or test fixes required by dependency API changes.
- Wrangler, Workerd,
@cloudflare/vitest-pool-workers, Flue, binding, migration, compatibility-date, andwrangler.jsoncchanges can all change generated Worker types. Runbunx wrangler typesafter these changes, commitworker-configuration.d.tswhen it changes, then runbunx wrangler types --check. - Treat
worker-configuration.d.tsheader-only runtime changes as real generated output. Recent Wrangler updates have failed checks until the generatedworkerd@...version in this file was refreshed. - Dependency update PRs must pass
bun install --frozen-lockfile,bun run tsc --noEmit,bun run test,bun run lint,bun run build,bunx wrangler types --check, and the generated-config dry-run deploy command before they are complete.
Architecture
src/index.tsis the Wrangler entrypoint shim: it exports the default app andRepoAgentonly.src/app.tsowns the Hono app, non-Flue HTTP routes, auth endpoints,/stats, the legacy/webhooksroute, andhandleGitHubDelivery().src/channels/github.tsexports the Flue GitHub channel. The canonical webhook route is generated by Flue at/channels/github/webhook.src/workflows/github-setup.ts,src/workflows/github-track.ts, andsrc/workflows/github-finalize.tsare internal Flue workflows backing the OIDC-protected/api/github/*compatibility routes. They run through the Cloudflare Flue target and generated workflow Durable Objects.src/github-workflow-jobs.tsowns the shared setup, track, and finalize job logic used by those workflows.src/cloudflare.tsexports Cloudflare entrypoints for Flue discovery. Keep it in sync with exported Durable Object classes.src/agent.tsdefinesRepoAgent, the Durable Object that tracks workflow runs and posts/edit failure comments.github/action.ymlandgithub/script/*.tsare the composite action that runs OpenCode inside GitHub Actions. The Worker does not run OpenCode itself.cli/is the interactive installer/workflow generator. It usesghCLI helpers and Handlebars templates.ae_queries/SQL files are imported by Wrangler text rules for/statsAnalytics Engine endpoints.
Webhooks And Flue
- Keep both webhook paths working:
/channels/github/webhookis canonical Flue,/webhooksis legacy GitHub App compatibility. - Do not replace
/webhookswith a redirect. GitHub sends signed POST bodies; signature verification must see the exact body. - The legacy
/webhookshandler should usecreateGitHubChannelwithGITHUB_WEBHOOK_SECRETand then call the samehandleGitHubDelivery()path. - If the Flue channel cannot read
GITHUB_WEBHOOK_SECRETat module init, it uses an unguessable fallback so the generated route fails closed. Do not reintroduce a public fallback secret. /ask,Sandbox, and the containerDockerfilewere removed. Only keep historicalSandboxmentions in Durable Object migrations (v4create,v6delete).
Auth And GitHub API
- All
/api/github/*endpoints must follow:extractBearerToken()->validateOIDCAndExtractRepo()-> compare OIDCowner/repoclaims with request bodyowner/repo-> proceed. - The
/api/github/setup,POST /api/github/track, andPUT /api/github/trackhandlers must keep the OIDC checks above before admitting internal Flue workflows. The workflow routes themselves are internal-only and guarded by an unguessable in-process header fromsrc/internal-workflows.ts. - Cross-repo token exchange must keep all three checks: same org, public-to-private visibility block, and actor write access.
- PAT exchange remains disabled unless
ENABLE_PAT_EXCHANGEis set. - Use
createOctokit()/createOctokitForRepo()fromsrc/github.tsandsrc/oidc.ts; installation IDs are cached inAPP_INSTALLATIONSand stale 404 cache entries are retried via API lookup.
RepoAgent Durable Object
- Durable Object name format is
{owner}/{repo}. Persistownerandrepoin state; alarm wakeups may not havethis.nameavailable. - There are three finalization paths: action-driven
PUT /api/github/track, DO alarm polling, andworkflow_run.completedwebhook safety net. RepoAgentstill owns external GitHub Actions run state. Do not remove it just because setup/track/finalize are Flue workflows; OpenCode still runs in GitHub Actions, so Bonk needs cross-request active-run state, alarm polling, and failure-comment edit history outside Flue workflow run records.- Reevaluate moving or reducing
RepoAgentonly when Bonk can run OpenCode inside a Flue-managed isolated sandbox and use Flue workflow run state as the primary execution record. workflow_run.completedmust only post comments for tracked runs. Untracked workflow runs are metrics-only to avoid failure-comment spam.this.schedule()calls must stay wrapped intry/catch; the workflow_run webhook is the backup if scheduling fails.- Failure comments are edited in place by context key (
i:{issueNumber}orrc:{reviewCommentId}); preserve the create/edit fallback behavior.
GitHub Action Pitfalls
- Composite action steps do not share environment variables unless values are written to
GITHUB_ENV. Outputs requirecore.setOutput()andsteps.<id>.outputs.*. finalize.tsmust never callcore.setFailed(). It runs underif: always()and must not mask the real OpenCode failure.- GitHub reports downstream skipped steps as
skipped, notfailure; keep the client-side and server-side remapping/treatment as failure. actions/checkoutpersistsGITHUB_TOKENinhttp.https://github.com/.extraheader. The action must replace it with the App installation token so Bonk pushes trigger CI.- Multiline
GITHUB_ENVand step output writes use randomBONK_<uuid>delimiters to avoid injection.
Error Handling And Logging
- Use
Resultfrombetter-resultat API boundaries and domainTaggedErrorclasses fromsrc/errors.ts. - Every
Result.tryPromiseneeds a typedcatchmapper. Do not allowunknownexceptions to leak through result types. - Log through
src/log.ts; never use rawconsole.log/info/errorin app code. - Use
errorWithException()for exception logging because it sanitizes secrets. Git errors can contain tokenized remote URLs. - Log event names are
snake_case; include useful context such asrequest_id,owner,repo,issue_number,run_id,actor, andduration_mswhen available.
Tests And Config
- Tests run through Vitest 4 with
cloudflareTest()from@cloudflare/vitest-pool-workers; do not import the removed@cloudflare/vitest-pool-workers/configpath. - Tests should exercise real parsing, validation, request handlers, fixtures, and API boundaries. Avoid tests that only verify mocked structures.
wrangler.jsoncis the source Worker config.bun run buildwrites the deployable Flue artifact todist/ask_bonk/wrangler.json.worker-configuration.d.tsis generated. Regenerate it after Wrangler, binding, migration, compatibility date, or config changes.- Prefer JSONC for config files unless a tool requires strict JSON.
Code Style
- Keep related code together; avoid new helpers/files until reuse or composition is real.
- Use type-only imports for types and group imports as external packages first, then local modules.
- External API code belongs in its domain file (
github.ts,oidc.ts,workflow.ts, etc.). - Comments should explain why, especially at I/O, external orchestration, and stateful boundaries. Skip comments that restate simple code.
- Cloudflare Worker code must use Workers-compatible APIs. Do not add Node-only
fs,path, orchild_processusage tosrc/.