Resource Management
The VoiceRun CLI exposes platform resources through four parallel verbs: vr get, vr describe, vr create, and vr delete. The resource set covers agents and their functions, org-scoped environments, releases that bind agents to environments, entrypoints that route traffic, variables, secrets, phone numbers, telephony providers, and agent templates.
Listing Resources#
vr get prints a table of resources. Every command takes an optional positional filter that narrows the same table down to a single matching row — vr get agents my-agent is the one-row form of vr get agents.
vr get agents # List all agents vr get functions <agent> # Functions for an agent vr get environments # Org-scoped environments vr get agentenvironments <agent> # Legacy per-agent environments vr get releases # Releases (filterable by agent/environment) vr get entrypoints # Org-scoped entrypoints (filterable by type) vr get variables --org # Organization variables vr get variables --agent <agent> --environment <env> # Agent environment variables vr get secrets # Organization secrets vr get phonenumbers # Organization phone numbers vr get telephony # Telephony providers vr get assignments <agent> # Phone number assignments for an agent vr get templates # Available agent templates vr get organizations # Organizations you belong to vr get organizations "Prim Voices" # Single-row organization match vr describe organization "Prim Voices" # Detailed organization info
The <agent> argument accepts a name or ID and defaults to the agent in .voicerun/agent.lock when run inside a project.
vr get releases supports --agent / --environment filters. vr get entrypoints supports --type (phone, web, native).
Viewing Resource Details#
vr describe shows full detail for a single resource:
vr describe agent <name-or-id> vr describe function <agent> <name-or-id> vr describe environment <name-or-id> vr describe agentenvironment <agent> <name-or-id> vr describe release <release-id> vr describe entrypoint <name-or-id> vr describe variable <name-or-id> vr describe secret <name-or-id> vr describe phonenumber <id-or-phone-or-friendly-name> vr describe telephony <name-or-id> vr describe assignment <phone-number>
vr describe variable accepts --agent, --environment, and --org to locate an agent environment variable. vr describe entrypoint shows the weighted release list with each release's share of traffic.
Environments#
Environments are org-scoped — created once for the organization (e.g. staging, production) and reused across agents. Agents are bound to an environment by creating a release.
vr create environment production vr create environment staging --description "Pre-production testing" vr delete environment staging
A legacy per-agent environment concept also exists for agents created before the IaC migration; manage those with vr create agentenvironment, vr get agentenvironments, etc. New projects should use org-scoped environments.
Releases#
A release ties (agent, function, environment, rendered manifest) together at a point in time. The latest release for (agent, environment) is implicitly the active one.
Create a release with vr release. Other release operations:
vr get releases # All releases vr get releases --agent my-agent --environment production vr describe release <release-id> vr delete release <release-id>
Dedicated release lifecycle#
Releases whose Deployment spec sets dedicated: true run in their own pods with a per-release image, and can be stopped, started, and restarted without rebuilding:
vr stop release <release-id> # Scale pods to zero (standby) vr start release <release-id> # Bring a standby release back (~seconds) vr restart release <release-id> # Rolling bounce, same image
Stop puts the release in standby: the built image and infrastructure stay, only the pods go, so vr start release is seconds rather than a rebuild. Restart is rejected while in standby — start it instead.
Stopping a serving release — the newest for its (agent, environment), or one an active entrypoint routes to — takes live traffic down, so the API refuses it (409) unless you pass --force:
vr stop release <release-id> --force
Dedicated release builds run asynchronously: vr release returns as soon as the release is created and then follows the build to completion (created → building → starting → running), printing the final state. Pass --no-wait to return immediately and watch progress with vr get releases (STATE column) or vr describe release.
The platform derives an operational status for every dedicated release from operator intent plus the continuously observed pod state (never hand-maintained, so it cannot drift):
| Status | Meaning |
|---|---|
created | Release exists; nothing has been built or observed yet |
building | The per-release image build is in flight |
starting | Pods are coming up but none is ready yet |
running | At least one pod is ready |
degraded | Pods should be running but show failure signals (crash loops, restarts) |
stopping | Stop requested; pods still winding down |
standby | Deliberately stopped — not a failure |
failed | The release build/prepare failed |
The status appears in release API responses (operationalStatus), the app's releases tab and admin coderunner page, and the output of the lifecycle commands.
Automatic standby and wake
Two platform behaviors manage dedicated release pods without operator action:
- Idle reaper (per-environment, off unless configured): a release that has served no sessions for the configured window is automatically put in standby — pods scale to zero, the built image stays. Idleness is judged only on fresh monitoring data, and a freshly started release always gets a full idle window before it can be reaped.
- Wake-on-demand (always on): any session that reaches a standby release — a phone call, web session, native client, or simulation — automatically scales it back up and connects once a pod is ready, typically within seconds since the image is already built. This also covers manually stopped releases:
vr stop releasefollowed by an incoming call wakes the release rather than failing it.
Together they mean dormant agents cost nothing to keep deployed, and the first call after a quiet period simply waits a few seconds instead of failing.
Entrypoints#
Entrypoints are the public endpoint callers reach — a phone number, a web widget origin, or a native SDK client. Each entrypoint carries a weighted list of releases, and the API picks one per call via weighted random selection. The list can mix releases from different agents/environments — only the release IDs need to be valid.
Creating an entrypoint#
There are three kinds: phone, web, and native. Each accepts --release <releaseId>[:<weight>] (repeatable). Weight defaults to 1 when omitted; weights don't need to sum to a particular number — shares are computed relative to the total. Omit --release entirely to create a release-less entrypoint that you wire up later with vr update entrypoint.
# Phone entrypoint pointing at a single release vr create entrypoint phone support-line \ --release REL_ID \ --phone-number +15551234567 \ --friendly-name "Support" --direction inbound # 70/30 A/B split vr create entrypoint phone support-line \ --release rel-a:70 --release rel-b:30 \ --phone-number +15551234567 # Web (widget) entrypoint vr create entrypoint web widget \ --release REL_ID \ -o https://acme.com -o https://app.acme.com # Native SDK entrypoint vr create entrypoint native mobile-app \ --release REL_ID \ --client-id mobile-ios \ --client-secret-secret-id SECRET_ID
Updating an entrypoint#
Mutate an existing entrypoint with vr update entrypoint. Passing --release replaces the entire routing list (it is not an append).
# Cut over to a new release at 100% vr update entrypoint ENTRYPOINT_ID --release rel-new:100 # Replace the weighted list (replaces, not appends) vr update entrypoint ENTRYPOINT_ID --release rel-a:50 --release rel-b:50 # Disable an entrypoint without deleting it vr update entrypoint ENTRYPOINT_ID --status disabled # Rename vr update entrypoint ENTRYPOINT_ID --name new-name
At least one of --release, --name, or --status must be provided.
vr create entrypoint update still works as a deprecated alias and prints a warning directing you at vr update entrypoint.
Delete an entrypoint:
vr delete entrypoint <name-or-id>
Variables#
Variables are the values your agent reads at runtime via context.variables.get(NAME). They're merged from two scopes at session start: organization-level (visible to every agent) and agent environment-level (scoped to a specific environment).
# Organization-level variable vr create variable SUPPORT_EMAIL help@acme.com --org # Environment-scoped variable for a specific agent + environment vr create variable GREETING_VOICE nova \ --agent my-agent --environment production # Inside a voicerun project, --agent defaults to agent.lock vr create variable GREETING_VOICE nova --environment production
| Flag | Description |
|---|---|
--agent, -a | Agent name or ID (defaults to .voicerun/agent.lock) |
--environment, -e | Environment name or ID (required unless --org) |
--org | Create an organization-level variable instead of an agent environment variable |
--masked | Hide the value in CLI listings and the web UI. The agent runtime still receives the real value. |
Variables are for non-sensitive configuration — for API keys, tokens, and other credentials, use secrets instead. In your handler:
async def handler(event, context): greeting_voice = context.variables.get("GREETING_VOICE", "nova") support_email = context.variables.get("SUPPORT_EMAIL", "help@example.com")
See the Context Reference for runtime behavior including scope merge precedence.
Secrets#
Secrets are organization-scoped values stored in GCP Secret Manager — only metadata touches the VoiceRun database. They're referenced from rendered manifests via {{ Secrets.organization.NAME }} placeholders, which Helm leaves intact through rendering and the API resolves at session start. Secrets never round-trip through the release record itself.
vr create secret OPENAI_API_KEY sk-... vr describe secret OPENAI_API_KEY vr delete secret OPENAI_API_KEY
Reference a secret in .voicerun/templates/:
apiVersion: voicerun/v1 kind: Evaluator metadata: name: resolution-judge spec: evalType: judge apiProvider: google model: gemini-3.5-flash organizationSecretName: GEMINI_API_KEY
If you need a value readable from context.variables.get() at runtime, use variables with --masked instead — agent-scoped runtime injection of secrets is not supported. Passing --agent to vr create secret exits non-zero with a redirect.
Phone Numbers#
Register an existing phone number or purchase a new one from a connected telephony provider:
vr create phonenumber --phone-number +15551234567 # Register existing number vr create phonenumber --purchase --area-code 415 # Purchase new number vr create phonenumber <telephony-id> --purchase -a 212 -c US # From specific provider
| Flag | Description |
|---|---|
--purchase | Purchase a new number from the telephony provider |
--area-code, -a | Area code for the number |
--country-code, -c | Country code (default: US) |
--friendly-name, -n | Friendly name for the number |
--phone-number, -p | Phone number to register (without --purchase) |
Delete or release a phone number:
vr delete phonenumber +15551234567 # Remove from VoiceRun vr delete phonenumber +15551234567 --release # Release back to the provider
Phone Number Assignments#
For agents using legacy per-agent environments, vr create assignment ties a phone number to an agent environment so incoming calls route to that agent. New entrypoint-based projects route via vr create entrypoint phone instead.
vr create assignment <agent> <environment> <phone-number-id> vr create assignment <agent> <environment> <phone-number-id> --configure
Without --configure, the assignment is recorded in VoiceRun but the telephony provider isn't reconfigured. --configure also updates the provider side so incoming calls actually route to the agent.
If you omit the <agent> argument, the agent is resolved from .voicerun/agent.lock.
vr get assignments <agent> # List assignments for an agent vr describe assignment <phone-number> # Details for one assignment vr delete assignment <phone-number> # Unassign (clears agentId / agentEnvironmentId) vr delete assignment <phone-number> --skip-unconfigure # Skip provider-side unconfigure
Telephony Providers#
Connect a Twilio or Telnyx account:
vr create telephony
Without flags, this runs interactively. You can also pass all values up-front:
vr create telephony --name "My Twilio" --provider-type twilio \ --account-sid AC123 --api-key-sid SK123 --api-key-secret secret123 vr create telephony --name "My Telnyx" --provider-type telnyx --api-key KEY123
Templates#
Create a reusable agent template from the current project:
vr create template my-template vr create template my-template --description "Restaurant booking agent" --category booking --public vr create template my-template --upsert # Update if it exists, else create
--public is admin-only; non-admins get a private template. --upsert matches on (name, visibility) — flipping a template between public and private stays a deliberate delete + recreate.
agent.lock is automatically excluded from published templates so consumers don't inherit the author's agent/function IDs.
Deleting Resources#
vr delete agent <name-or-id> vr delete function <agent> <name-or-id> vr delete environment <name-or-id> vr delete agentenvironment <agent> <name-or-id> vr delete release <release-id> vr delete entrypoint <name-or-id> vr delete variable <name-or-id> --org vr delete variable <name-or-id> --agent <agent> --environment <env> vr delete secret <name-or-id> vr delete phonenumber <name-or-id> vr delete phonenumber <name-or-id> --release # Release back to provider vr delete telephony <name-or-id> vr delete assignment <phone-number> vr delete assignment <phone-number> --skip-unconfigure vr delete template <name-or-id>
