@@ -4,15 +4,15 @@ Manage Vapi resources via Git using YAML/Markdown as the source-of-truth.
44
55## Why GitOps?
66
7- | | Dashboard / Ad-hoc API | GitOps |
8- | ---| ---| ---|
9- | ** History** | Limited visibility of who changed what | Full git history with blame |
10- | ** Review** | Changes go live immediately (can break things) | PR review before deploy |
11- | ** Rollback** | Manual recreation | ` git revert ` + push |
12- | ** Environments** | Tedious to copy-paste between envs | Same config, different state files |
13- | ** Collaboration** | One person at a time. Need to duplicate assistants, tools, etc. | Team can collaborate and use git branching |
14- | ** Reproducibility** | "It worked on my assistant!" | Declarative, version-controlled |
15- | ** Disaster Recovery** | Hope you have backups | Re-apply from git |
7+ | | Dashboard / Ad-hoc API | GitOps |
8+ | --------------------- | --------------------------------------------------------------- | ------------------------------------------ |
9+ | ** History** | Limited visibility of who changed what | Full git history with blame |
10+ | ** Review** | Changes go live immediately (can break things) | PR review before deploy |
11+ | ** Rollback** | Manual recreation | ` git revert ` + push |
12+ | ** Environments** | Tedious to copy-paste between envs | Same config, different state files |
13+ | ** Collaboration** | One person at a time. Need to duplicate assistants, tools, etc. | Team can collaborate and use git branching |
14+ | ** Reproducibility** | "It worked on my assistant!" | Declarative, version-controlled |
15+ | ** Disaster Recovery** | Hope you have backups | Re-apply from git |
1616
1717### Key Benefits
1818
@@ -24,16 +24,16 @@ Manage Vapi resources via Git using YAML/Markdown as the source-of-truth.
2424
2525### Supported Resources
2626
27- | Resource | Status | Format |
28- | ----------| --------| -------- |
29- | ** Assistants** | ✅ | ` .md ` (with system prompt) or ` .yml ` |
30- | ** Tools** | ✅ | ` .yml ` |
31- | ** Structured Outputs** | ✅ | ` .yml ` |
32- | ** Squads** | ✅ | ` .yml ` |
33- | ** Personalities** | ✅ | ` .yml ` |
34- | ** Scenarios** | ✅ | ` .yml ` |
35- | ** Simulations** | ✅ | ` .yml ` |
36- | ** Simulation Suites** | ✅ | ` .yml ` |
27+ | Resource | Status | Format |
28+ | ---------------------- | ------ | ------------------------------------ |
29+ | ** Assistants** | ✅ | ` .md ` (with system prompt) or ` .yml ` |
30+ | ** Tools** | ✅ | ` .yml ` |
31+ | ** Structured Outputs** | ✅ | ` .yml ` |
32+ | ** Squads** | ✅ | ` .yml ` |
33+ | ** Personalities** | ✅ | ` .yml ` |
34+ | ** Scenarios** | ✅ | ` .yml ` |
35+ | ** Simulations** | ✅ | ` .yml ` |
36+ | ** Simulation Suites** | ✅ | ` .yml ` |
3737
3838---
3939
@@ -45,6 +45,7 @@ Manage Vapi resources via Git using YAML/Markdown as the source-of-truth.
45454 . ** Promote by environment** (` dev ` -> ` stg ` -> ` prod ` ) by copying files between ` resources/dev/ ` , ` resources/stg/ ` , and ` resources/prod/ ` .
4646
4747Use:
48+
4849- ` pull ` when Vapi might have changed
4950- ` push ` for explicit deploys
5051- ` apply ` (` pull -> merge -> push ` ) when you want one command for sync + deploy
@@ -78,26 +79,26 @@ cp .env.example .env.prod
7879
7980### Commands
8081
81- | Command | Description |
82- | ---------| -------------|
83- | ` npm run build ` | Type-check the codebase |
84- | ` npm run pull:dev ` | Pull platform state, preserve local changes |
85- | ` npm run pull:stg ` | Pull staging state, preserve local changes |
86- | ` npm run pull:dev:force ` | Pull platform state, overwrite everything |
87- | ` npm run pull:stg:force ` | Pull staging state, overwrite everything |
88- | ` npm run pull:prod ` | Pull from prod, preserve local changes |
89- | ` npm run pull:prod:force ` | Pull from prod, overwrite everything |
90- | ` npm run push:dev ` | Push local files to Vapi (dev) |
91- | ` npm run push:stg ` | Push local files to Vapi (staging) |
92- | ` npm run push:prod ` | Push local files to Vapi (prod) |
93- | ` npm run apply:dev ` | Pull → Merge → Push in one shot (dev) |
94- | ` npm run apply:stg ` | Pull → Merge → Push in one shot (staging) |
95- | ` npm run apply:prod ` | Pull → Merge → Push in one shot (prod) |
96- | ` npm run push:dev assistants ` | Push only assistants (dev) |
97- | ` npm run push:dev tools ` | Push only tools (dev) |
98- | ` npm run call:dev -- -a <name> ` | Start a WebSocket call to an assistant (dev) |
99- | ` npm run call:dev -- -s <name> ` | Start a WebSocket call to a squad (dev) |
100- | ` npm run mock:webhook ` | Run local webhook receiver for Vapi server messages |
82+ | Command | Description |
83+ | ------------------------------- | --------------------------------------------------- |
84+ | ` npm run build ` | Type-check the codebase |
85+ | ` npm run pull:dev ` | Pull platform state, preserve local changes |
86+ | ` npm run pull:stg ` | Pull staging state, preserve local changes |
87+ | ` npm run pull:dev:force ` | Pull platform state, overwrite everything |
88+ | ` npm run pull:stg:force ` | Pull staging state, overwrite everything |
89+ | ` npm run pull:prod ` | Pull from prod, preserve local changes |
90+ | ` npm run pull:prod:force ` | Pull from prod, overwrite everything |
91+ | ` npm run push:dev ` | Push local files to Vapi (dev) |
92+ | ` npm run push:stg ` | Push local files to Vapi (staging) |
93+ | ` npm run push:prod ` | Push local files to Vapi (prod) |
94+ | ` npm run apply:dev ` | Pull → Merge → Push in one shot (dev) |
95+ | ` npm run apply:stg ` | Pull → Merge → Push in one shot (staging) |
96+ | ` npm run apply:prod ` | Pull → Merge → Push in one shot (prod) |
97+ | ` npm run push:dev assistants ` | Push only assistants (dev) |
98+ | ` npm run push:dev tools ` | Push only tools (dev) |
99+ | ` npm run call:dev -- -a <name> ` | Start a WebSocket call to an assistant (dev) |
100+ | ` npm run call:dev -- -s <name> ` | Start a WebSocket call to a squad (dev) |
101+ | ` npm run mock:webhook ` | Run local webhook receiver for Vapi server messages |
101102
102103### Basic Workflow
103104
@@ -242,11 +243,13 @@ ngrok http 8787
242243```
243244
244245Then set your assistant ` server.url ` to the ngrok HTTPS URL and include event types like:
246+
245247- ` speech-update `
246248- ` status-update `
247249- ` end-of-call-report `
248250
249251The mock server exposes:
252+
250253- ` POST /webhook ` (or ` POST / ` )
251254- ` GET /health `
252255- ` GET /events `
@@ -319,19 +322,23 @@ firstMessage: Hello! How can I help you?
319322---
320323
321324# Identity & Purpose
322- You are a helpful assistant for Acme Corp.
325+
326+ You are a helpful assistant for the business you represent.
323327
324328# Conversation Flow
329+
3253301 . Greet the user
3263312 . Ask how you can help
3273323 . Resolve their issue
328333
329334# Rules
335+
330336- Always be polite
331337- Never make up information
332338```
333339
334340** Benefits:**
341+
335342- System prompts are readable Markdown (not escaped YAML strings)
336343- Proper syntax highlighting in editors
337344- Easy to write headers, lists, tables
@@ -405,13 +412,15 @@ members:
405412# ## Simulations
406413
407414**Personality** (`simulations/personalities/`):
415+
408416` ` ` yaml
409417name: Skeptical Sam
410418description: A doubtful caller who questions everything
411419prompt: You are skeptical and need convincing before trusting information.
412420` ` `
413421
414422**Scenario** (`simulations/scenarios/`):
423+
415424` ` ` yaml
416425name: Happy Path - New Customer
417426description: New customer calling to schedule an appointment
@@ -421,13 +430,15 @@ prompt: |
421430` ` `
422431
423432**Simulation** (`simulations/tests/`):
433+
424434` ` ` yaml
425435name: Booking Test Case 1
426436personalityId: skeptical-sam
427437scenarioId: happy-path-new-customer
428438` ` `
429439
430440**Simulation Suite** (`simulations/suites/`):
441+
431442` ` ` yaml
432443name: Booking Flow Tests
433444simulationIds:
@@ -460,6 +471,7 @@ model:
460471---
461472
462473# Your System Prompt Here
474+
463475Instructions for the assistant...
464476` ` `
465477
@@ -511,23 +523,23 @@ Use the **filename without extension** as the resource ID:
511523# In an assistant
512524model:
513525 toolIds:
514- - my-tool # → resources/<env>/tools/my-tool.yml
515- - utils/helper-tool # → resources/<env>/tools/utils/helper-tool.yml
526+ - my-tool # → resources/<env>/tools/my-tool.yml
527+ - utils/helper-tool # → resources/<env>/tools/utils/helper-tool.yml
516528artifactPlan:
517529 structuredOutputIds:
518- - call-summary # → resources/<env>/structuredOutputs/call-summary.yml
530+ - call-summary # → resources/<env>/structuredOutputs/call-summary.yml
519531` ` `
520532
521533` ` ` yaml
522534# In a squad
523535members:
524- - assistantId: intake-agent # → resources/<env>/assistants/intake-agent.md
536+ - assistantId: intake-agent # → resources/<env>/assistants/intake-agent.md
525537` ` `
526538
527539` ` ` yaml
528540# In a simulation
529- personalityId: skeptical-sam # → resources/<env>/simulations/personalities/skeptical-sam.yml
530- scenarioId: happy-path # → resources/<env>/simulations/scenarios/happy-path.yml
541+ personalityId: skeptical-sam # → resources/<env>/simulations/personalities/skeptical-sam.yml
542+ scenarioId: happy-path # → resources/<env>/simulations/scenarios/happy-path.yml
531543` ` `
532544
533545# ## How to Delete a Resource
@@ -537,27 +549,28 @@ scenarioId: happy-path # → resources/<env>/simulations/scenarios/hap
5375493. **Push** : ` npm run push:dev`
538550
539551The engine will :
552+
540553- Detect the resource is in state but not in filesystem
541554- Check for orphan references (will error if still referenced)
542555- Delete from Vapi
543556- Remove from state file
544557
545558# ## How to Organize Resources into Folders
546559
547- Create subdirectories for multi-tenant or feature organization :
560+ Create subdirectories only when they help organize related resources by feature or workflow :
548561
549562` ` `
550563resources/<env>/
551564├── assistants/
552565│ ├── shared/
553566│ │ └── fallback.md
554- │ └── client-a /
555- │ └── support .md
567+ │ └── support /
568+ │ └── intake .md
556569├── tools/
557570│ ├── shared/
558571│ │ └── transfer-call.yml
559- │ └── client-a /
560- │ └── custom-api .yml
572+ │ └── support /
573+ │ └── lookup-customer .yml
561574` ` `
562575
563576Reference using full paths :
@@ -566,7 +579,7 @@ Reference using full paths:
566579model:
567580 toolIds:
568581 - shared/transfer-call
569- - client-a/custom-api
582+ - support/lookup-customer
570583` ` `
571584
572585---
@@ -597,6 +610,7 @@ files
597610# ## Processing Order
598611
599612**Pull** (dependency order):
613+
6006141. Tools
6016152. Structured Outputs
6026163. Assistants
@@ -607,12 +621,14 @@ files
6076218. Simulation Suites
608622
609623**Push** (dependency order):
624+
6106251. Tools → 2. Structured Outputs → 3. Assistants → 4. Squads
611- 5 . Personalities → 6. Scenarios → 7. Simulations → 8. Simulation Suites
626+ 2 . Personalities → 6. Scenarios → 7. Simulations → 8. Simulation Suites
612627
613628**Delete** (reverse dependency order):
629+
6146301. Simulation Suites → 2. Simulations → 3. Scenarios → 4. Personalities
615- 5 . Squads → 6. Assistants → 7. Structured Outputs → 8. Tools
631+ 2 . Squads → 6. Assistants → 7. Structured Outputs → 8. Tools
616632
617633# ## Reference Resolution
618634
@@ -642,7 +658,7 @@ Credentials (API keys, JWT secrets, etc.) are environment-specific and managed a
642658# Resource file stores credential NAME (environment-agnostic)
643659server:
644660 url: https://my-api.com/endpoint
645- credentialId: my-server-credential # ← human-readable name
661+ credentialId: my-server-credential # ← human-readable name
646662` ` `
647663
648664` ` ` json
@@ -696,10 +712,10 @@ Tracks mapping between resource IDs and Vapi UUIDs:
696712
697713# ## Environment Variables
698714
699- | Variable | Required | Description |
700- |----------| ----------| -------------|
701- | `VAPI_TOKEN` | ✅ | API authentication token |
702- | `VAPI_BASE_URL` | ❌ | API base URL (defaults to `https://api.vapi.ai`) |
715+ | Variable | Required | Description |
716+ | --------------- | -------- | ------------------------------------------------ |
717+ | `VAPI_TOKEN` | ✅ | API authentication token |
718+ | `VAPI_BASE_URL` | ❌ | API base URL (defaults to `https://api.vapi.ai`) |
703719
704720# ## Excluded Fields
705721
@@ -716,6 +732,7 @@ Some fields are excluded when writing to files (server-managed):
716732# ## "Reference not found" warnings
717733
718734The referenced resource doesn't exist. Check :
735+
7197361. File exists in correct folder
7207372. Filename matches exactly (case-sensitive)
7217383. Using filename without extension
@@ -731,13 +748,15 @@ The referenced resource doesn't exist. Check:
731748# ## Resource not updating
732749
733750Check the state file has correct UUID :
751+
7347521. Open `.vapi-state.{env}.json`
7357532. Find the resource entry
7367543. If incorrect, delete entry and re-run push
737755
738756# ## "Credential with ID not found" errors
739757
740758The credential UUID doesn't exist in the target environment. Fix :
759+
7417601. Run `npm run pull:{env}` to fetch credentials into the state file
7427612. If the credential doesn't exist in the target org, create it in the Vapi dashboard with the same name
7437623. Pull again — the mapping will be auto-populated
0 commit comments