Building Reliable Background Coding Agents with Verification Loops

spotify · Media & Entertainment · 2025 · source Agentic: yes · promotional bias: low · source-backed · extracted with prompt 0.5.5 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: Background coding agents for large-scale software maintenance

Spotify needed background coding agents to make automated code changes across thousands of software components without direct human supervision while avoiding PRs that fail CI or, worse, pass CI while being functionally wrong.

Constraints:

Architecture

Spotify's Honk background coding agent is intentionally narrow: it receives a prompt, sees the relevant codebase, edits files, and invokes verifiers as tools. Surrounding infrastructure handles prompt authoring, Slack interactions, pushing code, and other orchestration. The core reliability mechanism is a verification loop exposed through MCP: independent verifiers activate automatically based on component contents, such as a Maven verifier when a root pom.xml exists, and return concise feedback so the agent can iterate before opening a PR. All relevant verifiers also run before PR creation through a Claude Code stop hook. After deterministic formatting/build/test verifiers pass, an LLM judge compares the proposed diff with the original prompt to veto out-of-scope changes. The agent runs in a highly sandboxed container with limited permissions, few binaries, and little access to surrounding systems.

Diagram confidence: explicit (topology described by the source).

flowchart LR
  surrounding-infrastructure[Surrounding infrastructure] --> background-coding-agent[Background coding agent]
  background-coding-agent --> relevant-codebase[Relevant codebase]
  relevant-codebase --> verifier-activation[Verifier activation]
  verifier-activation --> independent-verifiers[Independent verifiers]
  background-coding-agent --> mcp-verifier-tool[MCP verifier tool]
  mcp-verifier-tool --> independent-verifiers
  independent-verifiers --> stop-hook-gate[Stop hook gate]
  stop-hook-gate --> pull-request-flow[Pull request flow]
  independent-verifiers --> llm-judge[LLM judge]
  llm-judge --> pull-request-flow
  surrounding-infrastructure --> pull-request-flow
  background-coding-agent --> sandboxed-runtime[Sandboxed runtime]
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
Surrounding infrastructure Manages prompt authoring, Slack interaction, pushing code, and other tasks outside the agent. Background coding agent, Pull request flow
Background coding agent Takes a prompt, edits code in the relevant codebase, and calls verification tools. Surrounding infrastructure, Relevant codebase, MCP verifier tool, Sandboxed runtime
Relevant codebase The component being modified by the background agent. Background coding agent, Verifier activation
Verifier activation Detects component contents and automatically selects independent verifiers such as Maven. Relevant codebase, Independent verifiers
MCP verifier tool Unified agent-facing tool abstraction that hides individual verifier implementations. Background coding agent, Independent verifiers
Independent verifiers Formatting, building, testing, and component-specific checks that return concise success or failure feedback. Verifier activation, MCP verifier tool, Stop hook gate, LLM judge
Stop hook gate Runs all relevant verifiers before PR creation and blocks the PR when any verifier fails. Independent verifiers, Pull request flow
LLM judge Evaluates the proposed diff against the original prompt after deterministic verifiers pass. Independent verifiers, Pull request flow
Pull request flow Creates a PR only after the verifier loop and judge allow the change. Surrounding infrastructure, Stop hook gate, LLM judge
Sandboxed runtime Container with limited permissions, few binaries, and little access to surrounding systems. Background coding agent

Data flow

Surrounding infrastructure sends a scoped code-change prompt to the background coding agent. The agent edits the relevant codebase and calls an MCP verifier tool without needing to know individual verifier internals. Component contents activate independent verifiers, which run formatting, build, and test checks and return concise feedback. Before a PR opens, all relevant verifiers run again through a stop hook; failures block the PR and surface an error. If deterministic verifiers pass, the LLM judge receives the proposed diff and original prompt, vetoing changes that drift outside the request. Only changes that survive those loops reach the pull request flow.

4 supporting quotes
“The verification loop allows the agent and its underlying LLM to gradually confirm it is on the right track before committing to a change.”article, stated
“An individual verifier is not exposed directly to the agent; instead, it activates automatically depending on the software component contents.”article, stated
“This verification loop can be triggered as a tool call, but our agent also runs all relevant verifiers before attempting to open a PR.”article, stated
“It uses the diff of the proposed change and the original prompt, and sends them to an LLM for evaluation. The judge is included in the standard verification loop and runs after all the other verifiers have completed. ![Coding agents_part 3_image”article, stated

Why this architecture

Spotify designed for predictability because functionally incorrect PRs that pass CI are hard to catch across thousands of components and can break production. The verification abstraction gives the agent feedback without forcing it to understand build systems or parse noisy test output. The LLM judge exists because deterministic tests cannot detect all out-of-scope refactors or disabled flaky tests. The agent is kept narrow and sandboxed so surrounding infrastructure, not the model, owns higher-risk operations.

5 supporting quotes
“When performing changes over thousands of components, these changes are hard to spot in reviews. If these PRs get merged, they could break functionality in production. The second and third failure modes can happen for a few reasons: The target component has”article, stated
“modes can also be large time sinks for engineers; reviewing nonsensical PRs is expensive. To mitigate this, we had to design for predictability from the ground up. ## Designing for predictability: verification loops We address this challenge by implementing strong verification loops”article, stated
“they allow the agent to get incremental feedback, guiding it toward the correct solution. They also abstract away much of the noise and decision-making that would otherwise consume the agent’s precious context window. For example, the agent doesn’t need to”article, stated
“We found this necessary because some agents were a bit too “ambitious”, trying to solve problems that weren’t strictly in their prompt”article, stated
“by surrounding infrastructure. This is intentional, we believe that the reduced flexibility of the agent makes it more predictable. It also has secondary positive effects for security. The agent runs in a container with limited permissions, few binaries, and virtually no access to surrounding”article, stated

Models used: Underlying LLM for the background coding agent · LLM judge for diff-versus-prompt evaluation · Claude Code stop hook integration

Scale

Alternatives considered (roads not taken)

Expose each verifier implementation directly to the agent

Rejected because: Spotify hides verifier details behind an MCP abstraction so the agent only knows it can or must call verification tools.

“the agent doesn’t know what the verification does and how, it just knows that it can (and in certain cases must) call it”article, stated
“Note the abstraction on the MCP level. The agent is unaware of the underlying Maven verifier. ![Coding agents_part 3_image”article, stated

Rely only on deterministic formatting, build, and test verifiers

Rejected because: Deterministic checks can pass even when an agent goes outside prompt scope by refactoring or disabling flaky tests.

“On top of these deterministic verifiers, we added another layer of protection: an LLM as a judge. We found this necessary because some agents were a bit too “ambitious”, trying to solve problems that weren’t strictly in their prompt, like refactoring code or”article, stated
“trying to solve problems that weren’t strictly in their prompt, like refactoring code or disabling flaky tests.”article, stated

Let the coding agent own all surrounding workflow tasks

Rejected because: Spotify deliberately keeps pushing code, Slack interaction, and prompt authoring outside the agent to reduce flexibility and improve predictability.

“Pushing code, interacting with users on Slack, and even the authoring of prompts are all managed by surrounding infrastructure.”article, stated
“prompts are all managed by surrounding infrastructure. This is intentional, we believe that the reduced flexibility of the agent makes it more predictable. It also has secondary positive effects for security. The agent runs in a container with limited permissions, few binaries,”article, stated

Open PRs before the full verifier loop runs

Rejected because: A stop hook blocks PR creation when any relevant verifier fails, reducing review noise and half-broken PRs.

“If one of the verifiers fails, the PR isn’t opened and the user is presented with an error message. These verifiers that invoke formatting, building, and testing make sure our agent produces syntactically correct code that builds and passes tests. ## Using”article, stated

Patterns

eval-driven-development (quality)

Spotify routes every proposed change through deterministic verifiers and plans structured evals for system prompts, architectures, and providers.

“These verifiers that invoke formatting, building, and testing make sure our agent produces syntactically correct code that builds and passes tests.”article, stated
“Implementing robust evals will allow us to systematically assess changes to system prompts, experiment with new agent architectures, and benchmark different LLM providers”article, stated

llm-as-judge (verification)

An LLM judge evaluates proposed diffs against the original prompt after deterministic verifiers pass, vetoing out-of-scope changes.

“On top of these deterministic verifiers, we added another layer of protection: an LLM as a judge.”article, stated
“The judge is included in the standard verification loop and runs after all the other verifiers have completed.”article, stated

tool-use-orchestration (architecture)

Verifiers are exposed as a single MCP tool abstraction, while individual checks activate automatically from component contents.

“The verification loop consists of one or more independent verifiers.”article, stated
“For example, a Maven verifier activates if it finds a pom.xml file in the root of the codebase.”article, stated

context-compaction (context)

Verifiers parse noisy build and test output, returning only relevant errors or short success messages so the agent's context window is not consumed by raw logs.

“They also abstract away much of the noise and decision-making that would otherwise consume the agent’s precious context window.”article, stated
“many of our verifiers use regular expressions to extract only the most relevant error messages on failure and return a very short success message otherwise.”article, stated

guardrails-io-filtering (safety)

The stop hook and judge gate prevent failed verification or out-of-scope changes from becoming PRs.

“If one of the verifiers fails, the PR isn’t opened and the user is presented with an error message.”article, stated
“However, we know from internal metrics that out of thousands of agent sessions, the judge vetoes about a quarter of them. When that happens, the agent is able to course correct half the time.”article, stated

safety-policy-enforcement (security)

The agent is sandboxed with limited permissions, few binaries, and little access to surrounding systems.

“The agent runs in a container with limited permissions, few binaries, and virtually no access to surrounding systems.”article, stated
“It's highly sandboxed. With verifiers and a Judge to guide them, we've found that our agents can solve increasingly complex tasks with a high degree of reliability.”article, stated

Tradeoffs

Keep the background agent narrowly scoped

Chose An agent that takes a prompt, edits code, and calls verifiers over An agent that also manages pushing code, Slack interaction, and prompt authoring.

Rationale: Reduced flexibility improves predictability and security.

“By design, our background coding agent is built to do one thing: take a prompt and perform a code change to the best of its ability.”article, stated
“This is intentional, we believe that the reduced flexibility of the agent makes it more predictable.”article, stated

Hide verifier internals behind MCP

Chose A unified verifier tool abstraction over Teaching the agent each individual verifier and build system.

Rationale: The abstraction reduces context burden and lets component contents choose the right verifier automatically.

“An individual verifier is not exposed directly to the agent; instead, it activates automatically depending on the software component contents.”article, stated
“the agent doesn’t need to understand the specifics of calling different build systems or parsing complex output from tests”article, stated

Run deterministic verifiers before the LLM judge

Chose Judge only after formatting, build, and test checks complete over Asking the judge to evaluate syntactically broken or untested code.

Rationale: The judge can focus on prompt adherence and out-of-scope behavior once lower-level correctness has been checked.

“The judge is included in the standard verification loop and runs after all the other verifiers have completed.”article, stated
“These verifiers that invoke formatting, building, and testing make sure our agent produces syntactically correct code that builds and passes tests.”article, stated

Block PR creation on verifier failure

Chose Stop-hook gate before PR opening over Creating PRs and letting humans discover verifier failures later.

Rationale: Blocking failed changes avoids noisy half-broken PRs and protects reviewer time.

“our agent also runs all relevant verifiers before attempting to open a PR.”article, stated
“If one of the verifiers fails, the PR isn’t opened and the user is presented with an error message.”article, stated

Gotchas (what bit them)

A PR can pass CI while still being functionally wrong.

Root cause: Agents can make creative, out-of-scope changes that existing tests do not catch, especially when target components have weak test coverage.

Resolution: Add an LLM judge that compares the diff to the original prompt after deterministic verifiers pass.

“The background agent produces a PR that passes CI but is functionally incorrect.”article, stated
“The target component has little to no test coverage, the agent “gets creative” and decides to change things outside the scope of the prompt”article, stated

Reviewing nonsensical or half-broken PRs becomes expensive at scale.

Root cause: Agents that fail CI or produce unclear changes force engineers to decide whether to salvage or abandon partially completed work.

Resolution: Run verifiers before PR creation and block PRs when verification fails.

“The background agent produces a PR that fails in continuous integration (CI). This is a frustrating error for engineers.”article, stated
“The second and third failure modes can also be large time sinks for engineers; reviewing nonsensical PRs is expensive. To mitigate this, we had to design for predictability from the ground up.”article, stated

Build and test output can overwhelm the agent context window.

Root cause: Different build systems and complex test outputs contain noisy details the agent does not need to reason over directly.

Resolution: Verifier implementations parse output and return concise, actionable success or failure messages.

“the agent doesn’t need to understand the specifics of calling different build systems or parsing complex output from tests; the verifier handles these tasks.”article, stated
“extract only the most relevant error messages on failure and return a very short success message otherwise.”article, stated

Current verifier infrastructure does not cover every runtime environment Spotify needs.

Root cause: Existing verifiers only run on Linux x86, while iOS and some backend systems require macOS or ARM64.

Resolution: Expand verifier infrastructure to more hardware and operating systems.

“we plan to expand our verifier infrastructure to support a wider range of hardware and operating systems.”article, stated
“our iOS applications require macOS hosts to run verifiers successfully, and some backend systems rely on ARM64 architecture.”article, stated

The judge itself lacks robust evals so far.

Root cause: Spotify has internal metrics for judge veto behavior but has not yet invested in a structured judge-evaluation harness.

Resolution: Add robust evals for prompts, architectures, and provider benchmarks.

“We have yet to invest in evals for our judge. However, we know from internal metrics that out of thousands of agent sessions, the judge vetoes about a quarter of them.”article, stated
“Finally, we recognize the need for more structured evaluations.”article, stated

Evaluation

Spotify evaluates the background agent through independent formatting/build/test verifiers, an LLM judge that compares diffs against prompts, internal metrics on judge vetoes and course correction, and planned structured evals for prompts, architectures, and LLM providers.

Metrics: PR produced or failed to produce · CI pass or failure · Functional correctness despite passing CI · Verifier pass/fail by component · Judge veto rate · Agent course-correction rate after a veto · Future prompt, architecture, and provider benchmark results

4 supporting quotes
“## How things fail On a high level, when we run agentic code changes across thousands of different software components, we worry about three primary failure modes. 1.”article, stated
“These verifiers that invoke formatting, building, and testing make sure our agent produces syntactically correct code that builds and passes tests.”article, stated
“we know from internal metrics that out of thousands of agent sessions, the judge vetoes about a quarter of them.”article, stated
“Implementing robust evals will allow us to systematically assess changes to system prompts, experiment with new agent architectures, and benchmark different LLM providers”article, stated

Outcomes

The system operates across thousands of software components and thousands of agent sessions. The article quantifies judge behavior at roughly one-quarter vetoes and half course-correction after veto, and notes current verifier support is Linux x86 with macOS and ARM64 still needed.

4 supporting quotes
“With verifiers and a Judge to guide them, we've found that our agents can solve increasingly complex tasks with a high degree of reliability.”article, stated
“Without these feedback loops, the agents often produce code that simply doesn't work.”article, stated
“out of thousands of agent sessions, the judge vetoes about a quarter of them.”article, stated
“When that happens, the agent is able to course correct half the time.”article, stated