feat(web): a coding agent watches its pull request's CI with gh and fixes what fails, where the installation grants the App the read

Merged
DA
8d ago
+300-66

Do not merge or enqueue: Dean reviews this one first.

What

Coding agents watch their own pull request's CI in the same turn with the gh CLI already authenticated at their sandbox's firewall, and fix what fails. No server watcher, no webhooks, no new state, no migration.

  • The write token asks for the CI read only where it is granted. Dean added Actions: read, Checks: read, Commit statuses: read to the App; each installation still has to approve them, and a mint naming a permission the installation never granted fails whole. So github-app.ts reads each installation's permissions off the /user/installations listing the mint already reads (no new request), and repositoryWriteToken adds checks, statuses, and actions read beside contents and pull requests write only where the installation grants all three (CI_READ_PERMISSIONS); otherwise it mints exactly as today. Planning's read token is unchanged.
  • The agent is told whether CI is readable through the seam that already composes its instructions: host.prompt now reads repositoryCiReadable (the same reach check, as far as the installation) and composes the instructions on it. A GitHub read that fails at session start is logged and reads as not readable, so the session still starts; the checkout refuses on its own terms when the sandbox opens. What the prompt said is kept in the session's prompt state beside its hash, so a step's context estimate composes the same text again.
  • Instructions (coder-host/instructions.ts), one step after "open a pull request": where readable, watch with gh pr checks <n> --watch --fail-fast, check back on the backgrounded command rather than polling, read a failure with gh run view <run-id> --log-failed, fix, push, and watch again for at most CODER.CI_FIX_ROUNDS (3, in bounds.ts) rounds; stop when every check passes or the repository runs no checks; say plainly when it stopped with a check failing; never mark the PR ready, merge, or close it. Where not readable: do not try, and say CI was not watched.

Tests

  • github-app.test.ts: the write mint names the three CI permissions for an installation that grants them and exactly today's body for one that does not, and repositoryCiReadable answers each; through the App's public seam over the existing GitHub HTTP fake, which now carries an installation's permissions.
  • coder-host.test.ts: host.prompt says CI is readable for a granting installation, not for a withholding one (different hashes), and not where GitHub cannot be read.
  • coder-agent.test.ts: the instructions name gh pr checks, the round count from CODER.CI_FIX_ROUNDS, and the never-merge rule where readable, and "CI was not watched" where not, in the shape of the existing instructions tests.

Verification

./scripts/check.sh exits 0 locally. CI could not verify the Mac; this PR changes no desktop or UI code, so there is no component to screenshot and no verify.sh evidence to attach (Dean waived verify.sh for this work).

šŸ¤– Generated with Claude Code


Open workspace in Conductor


Devin Review