Voice Agent Tests as Code: YAML Template for CI

Sumanyu Sharma
Sumanyu Sharma
Founder & CEO
, Voice AI QA Pioneer

Has stress-tested 4M+ voice agent calls to find where they break.

May 25, 2026Updated July 7, 202611 min read
Voice Agent Tests as Code: YAML Template for CI

Voice agent tests as code means defining test cases in version-controlled files so prompts, personas, call paths, assertions, and expected evidence can be reviewed before they run against production agents.

If your team changes one demo agent by hand once a month, this is probably too much process. Use the dashboard, listen to the calls, and keep moving.

This is for teams where voice-agent behavior changes through pull requests: prompt edits, tool schemas, routing rules, language support, compliance scripts, and workflow fixes. Once those changes ship through Git, the tests should live there too.

"The programmatic part of it to me is the big unique offering and advantage," says Blake Jones, AI Engineer at Basata. We found that the value appears when the test definition, evidence, and agent change can be reviewed together.

TL;DR: Put voice agent test cases in YAML, validate them against a schema, run the blocking subset in CI, and store the result with the same commit that changed the prompt or workflow.

A test that only exists in a vendor dashboard can still be useful. It is just hard to review, diff, export, or connect to the code change that made it necessary.

Methodology Note: The template in this guide is based on Hamming's analysis of 4M+ production voice agent calls across 10K+ voice agents (2025-2026).

Treat this as a starting contract. Regulated flows, payments, and account changes need stricter approvals and side-effect controls than low-risk FAQ flows.

Last Updated: July 2026

Related Guides:

What Belongs in a Voice Agent Test File

The file should be boring. A reviewer should understand what the call will do, what must pass, what is allowed to touch a real system, and what evidence will be saved.

Test fieldWhat it capturesWhy it belongs in Git
idStable test identifierLets failures stay searchable across runs
ownerTeam or person responsiblePrevents orphaned tests
agent_refAgent, prompt, branch, or environmentTies the test to a deployable target
personaCaller language, accent, goal, constraintsMakes caller coverage reviewable
setupFixture state before the callKeeps tests reproducible
call_pathInbound, outbound, WebRTC, SIP, or provider modePrevents text-only tests from pretending to be voice tests
assertionsOutcome, transcript, tool, latency, policy, and side-effect checksDefines pass/fail before the run starts
evidenceAudio, transcript, trace, tool result, dashboard linkMakes failures debuggable
cleanupHow test data is removed or isolatedPrevents synthetic calls from polluting production

GitHub Actions workflows are YAML files under .github/workflows, and GitLab CI uses YAML for pipeline configuration. That does not mean voice-agent tests must use YAML forever. It means YAML is familiar enough for code review, comments, ownership, and CI wiring.

A Copyable YAML Template

Use this as the starting shape. Keep IDs stable and names human-readable.

version: 1suite: appointment_booking_smokeowner: growth-engagent_ref:  environment: staging  agent_slug: scheduling-agent  prompt_version: pr-482defaults:  call_path: inbound_phone  timeout_seconds: 180  evidence:    retain_audio: true    retain_transcript: true    retain_tool_trace: true    retain_days: 30tests:  - id: booking_reschedule_verified_caller    title: Reschedule an appointment after identity check    risk: blocking    persona:      language: en-US      caller_goal: Move my Tuesday appointment to Friday afternoon      speech_conditions:        accent: neutral        background_noise: office    setup:      fixtures:        caller_id: caller_qa_104        appointment_id: appt_fixture_882      side_effect_mode: sandbox    call_script:      - user: I need to move my appointment from Tuesday to Friday after 2.      - user: Yes, Friday at 3 works.    assertions:      outcome:        task_completed: true        no_unplanned_handoff: true      transcript:        must_include:          - Friday at 3        must_not_include:          - I cannot access your account      tools:        required_order:          - lookup_identity          - list_appointments          - hold_slot          - update_booking          - send_confirmation      side_effects:        calendar:          appointment_id: appt_fixture_882          expected_status: rescheduled          duplicate_events_allowed: false      latency:        turn_p95_ms_max: 1500    cleanup:      delete_sandbox_records: true

This template is intentionally more specific than a generic "run test" payload. Voice-agent failures hide in the details: wrong fixture, wrong call path, missing tool trace, duplicate calendar write, or a human handoff that technically happened but carried no context.

Field-by-Field Review Checklist

Review the test file like production code.

Review questionGood answerBlock the PR when
Does the test have an owner?owner maps to a team or personNobody can triage failures
Is the target clear?Environment, agent slug, and prompt version are explicitTest could run against the wrong agent
Is the caller realistic?Persona includes goal, language, and relevant speech conditionTest only mirrors the happy-path script
Are assertions layered?Outcome, transcript, tool, side-effect, and latency checks are separatedA transcript check stands in for the whole workflow
Are writes safe?side_effect_mode is mock, sandbox, or explicitly allowlistedCI can touch real customer systems
Is evidence retained?Audio, transcript, tool trace, and run ID are savedFailure cannot be debugged later
Is cleanup defined?Fixtures reset or expireSynthetic data leaks into later runs

The important shift is that QA changes become reviewable. A teammate can ask, "Why is this test non-blocking?" or "Why does this prompt change not add a regression case?" before the agent reaches customers.

Git review rule: a voice agent test is reviewable only when the reviewer can see the caller setup, target agent, assertions, side-effect policy, and retained evidence before the test runs. If those details live only in a dashboard, the PR cannot prove what behavior it is protecting.

How to Import a Golden Dataset

Most teams start with a spreadsheet. That is fine. The mistake is importing the spreadsheet as loose rows with no schema.

Use an import map:

Spreadsheet columnYAML fieldRequired?Notes
case_idtests[].idYesStable, lowercase, no spaces
caller_goalpersona.caller_goalYesPlain English job-to-be-done
languagepersona.languageYesUse locale format when possible
fixture_customersetup.fixtures.caller_idConditionalRequired for account workflows
opening_utterancecall_script[0].userYesFirst caller turn
expected_outcomeassertions.outcomeYesConvert prose into typed checks
must_call_toolassertions.tools.required_orderConditionalRequired for workflow tests
max_latency_msassertions.latency.turn_p95_ms_maxOptionalUse only when latency is part of the risk
risktests[].riskYesblocking, scheduled, or manual

After import, validate the file. JSON Schema is a good fit because it can require fields, constrain object shapes, and validate nested data. The point is not ceremony. The point is refusing a "golden dataset" where half the rows have no expected outcome.

Blocking, Scheduled, and Ephemeral Tests

Not every test belongs in the same gate.

Test classWhen to useStorage policyRun cadence
BlockingCritical account, payment, compliance, booking, or safety flowsPersist test definition and evidenceEvery relevant PR
ScheduledBroader regression, language, persona, and coverage suitesPersist definition, retain sampled evidenceNightly or weekly
EphemeralOne-off investigation, vendor trial, support reproductionStore run metadata and result, not permanent suite entryManual or temporary CI job

Ephemeral is a lifecycle choice, not a logging shortcut. Otherwise the team cannot tell whether it was a real test or just a dashboard click.

Ephemeral run rule: temporary voice agent tests can skip permanent suite registration, but they should not skip evidence. The minimum record is the run ID, agent version, assertion result, trace link, and cleanup status.

How to Run Ephemeral Tests Without Permanent Vendor Storage

Ephemeral voice agent tests are useful when you need a short-lived reproduction: a vendor bakeoff, a support escalation, a preview-environment smoke test, or a one-off prompt investigation. The trap is treating "temporary" as "unreviewable." Even if the test disappears tomorrow, the team still needs enough evidence to debug the failure, prove cleanup, and decide whether the case belongs in the permanent suite.

Temporary test contract: delete the throwaway test definition when the investigation ends, but keep a redacted evidence envelope in customer-controlled storage. It should answer who ran the check, which agent version ran, what failed, where the trace lives, and when the test data expires.

Split retention by artifact instead of giving the whole run one broad expiration date. The values below are example operating defaults, not vendor limits or compliance advice:

ArtifactKeep for ephemeral tests?WhyDelete or promote when
Test definitionUsually no, unless repeatedAvoids turning a one-off reproduction into suite clutterDelete after the investigation, or promote when the failure is repeatable or high-risk
Run metadataYesEngineers need run ID, agent version, environment, and ownerStart with 7-30 days, then shorten or extend to match policy and incident-response needs
Redacted transcriptYes, if text is needed to debugLets reviewers inspect the failure without raw customer dataDelete after triage, or attach to a promoted regression
Raw audioOnly when voice quality mattersNeeded for ASR, interruption, silence, or latency debuggingPrefer short retention; disable when not needed
Tool traceYes for workflow testsProves the agent called the right tool with safe fixture dataKeep until the issue is closed
Fixture cleanup proofYesShows test records, calendar holds, tickets, or sandbox writes were removedKeep with the run record

Security, legal, contractual, and incident-response requirements own the final retention window. If those requirements conflict with this example, use the stricter policy.

Provider settings matter here. ElevenLabs documents separate retention controls for conversation transcripts and audio recordings, including scheduled deletion by setting retention to 0 days. Retell documents per-agent retention from 1 to 730 days; after expiry it deletes recordings, transcripts, logs, retrieval logs, dynamic variables, and metadata on a daily schedule, while retaining some basic internal metadata. That is delayed payload deletion, not zero retention. If a vendor cannot separate test definitions, run results, audio, transcripts, and tool traces, treat that as a security-review question before using production-derived test material.

For Google CX Agent Studio, the evaluation model separates scenario tests from golden tests. That distinction is useful outside Google too: scenario-style checks are good for exploration, while golden tests are the cases you want to keep stable. The batch-upload format shows what the promoted version needs: a named evaluation row, ordered turns, action types, and explicit expectations.

Use this promotion rule:

SignalKeep ephemeralPromote to permanent tests-as-code
One-off vendor trialYesOnly if it exposes a repeatable platform limitation
Support reproduction with synthetic dataYesPromote when the same failure appears in production or staging
Preview-environment smoke testYesPromote when it protects a launch-critical workflow
Compliance or payment pathRarelyUsually promote immediately after privacy review
Repeated failing tool-call sequenceNoPromote with fixture data, expected tool order, and cleanup assertion

We used to think every useful test should become a permanent test. That created noisy suites. The better rule is narrower: every useful failure needs evidence, and every repeated useful failure needs a reviewed test.

GitHub Actions Gate

Here is a minimal GitHub Actions shape. Use your own runner and command names.

name: voice-agent-testson:  pull_request:    paths:      - agents/**      - prompts/**      - tests/voice-agents/**jobs:  voice-agent-tests:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-node@v4        with:          node-version: "20"      - run: npm ci      - name: Validate voice test YAML        run: npm run voice-tests:validate -- tests/voice-agents      - name: Run blocking voice tests        run: npm run voice-tests:run -- --risk=blocking --env=staging      - name: Upload voice test evidence        if: always()        run: npm run voice-tests:evidence -- --format=summary

The gate should fail when a blocking test fails, when a required fixture is missing, when a test tries to write outside its allowed mode, or when the evidence upload fails. A test result that nobody can inspect is not a CI gate. It is a guess with a status icon.

Common Mistakes

MistakeWhy it hurtsBetter pattern
Storing tests only in a vendor dashboardPrompt changes and test changes cannot be reviewed togetherKeep critical tests in Git and sync to the runner
Making every test blockingCI becomes slow and noisyUse blocking, scheduled, and manual risk classes
Checking only transcript textThe agent can say the right thing while tools failAdd tool, side-effect, latency, and handoff assertions
Importing spreadsheets without schema validationRows drift into inconsistent formatsConvert columns into typed YAML fields
Keeping no evidence for failed runsDevelopers cannot debug the failureRetain audio, transcript, trace, tool output, and cleanup status
Letting tests write to shared systemsSynthetic calls pollute calendars, CRMs, and support queuesUse mock or sandbox modes by default

The honest limitation: tests as code will not replace exploratory QA. Voice agents still need humans listening for weird pacing, awkward recovery, and caller frustration. But once a failure matters enough to block a release, it should graduate into a file someone can review.

Frequently Asked Questions

Yes. Define the persona, setup, call path, assertions, evidence policy, and cleanup rules in YAML, validate the file against a schema, then run the blocking subset from CI. Hamming recommends keeping high-risk workflow tests in Git so prompt and test changes can be reviewed together.

Include a stable test ID, owner, agent reference, persona, setup fixtures, call path, assertions, evidence retention, and cleanup rules. Hamming recommends separating transcript, tool, side-effect, latency, and handoff assertions so a spoken answer does not hide an operational failure.

Use stable IDs, explicit owners, typed assertions, and small files grouped by agent or workflow. Reviewers should be able to see what changed in the caller goal, fixture, expected tool order, latency threshold, or side-effect policy before the test runs.

Map spreadsheet columns into typed fields such as id, caller goal, language, fixture, expected outcome, and risk. Hamming recommends rejecting imported rows that do not have an expected outcome or owner because they become untriageable later.

Ephemeral tests can be temporary, but they should still produce evidence: run ID, agent version, assertion results, trace link, retention policy, and cleanup status. Hamming recommends using them for investigations, vendor trials, and preview-environment smoke checks, then promoting repeated failures into the permanent regression suite.

Keep the test definition temporary, but save a redacted evidence envelope with run metadata, assertion results, trace links, and fixture cleanup proof. Hamming recommends setting separate retention rules for transcripts, audio, tool traces, and run metadata so short-lived tests still remain debuggable.

Block on tests for account access, payments, compliance scripts, booking writes, workflow side effects, production handoff behavior, and any failure that previously caused customer impact. Keep long-tail coverage and expensive language sweeps scheduled unless they protect a launch-critical flow.

Save audio, transcript, trace ID, tool inputs and outputs, assertion results, final state, and cleanup status. Hamming recommends storing enough context that an engineer can reproduce the failure without asking QA which dashboard filters they used.

No. Dashboard-created tests are useful for exploration, triage, and non-engineering workflows. Hamming recommends promoting release-blocking or repeatedly failing cases into Git so they become reviewable, portable, and connected to the code or prompt change that requires them.

Sumanyu Sharma

Sumanyu Sharma

Founder & CEO

Previously Head of Data at Citizen, where he helped quadruple the user base. As Senior Staff Data Scientist at Tesla, grew AI-powered sales program to 100s of millions in revenue per year.

Researched AI-powered medical image search at the University of Waterloo, where he graduated with Engineering honors on dean's list.

“At Hamming, we're taking all of our learnings from Tesla and Citizento build the future of trustworthy, safe and reliable voice AI agents.”