← writing

Stop Putting Agents in CI

A job runner can retry a command. It cannot restore a session.

An engineer asked me for help with an agent workflow that maintained dependencies in a repository he owned.

The repository had a steady stream of code-scanning alerts. Nobody wanted to triage them by hand, so he built a nightly job that fetched the open alerts, handed them to a coding agent, and opened one pull request per fix.

It worked.

That wasn’t the workflow he had designed.

The original version started when a ticket changed state. It carried the ticket into the run, gave the agent the related context, and tied the resulting change back to the work that requested it. An external automation tool was supposed to connect the ticket system to GitHub Actions.

Secret management made that connection awkward enough that it was cut. The event became a schedule. The ticket disappeared. What shipped was the part that fit cleanly inside CI: one cron, one tool call, one pull request.

The engineer made a sensible trade. A useful nightly job beats an elegant diagram that never runs. I would have made the same call.

The interesting part is what the runtime forced him to leave behind.

The workflow did not fit through CI’s door

CI is a hotel room. It is clean when I arrive, contains the basics, and gets reset after I leave. That is exactly what I want when I need to compile a binary or run a test suite.

An agent workflow starts asking for a workshop. It needs tools laid out, half-finished work left on the bench, and a notebook that still exists when it comes back tomorrow.

The nightly security job fit the hotel room. Fetch a bounded list, attempt a patch, publish the result, leave. The original workflow crossed systems and needed context to survive between events. Each extra requirement made the room less suitable.

Teams usually respond by adding glue. A webhook starts a workflow. The workflow fetches a ticket. A script rebuilds context from comments. A second job checks whether the first opened a pull request. Soon the glue is carrying the state that the runner throws away.

At that point, the workflow exists despite CI’s execution model.

CI gives me one thing cloud platforms still don’t

The strongest argument for agents in CI is git.

The prompt, permissions, trigger, and tool configuration can live beside the code. A change gets reviewed. git blame can explain when the agent’s behavior changed. A revert is a normal pull request.

That is excellent governance, and managed agent platforms still handle it unevenly. Configuration often lives in a web interface with limited history and no ordinary code review. When an automation behaves differently on Tuesday, I want a commit, not a group chat asking who changed a text box.

GitHub Agentic Workflows pushes in the right direction by treating agent definitions like repository artifacts. Small, bounded jobs benefit from exactly that model.

CI also has mature permissions, logs, concurrency controls, and a place developers already inspect when work fails. Throwing all of that away for a new agent platform would be its own kind of platform-engineering hobby project.

The hotel has a front desk, receipts, and good locks. I still don’t want to store an unfinished motorcycle in room 412.

Every retry wakes up with amnesia

A hosted runner is usually a fresh machine. When the job ends, the workspace disappears.

For a one-pass task, that is fine. The runner clones the repository, installs dependencies, does the work, and exits. The clean-room property makes the result reproducible.

Longer agent work has a different shape. Read the alert. Inspect history. Form a hypothesis. Change the code. Run a test. Learn that the hypothesis was wrong. Try again.

If the runner dies after the test, CI knows how to repeat the job. It does not know how to restore the investigation. The replacement session can rebuild some context from commits and logs, but it has to infer which dead ends were already explored and why the current patch exists.

Retries also meet side effects. An agent may have pushed a branch, commented on a ticket, or opened a pull request before the failure. Running the job again can duplicate work unless every external action is made idempotent.

CI calls this a retry. The agent experiences it as waking up in a new hotel room with somebody else’s receipt in its pocket.

The glue became the workflow

Cross-system automation is where the mismatch gets expensive.

A ticket event starts the work. Source control holds the code. An alerting system has the evidence. Chat carries a human approval. CI has the runner. Each system owns one piece of state, and the agent needs a coherent view of all of them.

It is possible to assemble that view with webhooks, queues, scripts, and an external automation tool. Sometimes that is the right answer. The important thing is to admit what has been built: a small orchestration service whose job is to make an ephemeral runner look stateful.

The original dependency workflow lost its ticket context because one link in that chain could not carry credentials safely. Cron was less expressive and much easier to operate.

Nobody made a bad decision. Every component did the job it was designed to do. The awkwardness came from their boundaries, and those boundaries only became visible when the workflow needed memory.

A durable session changes what failure means

Managed agent runtimes such as Cursor’s Cloud Automations start from a different unit of work. The session can own its event history, tools, credentials, and workspace while the underlying compute changes.

Failure still happens. Its blast radius gets smaller.

If a sandbox dies, the platform can replace the sandbox without pretending the investigation never happened. If a tool call needs human approval, the session can wait. If a second event arrives, it can be attached to existing work instead of starting another blind run.

Anthropic describes a similar separation in its work on managed agents: model, tools, sandbox, and session do not have to share one lifetime. That separation is the useful idea. The session becomes the durable record. Compute becomes replaceable.

The workshop can lose power without throwing away the notebook.

A cloud runtime does not fix the agent

Durable sessions solve a runtime problem. They do not make the work correct.

The agent can still open a bad pull request. It can carry the wrong context for 3 days instead of 20 minutes. A broad credential is still broad. A vague prompt remains vague with better uptime.

Managed platforms also create a configuration problem. If prompts and triggers live outside the repository, teams can lose the review history that made CI attractive in the first place. I want the durable runtime and the boring governance: definitions in git, scoped credentials, visible event history, and a human boundary before consequential changes.

Review cost remains the final limit. A runtime can preserve an agent’s reasoning and keep its workspace warm. Somebody still has to understand the patch. Ten durable sessions producing plausible pull requests can overwhelm a team more efficiently than 10 flaky CI jobs.

This is where the answer gets less exciting. The platform is only part of the system.

I still put small agent jobs in CI

A bounded task with one trigger, one repository, and one pass can live happily in GitHub Actions. Review a pull request. Update a generated file. Classify a known set of alerts. Run a tool, publish the result, leave the room.

CI is good at those jobs. They gain versioned configuration, existing permissions, and familiar logs. Moving them to a dedicated runtime would add machinery without adding much capability.

I move the work when it needs to wait for a person, survive retries, coordinate across systems, or continue an investigation over multiple passes. Those are session requirements. Encoding them as scripts around an ephemeral job moves the state into places that are harder to see.

The nightly dependency job was useful. It also showed the limit perfectly. The cron version fit in CI because the context-rich version had been trimmed away.

If the work needs memory, give it somewhere that survives the run.