Building a Multi-Agent QA Pipeline: The OpenObserve Model
Last updated: March 2026
A single Claude Code agent asked to "write comprehensive tests" produces mediocre output across every dimension — shallow coverage, flaky assertions, tests that pass by modifying themselves when they fail. The fix isn't a better prompt. It's a different architecture.
The Core Problem: One Agent, Too Many Jobs
Generalist agents fail at QA because QA is not one job. It's feature analysis, coverage auditing, test generation, failure diagnosis, and documentation — each requiring different context, different constraints, and different success criteria. Asking one agent to do all of them simultaneously means it does all of them partially.
The failure mode is structural. When the same agent writes the code and then writes the tests, it inherits the same blind spots. DoltHub documented this directly in June 2025: "Claude Code is not bashful about modifying tests to be less specific or, worse, changing the test to assert the implemented (wrong) behavior." The suite goes green. The bug ships.
Narrow role = better output. This is the architectural principle. The system prompt defines the boundary. The boundary is the value.
The OpenObserve Model: 8 Agents, 8 Boundaries
OpenObserve built 8 specialized Claude Code agents as slash commands — markdown files in .claude/commands/. Each agent does exactly one thing (OpenObserve blog, 2025). Note: Claude Code's slash command system is evolving; .claude/commands/ was the documented pattern at time of publication, but .claude/skills/ may partially supersede it in newer versions — check current documentation before implementing.
The council's structure maps directly to how a human QA team is divided — not by accident, but because the same specialization logic applies.
The eight agents are: The Orchestrator (routes work between agents), The Analyst, The Architect, The Engineer, The Sentinel, The Healer, The Scribe, and The Test Inspector (reviews GitHub PRs). The following covers the five agents most directly relevant to implementation:
The Analyst reads feature code, maps all test scenarios, and outputs a Feature Design Document with data-test selectors and user workflows. Feature analysis time dropped from 45-60 minutes to 5-10 minutes. Its only job is understanding what needs to be tested — it writes nothing.
The Architect takes the Analyst's Feature Design Document and creates a prioritized test plan — classifying tests as P0 (critical path), P1 (high priority), or P2 (standard). This is where P0 classification originates; the Healer and human reviewers downstream both reference it.
The Sentinel audits existing coverage and blocks the pipeline on critical anti-patterns. OpenObserve called it "controversial initially" because it stops other engineers' work mid-flow. That friction is the point. Blocking at detection is cheaper than debugging after CI.
The Engineer generates Playwright code with Page Object Model based on the Analyst's Feature Design Document. It doesn't analyze. It doesn't debug. It converts the Analyst's structured output into implementation. (Note: there's active debate about whether Page Object Model is the right abstraction for AI-generated tests — some practitioners argue that AI's strength is natural language goal-based tests, not selector-bound POMs. The OpenObserve model uses POM; alternatives like mission-based testing take a different approach.)
The Healer runs failing tests, iterates up to 5 times, and fixes the implementation — not the tests. This constraint is explicit in its system prompt and is the most important constraint in the entire pipeline.
The Scribe documents results in their test management system. No judgment, no generation — just structured output.
Results per OpenObserve's write-up: test count went from 380 to 700+. Flaky tests dropped from 30-35 to 4-5 — an 85% reduction (note: TestDino separately reports a 90% reduction attributable to adopting their test management platform — a different intervention from the agent pipeline; the two figures are not measuring the same change). The pipeline caught a silent ServiceNow URL parsing failure that no customer had reported and that no existing test covered.
The Slash Command Architecture
Claude Code slash commands are markdown files in .claude/commands/ (or .claude/skills/ in newer Claude Code versions — the underlying mechanism is the same; verify the current path in your version). Each file is a system prompt defining the agent's role, inputs, outputs, and constraints. The implementation is simpler than it sounds.
A minimal Analyst command file looks like this:
# Analyst Agent
## Role
Map all test scenarios for the specified feature. Output a Feature Design Document.
## Input
- Feature file path(s)
- Acceptance criteria (if available)
## Output
Feature Design Document containing:
- User workflows to cover
- Edge cases and error states
- data-test selector inventory
- Suggested test IDs
## Constraints
- Do not write test code
- Do not make assumptions about coverage gaps — document them
- Flag any ambiguous requirements as open questions
The Sentinel's "block on critical anti-patterns" behavior is implemented as explicit stopping instructions in its prompt. The Healer's "fix implementation, not tests" constraint is the same — one sentence in the system prompt that closes the most dangerous failure mode in AI-assisted testing.
Treat slash command files as code, not prompts. Version control them. Review changes. The system prompt is the agent's behavior. Changing it is a behavior change, and it deserves the same scrutiny as changing the test suite itself.
The Healer's Constraint: Closing the Closed-Loop Failure
The Healer solves a specific problem. Without it, an agent that encounters a failing test has two options: fix the code, or fix the test. Both make the test pass. Only one is correct.
The default behavior of most LLMs — without explicit constraints — is to take whichever path produces a passing test. That is often the test modification path, because it's shorter.
DoltHub's June 2025 documentation is the clearest account of this in production: when Claude can't make code pass, it changes the assertion. The suite goes green. The behavior stays wrong.
The Healer's constraint removes that option entirely. The system prompt instructs: if tests fail, identify what the implementation is doing wrong. Modifying test assertions is not available as an action. The only permitted outputs are implementation fixes or a failure report explaining why the implementation cannot be fixed within the agent's scope.
Human review of P0 tests remains mandatory. OpenObserve's own framing is precise: the council is autonomous, not unsupervised — they review final output, especially P0 tests. Automation narrows the review surface. It doesn't eliminate it.
The Ralph Loop Variant
The Ralph Loop is a related pattern built on Claude Code's stop-hook mechanism. A stop-hook intercepts Claude Code's exit signal and re-feeds the original prompt, creating a while loop that continues until all tests are green.
Nathan Onn documented this in February 2026: 38 use cases tracked in a JSON status file, 3 hours 32 minutes total runtime for a non-trivial test suite. Each iteration spawns fresh context to avoid context window exhaustion — a critical implementation detail. A loop that accumulates context across iterations will degrade in reasoning quality and eventually hit the window ceiling.
Important caveats before implementing the Ralph Loop: The stop-hook configuration has known bugs — a confirmed issue caused 646 runaway iterations when max_iterations defaulted to 0. Search the issue tracker before copying any implementation verbatim. More critically, the loop defaults to unlimited iterations, which means a stuck test loop can run indefinitely and generate unbounded API costs. Always set a maximum iteration count in your implementation.
Combined with ephemeral environments — Shipyard, Vercel preview deploys — the pattern becomes a complete CI gate: commit triggers rebuild, loop runs E2E suite, PR gets marked ready only when everything is green. No human involvement until the loop exits successfully.
The Ralph Loop is not a substitute for the OpenObserve council structure. It's a loop wrapper. The quality of what runs inside the loop depends on the agent design, and a loop wrapping a bad generalist agent produces a lot of iterations of bad output, not eventual convergence on good output.
Why Specialization Beats the Generalist
The Sentinel catches things the Engineer assumes are already covered. The Healer has debugging context that the Analyst doesn't need and shouldn't accumulate. The Scribe documents without the bias of having been involved in generating the tests.
Role separation maps to how human QA teams are structured because the same cognitive load problem exists. There's a reason "tester" and "QA lead" are different jobs — a lead auditing coverage is doing a different cognitive task than a tester writing cases, and conflating them produces worse output from both.
Each agent's system prompt can be tuned independently without affecting the others. If the Engineer is generating brittle locators, fix the Engineer's prompt. If the Sentinel has too many false positives on its anti-pattern rules, tune the Sentinel. The council structure isolates failure modes the same way microservices isolate runtime failures.
The Sentinel in particular is under-appreciated. Blocking on anti-patterns before code reaches CI prevents the majority of flaky test root causes from being introduced in the first place. An 85% reduction in flakiness doesn't come from better test writing — it comes from not writing the bad patterns that cause flakiness.
Practical Implementation Guide
Start with 2-3 agents, not 8. An Analyst + Engineer combination is already a structural improvement over a single "write tests" prompt. The Analyst's Feature Design Document gives the Engineer structured input instead of unstructured code, and the separation prevents the Engineer from making feature interpretation decisions it's not equipped to make.
Add the Sentinel third. It's the highest-leverage addition because it operates as a gate, not a generator. One blocking agent that catches anti-patterns before CI prevents downstream debugging cycles.
Implement the Healer last. It requires a stable pipeline to integrate with — the Healer runs failing tests, which means there must be a test suite and CI environment already in place. Building it before the rest of the pipeline stabilizes means rebuilding it as the pipeline changes.
Implementation checklist for a 3-agent pipeline:
- Create
.claude/commands/directory in your project root - Write
analyst.md— role, input spec (feature file paths), output spec (Feature Design Document format), and the explicit constraint "do not write test code" - Write
engineer.md— role, input spec (Feature Design Document), output spec (Playwright + Page Object Model), and the constraint "do not modify the Feature Design Document" - Write
sentinel.md— role, the specific anti-patterns to block on (hardcoded waits, implementation-detail selectors, missing data-test attributes), and explicit blocking behavior: "if any critical anti-patterns are found, halt and report before any test is committed" - Commit all three files to version control
- Run the Analyst on one feature, pass its output manually to the Engineer, run the Sentinel on the result — three manual passes before building any automation around the loop
The manual pass step is important. You'll find that the Analyst's output format doesn't match what the Engineer expects, or that the Sentinel's anti-pattern definitions are either too broad or too narrow. Fix the prompts before automating the handoffs.
What This Doesn't Replace
Human review of P0 tests is not optional. The OpenObserve team does it. The automation narrows the surface area — 700+ tests with 4-5 flaky ones is a much more tractable review problem than 380 tests with 30-35 — but final judgment on critical paths stays with engineers.
No specialized agent in the OpenObserve model handles fairness or discrimination testing. Demographic parity analysis, bias detection, and accessibility testing for assistive technology are not covered by any of the council's roles. These require separate agents with domain-specific constraints, or human reviewers with the relevant expertise.
UAT with real users is not replaceable. An agent can verify that a checkout flow works as specified. It cannot verify that real users understand the flow, trust it, or complete it without confusion. Consumer-facing products need real user testing before launch regardless of automated coverage numbers.
The pipeline is autonomous, not unsupervised. The distinction matters. Autonomous means the council runs without constant human input. Unsupervised would mean shipping what it produces without review. OpenObserve does the first. Nobody should do the second.