What is Tests as Code?
Normally you build evaluators in the Cekura dashboard and then run them. Tests as Code lets you skip that: write your test cases in a JSON file, commit it alongside the agent it tests, and run it straight from CI. Nothing in the file becomes an evaluator in your workspace. Your evaluator list stays exactly as you left it.Why Use It?
Tests live with the code
A change to your agent’s prompt and the tests that cover it land in the same pull request, reviewed together.
Full history
Your version control shows who changed which test case and why — including on branches, where dashboard evaluators cannot follow.
No dashboard setup
New environment, new branch, fork of the repo: the tests come with it. Nothing to recreate.
Same results
Runs appear in Results exactly like any other run, with the same metrics, transcripts, and reports.
Use dashboard evaluators when non-engineers author or review tests, and when you want them reusable across scheduled jobs. Use Tests as Code when the tests belong to a codebase. They work side by side — one agent can have both.
Quickstart
1. Create a spec file
Save this ascekura.tests.json in your repository:
$schema line is optional but gives you autocomplete and inline validation in most editors.
The file says what to test. Which agent to run it against, and how to reach that agent, are supplied by the request — so the same file works unchanged across agents, projects and environments.
2. Check it
Validate without running or spending anything:personality.mode tells you which form was resolved — existing (referenced by ID), override (a base plus your changes), inline (defined from scratch), or project_default. Use it to confirm the file did what you meant before spending anything.
3. Run it
Drop?dry_run=true and the runs start:
id against the Results API for progress and success rate.
The request
POST /test_framework/v1/scenarios/run_scenarios_json/
Authenticate with X-CEKURA-API-KEY. The key’s own scope resolves the project, so no project_id is needed.
* Send exactly one of
spec or file.
Uploading the file instead of embedding it
Avoids$(cat …) quoting entirely, which is handy in shells where escaping gets awkward:
Writing a spec file
Structure at a glance
agent_id, no channel, no credentials, no provider ids. Those are request parameters or agent configuration — see Choosing the run target. A file containing agent_id is rejected, so the split stays honest.
The envelope
A test case
*
instructions is required for instruction cases; conditional_actions cases need conditional_actions and language instead.
Metrics must already exist
A spec references metrics, it cannot define them. Create them in the dashboard first, then point at them by numeric ID or by slug:Personalities
Three forms, depending on how much control you want:- Use an existing one
- Adjust an existing one
- Define one from scratch
name, prompt, language, accent, voice_id, voice_model, provider, speed, background_noise, end_call_enabled.
Personalities defined inline are used for that run only. No personality is created in your workspace — your personality list is untouched. Cekura manages the underlying voice and transport configuration, so a spec cannot reach those internals.
Test data
Reference a saved test profile, or supply the data inline:agent_variablesreach the agent under test as dynamic variables at call time.caller_variablesare context for the simulated caller only, and never sent to your agent. Reference them ininstructionsas{{test_profile.<key>}}.
Defaults
Anything repeated across cases can move up intodefaults:
defaults field by field. metrics lists from both are combined.
Choosing the run target
Two request parameters decide where and how a spec runs — neither belongs in the file:elevenlabs. If the agent isn’t configured for the channel you pick, the run is rejected with a message naming what’s missing.
Other execution modes exist but are not accepted yet; passing one is rejected rather than run down an unintended path.
Reading validation errors
Every problem in a spec is reported at once, keyed by its location in the file, so one round trip tells you everything to fix:Using it in CI
success_rate. The GitHub Actions Tutorial covers the polling and gating pattern in full — the only difference is which endpoint starts the run.
Starting from evaluators you already have
If your tests currently live in the dashboard, export them rather than rewriting them by hand: select your evaluators, choose Export, and pick Test suite spec (.json). The file it produces is a valid spec you can commit as-is.Limits
Test cases from a spec are cleaned up automatically once no recent run needs them, and results keep their test-case names regardless. Inline personalities and test data never become rows at all, so nothing accumulates in your personality or test-profile lists.
Getting the schema
The machine-readable schema this endpoint accepts:$schema for editor autocomplete, or feed it to a JSON Schema validator to check specs locally before they reach CI.
The same document is published at a stable URL, which is what the $schema line in the examples above points at: