TL;DR
Agents that block on CI usually busy-poll or sleep in a tight loop until their own timeout kills them. Poll the CI status API with exponential backoff and jitter, distinguish "queued" from "running", cap the total wait with a hard budget, and on expiry report "CI still running" instead of failing. That keeps the agent cheap and honest.
Error
[agent log] waiting for CI... (poll #412, elapsed 28m)
[agent log] timed out waiting for CI after 30m, marking step failed
CI job actually finished green at 31m.
Steps
- Query the CI status API, not the web UI:
gh run view [RUN_ID] --json status,conclusion or the equivalent for your provider. Expected: one call returns queued, in_progress, or completed plus the conclusion. - Poll with backoff: start at 15s, double each round, cap at 120s, add jitter. Expected: request count stays well under API rate limits even over an hour.
- Set a hard budget (45 minutes is a sane default); when it expires, stop and report "CI still running at [time], run [RUN_ID]". Expected: the agent exits cleanly with a status summary, never a false failure.
- Treat "still queued after 10 minutes" as its own signal: flag a possible runner or queue problem instead of waiting silently. Expected: infra stalls get surfaced, not absorbed.
- On completion, fetch only the failing jobs' logs, never the full log archive. Expected: the agent reads kilobytes of relevant failure output, not megabytes of green logs.
When to use
- The agent blocks waiting for CI and risks its own timeout.
- CI polling shows up as hundreds of API calls in usage logs.
- The agent marks builds failed because CI was merely slow.
When not to use
- The CI job itself is slow because tests are slow (fix the suite, not the polling).
- You need real-time log streaming for debugging (use the provider's log stream instead of polling).
Tool compatibility
- Any coding agent (Claude Code, Cursor, etc.) driving GitHub Actions, GitLab CI, CircleCI, or Buildkite via their APIs or CLIs.
- Works with gh, glab, or plain HTTPS calls using your API key.
Variant phrasings
agent keeps asking CI "are we there yet"
The tight poll loop: fix with backoff and a budget so the agent asks less often and gives up gracefully.
CI check timed out on the agent side
The agent's own timeout fired before CI finished. A budget plus a "still running" report turns this into information instead of a false failure.
polling burned through the API rate limit
Too many status calls in a short window. Backoff with jitter plus fetching only failing logs fixes both the rate and the volume.
Why it happens
Agents default to the simplest loop: ask, sleep a fixed short interval, repeat, until a global timeout. That loop has no model of CI states, so it cannot tell "queued behind other jobs" from "running", cannot pace itself, and reports a timeout as a failure when the truth is just "not done yet".
Edge cases
- Matrix builds: poll the aggregate run status, then drill into individual jobs only when the aggregate completes.
- Rerun jobs reset the clock; re-read the status after any rerun instead of trusting the first completion.
- Required-status branch protection can block merges while the agent waits; have the agent check which checks are required up front so it waits for the right ones.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_yZREhN32iqgpo0KROem2fw