As I’ve grown frustrated with code review and spent more time using Amp, I’ve started to wonder whether the model for CI runners can be flipped around.
Today, getting a unit of work into main usually means moving it back and forth between two environments:
flowchart TB
accTitle: The current local development and remote CI loop
accDescr: Work repeatedly crosses between a local machine and fresh CI runners for duplicate testing, failure fixes, and review feedback before it can merge.
subgraph localBoundary["LOCAL"]
local["Human + agent develop<br/>Test · reproduce · revise"]
end
subgraph remoteBoundary["REMOTE"]
remote["CI validation · review"]
ready{"CI green and<br/>review complete?"}
remote --> ready
end
local -->|Push commit| remote
ready -.->|Failures + feedback| local
ready --> merge(("Merge to main"))
style localBoundary fill:transparent,stroke-dasharray:6 5
style remoteBoundary fill:transparent,stroke-dasharray:6 5
The transitions we have today create two expensive loops:
- Human ↔ agent boundary: CI posts a failure, a human asks an agent to interpret it, reviewers and agents post feedback, and a human asks another agent to implement the changes.
- Local ↔ remote boundary: the local environment runs the tests, CI provisions a clean machine to run them again, and both sides need enough of the other’s environment to reproduce failures.
We put effort into making local development and CI look the same so that when one runs into an issue, the other can replicate it. What if they were just the same machine?
The remote sandbox could become the long-lived unit of work: part development environment, part CI runner. Required workflows would run there and record their results against the exact commit SHA. Opening a review would grant read-only access to that same sandbox instead of shipping its state somewhere else to be reconstructed.
flowchart TB
accTitle: A persistent sandbox serving development, CI, and review
accDescr: Development and trusted workflows happen in one persistent remote sandbox. Reviewers inspect the diff and a live preview from that sandbox, then either send feedback back into it or approve the already verified SHA for merge.
subgraph sandbox["ONE PERSISTENT REMOTE SANDBOX · DEV ENVIRONMENT + CI RUNNER"]
work["DEVELOP IN PLACE<br/><br/>Human + agent work<br/>Context + processes stay alive"]
verify["VERIFY IN PLACE<br/><br/>Run required workflows<br/>Record the passing SHA"]
review["REVIEW THE SAME ENVIRONMENT<br/><br/>Inspect the diff + live app<br/>Read-only access"]
ready{"Ready?"}
work --> verify --> review --> ready
ready -.-> work
end
ready --> merge(("Merge to main"))
style sandbox fill:transparent,stroke-dasharray:6 5
This is still CI. The checks and merge gates do not disappear; their execution moves into the development loop. At merge time, the platform asks whether this exact SHA has a trusted passing result instead of provisioning another machine to prove it all over again.
There are a few ancillary benefits:
- A code review can include a running instance of the code. Reviewers can try the change instead of reasoning from the diff or pulling it locally. Setting up ephemeral preview environments is hard with the current model.
- Feedback returns to the environment that produced the change. The agent keeps its tools, logs, dependencies, and running processes instead of reconstructing context locally.
- One sandbox per stream of work replaces the annoying worktree flows that eat hundreds of gigabytes.
There’s obviously stuff to think through for this to work: workflow results need to be tamper-resistant, sandboxes need strong isolation, and the review surface needs to be read-only.
There is something here that feels different and magical. Amp is close, an Orb already makes a remote environment the center of a unit of work and there are multiplayer capabilities. The only thing missing is a code review mechanism built-in. Making development, verification, preview, and review different views into the same persistent environment feels like the endgame.