New Signadot is now available on AWS Marketplace. Buy it through your AWS account.

Watch Claude Code Validate a Microservices Change in a Closed Loop

Two Claude Code sessions, the same microservices task. One ships a change that looks correct. The other uses signadot-validate to catch a cross-service break before calling the work done.

Author
Anirudh Ramanathan
Published
June 4, 2026
Updated
October 15, 2026
Reading time
9 min
Topics
Agents

Coding agents are good at writing code. They are not good at knowing whether that code is actually safe to ship. In a cloud-native system, those are two very different things.

The gap shows up the moment a change touches more than one service. An agent can make a change to a microservice, build it, and pass its unit tests, then declare the work done. But in a distributed system, correctness lives in the contracts between services, not inside any single one. A field rename that compiles cleanly and passes local tests can still break the service downstream that depends on the old shape.

To verify a change in a microservices application, agents need a realistic environment with the changed service running against its real dependencies. Spinning up the full stack for every agent iteration is slow and expensive, and mocks or unit tests can’t catch cross-service contract breaks by design. The agent ships what looks correct, and the break surfaces later in review, in CI, or in production. Across many agents at once, that gap is what the complete guide to software factories calls running open loop.

That open loop is the bottleneck for agentic development in cloud-native teams. A closed loop, also called a verification loop, means the agent runs its change against the real system, reads what happened, and fixes what broke before it reports the work done. Boris Cherny, who built Claude Code, calls it the most important tip for working with Claude: give it a way to verify its work, which he says gets two to three times more out of it.

Agents generate change faster than ever, but every unverified change becomes more work for the reviewers who have to catch what the agent didn’t. Closing the loop is what makes a coding agent trustworthy enough to hand real work to.

The demo: same task, two agents

To show the difference, we gave two Claude Code sessions the exact same task in our demo app, HotROD: change the location service’s response so the id field becomes a JSON string called locID, and rename name to id. HotROD is a ride-share application made up of four microservices plus persistence, which we extended with Kafka and MySQL. Both sessions ran Opus 4.7 at medium effort. The harness and prompts are on GitHub, so you can run the same comparison yourself.

The session on the left is standard Claude Code with no feedback loop. It can’t verify its change against a running environment. The session on the right uses Signadot with the signadot-validate skill, which provisions a lightweight ephemeral environment and guides the agent in validating its code against the actual cluster before calling the work done.

Standard Claude Code

No feedback loop

  • Edit the location service
  • Build and unit tests pass
  • Declares the work done

Claude Code + signadot-validate

Closed loop, validates against the cluster

  • Edit the location service
  • Build and unit tests pass
  • Ephemeral environment, real dependencies
  • Playwright e2e finds the break
  • Fix the front end, revalidate
Same model. Same prompt. Two outcomes.

Left: fast, and wrong

The left session made the change, built the Go code, ran the unit tests, and declared success. Build passes, tests pass, done. There was no feedback loop beyond that one service.

The change renamed two fields of the location service’s Location struct, the unit tests for that single microservice still passed, and the agent had no way to know it had just broken the contract the front end depends on. It completed a change to one service without accounting for the fact that the service is part of a larger stack.

Right: closing the loop

The right session made the same change and ran the same build, then paused to set up validation. With Signadot, only the service that changed runs locally in the session. The Signadot operator routes traffic to the rest of the services in the cluster, creating a realistic virtualized environment around the single changed service. All the other dependencies, including Kafka and the database, are the shared stable versions running in the cluster.

We asked the agent to use Playwright to test the change end-to-end, driving a real browser through the UI to confirm the user flow still works. It spun up the location microservice locally, confirmed with curl that the new response shape had taken effect, and drove the front end through the ephemeral environment with its routing key.

The validation surfaced a real downstream break. The front end’s Go code shares the location service’s Location struct, still in its old shape, so it could no longer decode the new response: GET /splash returned a 500 with json: cannot unmarshal string into Go struct field Location.id of type int64, and the page never got past Loading. The agent also found that the React UI matches locations by their old numeric id, so rebuilding the Go client alone would not fix it. The rename was not safe to propagate and not safe to ship. The agent gave us a clear choice: propagate the rename through to the React front end, or revert. The same change the left session had already declared correct.

Two Claude Code sessions side by side. The left session has finished and gone quiet after its build and tests passed. The right session reports a validation summary that surfaces the downstream break, with the root cause: the cluster frontend shares the location struct through the Go client, so the renamed fields no longer match.

We told it to make the corresponding front-end change and validate again. The agent mutated the environment to add the front end locally alongside the location microservice, with everything else still served from the cluster, and ran Playwright again. This time, the golden path passed end-to-end.

The right session made more changes than the left. It also shipped a change that actually works across the whole application, with contracts intact and end-to-end flows verified, all with minimal intervention. The left session was faster, but only because it stopped before finding out it was wrong.

Why this matters

The difference between the two sessions is not model quality. Both ran the same model and prompt at the same effort. The difference is that one agent could see the consequences of its change, and the other could not.

This is what Signadot gives coding agents in a cloud-native system: the ability to iterate against a production-like environment, catch cross-service breaks where they work, and deliver code that is correct across the full stack rather than correct in isolation. That’s the layer most agentic development stacks are still missing, and it’s what turns agent speed into output you can actually merge.

Because each environment duplicates only the services a change touches, many agents can run this loop at once on one cluster. Coding agent environments covers how that works for a whole team.

Run the comparison yourself

The harness behind this comparison is the closed-loop-comparison folder of the signadot/examples repository. It starts Claude Code in a Docker Sandbox, once on its own and once with Signadot, each with a fresh clone of HotROD, so both sessions begin from the same code.

You need:

  • The Docker Sandboxes CLI, sbx, installed and logged in, and git
  • For the Signadot session: a Signadot account and API key, and a Kubernetes cluster connected to your Signadot org with HotROD deployed (the quickstart installs it)

Start each session in its own terminal to watch them side by side:

git clone https://github.com/signadot/examples.git
cd examples/closed-loop-comparison

# Claude Code on its own
./sbx-run.sh --without-skill

# Claude Code with Signadot
export SIGNADOT_API_KEY=...
export SIGNADOT_ORG=my-org
export SIGNADOT_CLUSTER=my-cluster
./sbx-run.sh --with-skill

The Signadot session gets everything the closed loop needs, inside the sandbox:

  • The Signadot agent skills, signadot-validate among them
  • The Signadot CLI, logged in with your API key, and the Signadot MCP server registered with Claude Code
  • Playwright with Chromium and its MCP server, to drive the front end, and grpcurl, to call gRPC services
  • A session start hook that runs signadot local connect, so the session reaches the services in the cluster

Then give both sessions the same task. The prompts are in prompts/HOTROD.md, and the third is the rename from the video. The baseline session gets its first version, ending in “validate your work”. The Signadot session gets the second:

Make the location service's response return the id field as a JSON string called locID instead of a number, and rename name to id, and validate your work with /signadot-validate

The file has more tasks to compare: a fare estimate and ride history feature across three HotROD services, and three prompts for Google’s microservices-demo, which you run by passing its URL to --repo. Where a prompt has only one version, the Signadot session’s copy ends with “verify with /signadot-validate and playwright on the demo cluster”. To try it on your own services, point --repo at your repository and use a cluster where they run.

Try signadot-validate

The signadot-validate skill follows the open Agent Skills format, so it works with Claude Code, Cursor, Codex and the other coding agents that read it. It needs the Signadot CLI, configured against your cluster. Install it with the skills CLI:

npx skills add signadot/agent-skills --skill signadot-validate

Frequently asked questions

What is a closed loop for a coding agent?

A closed loop, also called a verification loop, is when a coding agent runs its change against the real system, reads the result and fixes what broke before it reports the work done. In an open loop the agent stops once its code builds and its unit tests pass, and anything it broke in another service surfaces later, in review, in CI or in production.

Is Claude Code a closed loop on its own?

Only for what it can run in its own terminal: it builds the code and runs the tests it finds. A change to one microservice can break another service the agent cannot run, so for cloud-native code the loop stays open. Signadot extends it to the whole application: through the signadot-validate skill, the Signadot CLI and the MCP server, Claude Code runs its change against the real services, queues and databases in a Kubernetes cluster.

Why did the unit tests miss the break?

They test the location service alone, and the location service still worked. The break was in the contract between services: the front end still decoded the old field names and types, so it failed on the new response. Only a run that sent requests through the front end to the changed service could show it.

Does the agent need its own copy of the whole application?

No. Only the changed service runs in the agent's session. Signadot routes requests that carry the environment's routing key to it, and every other service, Kafka and MySQL included, is the shared version already running in the cluster. When the fix touched the front end too, the agent added the front end to the same environment.

How can I run this comparison myself?

Clone the signadot/examples repository and run the sbx-run.sh script in its closed-loop-comparison folder twice, once without Signadot and once with it. Each run starts Claude Code in a Docker Sandbox with a fresh clone of HotROD, and the prompts are in prompts/HOTROD.md. The Signadot run needs an API key and a Kubernetes cluster with HotROD deployed.

Stay in the loop

Get the latest updates from Signadot