Anything under .voicerun/templates/ is rendered with Helm at vr release time and snapshotted onto the release manifest. Each YAML document declares one resource:
apiVersion: voicerun/v1
kind: Deployment | Simulation | Webhook | Evaluator
metadata:name: <unique within the manifest>spec:...
Preview rendered output with vr render; validate spec shape with vr validate. Values referenced as {{ .Values.foo }} come from .voicerun/values.yaml (and overlays); {{ .Agent.Name }} and friends come from .voicerun/agent.yaml. Secrets are referenced as {{ Secrets.organization.NAME }} — Helm leaves the placeholder intact and the API resolves it at session start.
metadata.name must be unique within a manifest for each kind. It's the handle used by other commands (e.g. vr simulate --name <…>, vr evaluation list --type <…>).
Runtime configuration for the agent in an environment. Every field is optional except kind/metadata.name — omitted fields take platform defaults. The mode field decides whether handler.py is required at the project root.
apiVersion: voicerun/v1
kind: Deployment
metadata:name: my-agent-deployment
spec:mode: coderunner # 'coderunner' (handler.py sandbox) or 'relay'region: us-central1-a
variables:LOG_LEVEL: info
FEATURE_FLAG:"true"stt:model: flux-general-en
language: en
failover:model: nova-3turnTaking:mode: smart_turn
externalEndpointing:300smartTurnVadStopSecs:0.4smartTurnStopSecs:3.0smartTurnTimeout:5.0tts:provider: cartesia
model: sonic-2voice: lyric
language: en
speed:1.0relay:url: wss://my-relay.example.com/ws/agent
recording:enabled:falselocation: gs://my-bucket/recordings/
redaction:enabled:falsetracing:enabled:true
Runtime mode. coderunner (default) runs your handler.py in the sandbox. relay runs in voicerun-relay — no handler.py is required and vr validate skips the handler check automatically.
region
string
Cluster region (e.g. us-central1-a).
variables
map<string, string>
Values injected into context.variables at session start. Merged with the org/agent-environment variable scopes.
relay
object
Relay endpoint config. Only used when mode: relay.
stt
object
Speech-to-text config.
turnTaking
object
Turn-taking strategy. Sibling of stt/tts because the signal can come from STT (provider EoT), raw audio (Silero VAD, Smart Turn V3), or — eventually — semantic analyzers.
tts
object
Text-to-speech config.
recording
object
Call recording config.
redaction
object
PII redaction applied to traces and session events.
How turn boundaries are decided. provider uses the STT provider's built-in endpointing. silero runs local Silero VAD on the relay/agent. smart_turn runs Silero VAD + Smart Turn V3 ML.
externalEndpointing
number
Silence-stop threshold (ms) for silero / smart_turn.
smartTurnVadStopSecs
number
smart_turn only — VAD silence-stop window before the ML gates. Default 0.4.
smartTurnStopSecs
number
smart_turn only — ML's per-window timeout. Default 3.0.
smartTurnTimeout
number
smart_turn only — hard cap on the ML's running window. Default 5.0.
A simulated caller used by vr simulate. The CLI submits the simulation's metadata.name; the API resolves spec from the active release's manifest, so the version that runs is always the released one, not whatever is on disk.
apiVersion: voicerun/v1
kind: Simulation
metadata:name: happy-path
spec:systemPrompt:| You are a customer calling this agent. Keep turns short and realistic.numberOfSimulations:5provider: gemini_live
model: gemini-3.1-flash-live-preview
voice: Aoede
phases:-type: ring
durationSecs:8-type: message
text:"Thank you for calling. All representatives are busy. Please hold."-type: holdMusic
durationSecs:30loopPhases:truehumanPickupAfterSecs:90
Number of simulated sessions spawned per vr simulate invocation.
provider
gemini_live | openai_realtime
no
Persona engine vendor. Defaults to gemini_live.
model
string
no
Provider-specific model id. For gemini_live: e.g. gemini-3.1-flash-live-preview (default). For openai_realtime: e.g. gpt-realtime (default), gpt-realtime-mini.
voice
string
no
Provider-specific voice id. For gemini_live: Aoede, Puck, Charon, Kore, Fenrir, etc. For openai_realtime: alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin, cedar.
phases
PhaseSpec[]
no
Pre-pickup phase script — see below.
loopPhases
boolean
no
When phases is non-empty, restart the phase list when it ends. Default true.
humanPickupAfterSecs
integer (0-600)
no
Seconds of phase playback before the persona takes over. Omit to never auto-pickup (tests the agent's give-up logic).
Phase entries play before the simulated persona starts speaking — useful for warm-transfer testing where the outbound leg waits through ringing/queue/IVR before someone "answers".
type
Fields
Description
ring
durationSecs (int, 1-600)
North-American ringback tone (440+480 Hz, 2s on / 4s off).
holdMusic
durationSecs (int, 1-600)
Looping arpeggio that reads as hold music to a VAD.
Single-character keys (0-9, *, #) mapped to the sub-phases that fire when the agent sends that digit. Phases can themselves be ivrMenu entries for multi-level trees.
timeoutSecs
integer (1-120)
Seconds to wait for a digit after the prompt finishes. Default 8.
maxRepeats
integer (0-10)
Additional re-prompts when no digit arrives. Default 2.
onNoInput
PhaseSpec[]
Phases to run after maxRepeats re-prompts produce no input.
onInvalid
PhaseSpec[]
Phases to run when the agent sends a digit not in options.
Event triggers this webhook listens for. Only session.ended is supported today; the list is intentionally small so adding a new event requires explicit code review.
signingToken
string
no
HMAC-SHA256 signing token for outgoing deliveries. Typically supplied via {{ Secrets.organization.NAME }} and resolved at consume time. When absent, the worker sends an unsigned request.
.voicerun/values.yaml is the base values file used by Helm. Per-environment overlays (e.g. prod.yaml, staging.yaml) live alongside it and are pulled in with --values prod.yaml on vr release, vr render, or vr simulate.
# .voicerun/values.yamlvariables:LOG_LEVEL: info
region: us-central1-a
stt:model: flux-general-en
language: en
tts:provider: cartesia
model: sonic-2voice: lyric
recording:enabled:falsetracing:enabled:truewebhook:url:null# leave null to skip the Webhook resource entirelysimulation:numberOfSimulations:1evaluator:apiProvider: openai
model: gpt-4o
Helm leaves the placeholder intact through rendering. The API resolves it against organization secrets at session start, so secrets never round-trip through the release record itself. Create secrets with vr create secret.
Both vr validate and vr render run shape-only validation against rendered manifests. The validator checks that:
Each document has a known kind (Deployment, Simulation, Webhook, Evaluator).
spec contains only the allowed top-level keys for that kind.
Required fields are present (e.g. Webhook.spec.url, Evaluator.spec.systemPrompt for judge).
Bounded fields are in range (e.g. numberOfSimulations is 1-100).
metadata.name is unique per kind within a manifest.
Validator-level checks don't hit the database, so they don't catch missing organization secrets or unknown providers — those are surfaced at vr release time when the API processes the manifest.