By Sagar Shankaran, Founder of CallSphere
Provision an AI voice stack with Pulumi 3.230+ in TypeScript: ESC for secrets, AI-generated modules, deployments-as-a-service, and uv-backed Python providers.
Key takeaways
TL;DR — Pulumi ESC (now GA) gives you hierarchical, dynamic-credential environments. Combined with Pulumi Deployments and the AI agent CLI helpers, your AI voice stack provisions in a single
pulumi upwith no static secrets anywhere.
A TypeScript Pulumi program that stands up a k3s edge cluster on Hetzner, deploys a LiveKit + voice-agent + Postgres trio, and pulls all secrets at runtime from Pulumi ESC backed by AWS Secrets Manager.
flowchart LR
PULUMI[pulumi up] --> ESC[Pulumi ESC]
ESC --> ASM[(AWS Secrets Manager)]
PULUMI --> HZ[Hetzner k3s nodes]
HZ --> LK[LiveKit Deployment]
HZ --> AG[Voice Agent Deployment]
HZ --> PG[Postgres StatefulSet]
ESC -->|runtime env| AG
```bash pulumi new typescript -y pulumi env init voice-prod pulumi env set voice-prod aws.login.fn::open '{"provider":"aws-secrets","login":"arn:aws:iam::123:role/pulumi-esc"}' pulumi env set voice-prod openai.apiKey '{"fn::secret":{"fn::open::aws-secrets":"openai/realtime"}}' ```
Now openai.apiKey is defined in ESC but only fetched at pulumi up time — the value never lives on disk.
```yaml
environment:
Now every config read like config.requireSecret("openai:apiKey") resolves through ESC.
```typescript import * as hcloud from "@pulumi/hcloud"; import * as command from "@pulumi/command"; import * as pulumi from "@pulumi/pulumi";
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
const sshKey = new hcloud.SshKey("ops", { publicKey: process.env.SSH_PUB! }); const server = new hcloud.Server("voice-edge-1", { serverType: "ccx33", // 8 vCPU AMD, dedicated image: "ubuntu-24.04", location: "ash", // Ashburn, VA — closest to OpenAI us-east sshKeys: [sshKey.id], });
const k3sInstall = new command.remote.Command("k3s-install", {
connection: { host: server.ipv4Address, user: "root", privateKey: process.env.SSH_KEY! },
create: curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.31.0+k3s1 sh -s - --disable traefik,
});
```
ccx33 (dedicated AMD, 8 vCPU / 32 GB) is the sweet spot for ~50 concurrent voice sessions on OpenAI Realtime in our benchmarks.
```typescript import * as k8s from "@pulumi/kubernetes"; import { interpolate } from "@pulumi/pulumi";
const kubeconfig = command.remote.runOutput({ connection: { host: server.ipv4Address, user: "root", privateKey: process.env.SSH_KEY! }, create: "cat /etc/rancher/k3s/k3s.yaml", }, { dependsOn: k3sInstall }).apply(r => r.stdout.replace("127.0.0.1", server.ipv4Address));
const k = new k8s.Provider("k3s", { kubeconfig });
const ns = new k8s.core.v1.Namespace("voice", { metadata: { name: "voice" }}, { provider: k });
const cfg = new pulumi.Config(); const apiKey = cfg.requireSecret("openai:apiKey");
new k8s.core.v1.Secret("voice-secrets", { metadata: { namespace: ns.metadata.name, name: "voice-secrets" }, stringData: { OPENAI_API_KEY: apiKey }, }, { provider: k }); ```
apiKey is a pulumi.Output<string> that's only resolved by the engine — your TypeScript code never sees the plaintext.
```typescript import * as helmv4 from "@pulumi/kubernetes/helm/v4";
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
new helmv4.Chart("voice-agent", { chart: "oci://ghcr.io/acme/charts/voice-agent", version: "1.0.0", namespace: ns.metadata.name, values: { image: { repository: "ghcr.io/acme/voice-agent", tag: process.env.GIT_SHA }, livekit: { url: "ws://voice-livekit:7880" }, openai: { secretRef: "voice-secrets" }, }, }, { provider: k }); ```
Helm v4 provider in Pulumi (released 2025) does server-side apply and reports kstatus-aware readiness.
```yaml
template: config: aws:region: { value: us-east-1 } deploymentSettings: sourceContext: { git: { repoURL: "https://github.com/acme/voice", branch: main } } operationContext: { preRunCommands: ["uv sync --frozen"] } ```
Now every PR gets a pulumi preview posted as a comment, and merging main triggers pulumi up — Pulumi-managed runners, no GH Actions runner needed.
```bash pulumi ai prompt "add a Cloudflare DNS record voice.example.com pointing to the Hetzner server" ```
In 2026 the AI agent will read your existing program, generate a coherent diff, and offer it as a PR. Useful for boilerplate; review every line for IAM and networking.
Output<string> leaks via .toString() — if you log an Output you'll get Calling .toString() on an Output<T> warning. Use .apply properly.PIP_DISABLE_PIP_VERSION_CHECK=1 and UV_NO_CACHE=1 to avoid stale wheel issues.fetchOpts becomes repositoryOpts. Migration takes ~10 min per chart.CallSphere's primary infra is k3s on a dedicated host (not Hetzner — our Postgres lives at 72.62.162.83 behind Cloudflare Tunnel) but the Pulumi pattern above runs CallSphere fork environments for partners on Hetzner ccx33 nodes. ESC pulls model keys from a central vault per partner. 37 agents, 90+ tools, 115+ DB tables, $149/$499/$1499, 14-day trial, 22% affiliate.
Q: Pulumi vs Terraform for AI infra? Pulumi if your team writes TypeScript/Python already; the typed SDKs catch IAM bugs at compile time. Terraform if you want HCL's declarative purity.
Q: ESC vs External Secrets Operator?
ESC for infra-time secrets (during pulumi up); ESO for runtime secrets (Kubernetes pods). Use both.
Q: Pulumi Deployments cost? Free for individuals; team plans start ~$50/user/month and replace a self-hosted runner.
Q: Can I import existing infra?
Yes — pulumi import aws:s3/bucket:Bucket my-bucket existing-name generates the program.
Written by
Sagar Shankaran· Founder, CallSphere
Sagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
How to actually observe a WebSocket fleet: ping/pong heartbeats, Prometheus metrics that matter, dead-man switches, and the alerts that fire before customers notice.
Haystack 2.7's Agent component plus an Ollama-served Llama 3.2 gives you tool-calling RAG with citations. Here's a complete pipeline against your own document store.
The 2024 NPRM proposes mandatory penetration tests every 12 months and vulnerability scans every 6 months. Here is how an AI voice agent should be tested in 2026.
Run STT, LLM, and TTS entirely on Cloudflare's edge — no OpenAI, no ElevenLabs. Real working code with Whisper, Llama 3.3 70B, and Deepgram Aura.
Version your prompts in git, run a 50-case eval suite on every PR, block merges below threshold, and ship a new agent prompt with confidence — full GitHub Actions tutorial.
AI SDK 5 ships fully typed chat for React, Svelte, Vue, and Angular plus first-class agent loop primitives. Here are the patterns that matter for shipping in 2026.
© 2026 CallSphere LLC. All rights reserved.
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI