I moved the waiting out of my coding agent and into CI

My coding agent used to spend extra model turns checking whether tests and deployment had finished. I moved that post-edit work into GitHub Actions on a self-hosted runner. The authoring model now commits, emits CI_HANDOFF and stops.

9/9/2026

Writing the first version of this article with a coding agent took 47,290 tokens. In one long Codex session, a single later status check processed about 296,000 raw tokens. The useful edit had already been made; the extra tokens came from invoking the model again to handle asynchronous test and deployment status. I moved that post-edit work into CI.

What CI is, in one paragraph

CI stands for continuous integration: a server runs your tests and builds your project automatically whenever the code changes. On GitHub the mechanism is GitHub Actions. You push a commit or merge a pull request, GitHub matches the change against a workflow file in the repository, and a machine called a runner executes the commands listed in that file. Those commands are ordinary shell commands. No language model is invoked to start a job, to wait fifteen seconds, or to read back a status. When a runner polls an API for ten minutes, the cost is CPU time.

How this site is set up

rajeevg.com is a Next.js site deployed by Vercel. It has a workflow called Article local CI. The three parts do different jobs:

  • GitHub is the trigger and the status layer. It notices that a content/posts/** file changed, starts the workflow, and displays whether each job passed.
  • A self-hosted runner on my Mac does the compute. Installing dependencies, running the test suite, building the site and driving a browser all happen locally.
  • Vercel builds and serves the public site. CI does not deploy; it waits for Vercel and then checks the result.

There are two acceptance paths. On a pull request, CI installs dependencies, runs the broad test suite, builds, and proves the article renders in a real browser against the local build. After merge to main, CI does the same work and then waits for Vercel's deployment of that commit, waits for the live URL to serve the page, and runs the browser proof against production.

What the authoring agent does now

The agent that writes an article has a bounded job:

  1. Write or change the article file.
  2. Run only the targeted checks that inform the next edit, such as validating the MDX.
  3. Commit.
  4. Emit a marker in its final message: CI_HANDOFF.
  5. Stop.

CI_HANDOFF is a convention, not a product feature. It tells my orchestration layer that the model's turn is finished and everything after this point belongs to CI. The agent does not ask GitHub whether the workflow started, and it does not check Vercel.

The exact work that moved out of the model

After the handoff, all of this runs without a model call:

  • install locked dependencies with pnpm install --frozen-lockfile
  • run the broad Vitest regression suite
  • run the production build
  • poll GitHub every fifteen seconds until Vercel reports the deployment for that commit as successful, or fail after fifteen minutes
  • retry the live article URL until it serves the page
  • run the Playwright browser proof against the production URL
  • capture screenshots and upload them as a build artifact
  • record the job as green or red

These steps are deterministic. A normal runner can execute them without invoking a language model.

Why this saves tokens

The saving comes from avoiding model re-entry. If Codex checks an asynchronous job, the returned status has to be processed by the model. That model call includes the accumulated session context: instructions, files read, edits, tool results and previous turns. A small status update can therefore cause a large amount of context to be processed again.

CI changes that mechanism. GitHub Actions and the self-hosted runner poll status, run tests and inspect exit codes with ordinary programs. If everything succeeds, no model is called after CI_HANDOFF. The amount saved depends on how many model re-entries the old workflow would have caused and how large the session context had become.

What my session records show

I checked 632 Codex sessions recorded since 1 August 2026. Across them, I found 612 model responses whose only purpose was to process a wait result. Those wait-only responses averaged about 127,000 raw processed tokens each.

The cost rises as the session gets longer. In one clean GitHub Actions example late in a long session, four status-check model turns processed about 1.184 million raw tokens in total, or about 296,000 per check. The new CI path removes those successful status-check turns entirely.

For completeness, the underlying audit covered 20,632 tool calls, including 4,557 waits. The 612 wait-only responses processed about 77.75 million raw tokens in total. Most of that input was cached, so these figures describe context processing and quota use, not the equivalent number of freshly billed tokens.

Where the tokens went

Why a small status check can process a large context

Diagram showing the accumulated coding-agent context being processed again for four separate CI status checks. Each check processes about 296,000 raw tokens in the observed long session, totalling about 1.184 million raw processed tokens.
Four GitHub Actions status checks in one observed session processed about 1.184M raw tokens, mostly cached input. Source: AgentSessions audit of 632 Codex sessions since 1 Aug 2026; figure drawn 9 Sep 2026.

Download the editable diagram

That gives a useful estimate for a publication task. If the old publish/deploy tail would have caused three to five model re-entries, moving it into CI avoids roughly 380,000 to 635,000 raw processed tokens at the audit-wide average. In a long-context session like the observed four-check example, the same three to five avoided re-entries are roughly 890,000 to 1.48 million raw processed tokens.

Which tasks stopped needing a model

Work after handoffWhat CI doesRough saving if it avoids model re-entry
Broad tests and production buildRuns Vitest and next build, then reads the exit codesOne avoided result-check turn is about 127K raw tokens at the audit average, or about 296K in the observed long session
Vercel deployment wait and live-URL readinessPolls deployment status and the URL on fixed intervalsIf this removes 1–3 status-check turns, about 127K–381K at the audit average, or 296K–888K in a long session like the observed example
Production Playwright proof and artifact uploadRuns the browser proof and stores the evidenceOne avoided result-check turn is again roughly 127K average / 296K long-context

Those are estimates based on avoided model re-entries, not intrinsic token prices for Vitest, Vercel or Playwright. The important change is that successful post-handoff work now requires zero model turns.

Before and after

Before and after CI_HANDOFF

Diagram comparing the old and new publication flow. Before CI_HANDOFF, status results return to the coding model and cause more context processing. After CI_HANDOFF, GitHub Actions and the self-hosted Mac runner handle tests, build, Vercel status polling, live-URL checks, Playwright proof and artifact upload with zero successful post-handoff model turns.
Before CI_HANDOFF, status results can trigger more model calls. After CI_HANDOFF, the same deterministic work runs in GitHub Actions and on the self-hosted runner. Source: AgentSessions audit since 1 Aug 2026; figure drawn 9 Sep 2026.

Download the editable diagram

This article as the test case

The first version of this piece was written by a GPT-6 Astra worker at low reasoning. It finished in 2 minutes 56 seconds, used 47,290 tokens, committed, emitted CI_HANDOFF and stopped. It never polled GitHub and never looked at Vercel.

CI took it from there. The rewrite pull request run took 2 minutes 49 seconds. The production run after merge took 6 minutes 7 seconds: waiting for Vercel, running the broad suite and the build, then driving a browser over the published page and uploading the screenshots. The most recent proof artifact was about 3.28 MB.

An earlier production run also exposed a real CI bug. The workflow watched GitHub check-runs, while Vercel was publishing the deployment result as a commit status, so CI timed out even though deployment had succeeded. The workflow now checks both APIs. The failure appeared as a red job with logs; the authoring model did not need to stay active to detect it.

What this does and does not prove

This is not a controlled experiment. I did not run matched publishing tasks down the old and the new path and measure the difference, so I am not claiming a percentage saving. What is observable is the architecture: the writing model now stops before several minutes of installing, testing, building, deployment waiting and browser proof, and that work runs where waiting costs CPU seconds.

The metric I will watch is simple: for a successful change, model tokens spent after CI_HANDOFF should be zero. If CI fails, a repair worker can be started with the commit, failed job and relevant output. If CI succeeds, no further model call is needed.

This does not make CI a replacement for the coding agent. The agent still writes, reasons and runs targeted checks while editing. CI takes over the deterministic work that happens after the useful edit is complete.