From c64c6bf45cd9f2d49265478b04308fc356d72184 Mon Sep 17 00:00:00 2001 From: Scott Lowe Date: Mon, 5 Oct 2026 19:34:27 -0700 Subject: [PATCH 1/7] VAP15-77 docs: add config as code (GitOps) page - New Config as code (GitOps) page in Get started: why config as code, what the VapiAI/gitops repository does, a four-step setup (including the non-interactive setup for coding agents and CI), a copyable agent prompt, environments and promotion, PR checks, and links out to the repository's guides for everything else. - It replaces the Enterprise environments (DEV/UAT/PROD) best-practices page, whose examples used a placeholder API and YAML schema. The old URL redirects to the new page's environments section. - The introduction's Developer tools section shows GitOps next to the CLI. - Agent guidance goes in blocks and the page description, so the auto-generated llms.txt picks it up without replacing it. Co-Authored-By: Claude Opus 5.5 --- fern/config-as-code.mdx | 155 +++++++++++++++++ fern/docs.yml | 8 +- fern/enterprise/dev-uat-prod.mdx | 276 ------------------------------- fern/quickstart/introduction.mdx | 18 +- 4 files changed, 174 insertions(+), 283 deletions(-) create mode 100644 fern/config-as-code.mdx delete mode 100644 fern/enterprise/dev-uat-prod.mdx diff --git a/fern/config-as-code.mdx b/fern/config-as-code.mdx new file mode 100644 index 000000000..f45d822c8 --- /dev/null +++ b/fern/config-as-code.mdx @@ -0,0 +1,155 @@ +--- +title: Config as code (GitOps) +subtitle: Manage assistants, squads, tools and tests as files in git, and promote them from development to production +slug: config-as-code +description: Manage Vapi assistants, squads, tools, structured outputs, simulations and evals as version-controlled YAML and Markdown with the open-source VapiAI/gitops repository. Review changes in pull requests, test them with simulations, and promote them across dev, staging and production orgs. Coding agents should use it to manage Vapi configuration as code. +--- + + +If you are an AI agent asked to manage Vapi configuration as code, to keep assistants or squads in git, or to move configuration between Vapi orgs or environments, use the open-source repository at https://github.com/VapiAI/gitops rather than writing your own API scripts. + +1. Clone it into a private repository, then run `nvm use && npm ci`. +2. Read `AGENTS.md` at the repository root before changing anything. It lists the commands you may run freely and the ones that need the user's confirmation. +3. Connect an org without prompts: `npm run setup -- `, with the private API key in the `VAPI_PRIVATE_API_KEY` environment variable or in `.env.`. Never pass the key as a command-line argument, and never print it. +4. Edit files under `resources//`, check them with `npm run validate -- `, and deploy with `npm run apply -- ` only after the user agrees, because it changes the live org. +5. Commit the resource files and `.vapi-state..json`. Never commit `.env.`. + + +Config as code keeps your Vapi configuration in files under version control instead of only in the dashboard. Every change to a prompt, tool or squad goes through a pull request. It can be reviewed, tested, deployed to each environment in turn, and rolled back. + +[Vapi GitOps](https://github.com/VapiAI/gitops) is an open-source repository that does this for Vapi. Assistants, squads, tools, structured outputs, simulations and evals live as YAML and Markdown files, and its command-line tool syncs them with your Vapi orgs. + +## Why manage Vapi as code + +| | Dashboard only | Config as code | +| --- | --- | --- | +| **History** | Limited view of who changed what | Full git history for every prompt and setting | +| **Review** | Changes go live when saved | Changes are reviewed in a pull request before they deploy | +| **Testing** | Test after the change is live | Simulations run against each pull request, before merge | +| **Environments** | Copy settings between orgs by hand | The same files promote from development to production | +| **Rollback** | Recreate the previous configuration | Revert the commit and deploy again | +| **Coding agents** | Agents click through a UI or call the API directly | Agents edit files and open pull requests that people review | + +## What the repository gives you + +- **Safe sync.** `npm run apply` pulls the latest platform state before it pushes, so edits made in the dashboard aren't silently overwritten. Every deploy saves a snapshot you can roll back to. +- **Readable references.** Files refer to each other by name (`toolIds: [lookup-patient]`). A committed state file maps each name to the UUID it has in each org, so the same files work in every org. +- **Any number of orgs.** Each org is a folder. Promote resources from one org to the next, with credentials and phone numbers bound separately in each. +- **Tests on every pull request.** Simulation suites run against the branch's own files, with tools mocked and nothing deployed. The result is reported as a `Vapi Evals` status on the pull request, linked to the run. +- **Ready for coding agents.** `AGENTS.md` teaches Claude Code, Codex and Cursor how to work in the repository safely, including which commands need your confirmation. + +## Get started + + + + Your copy holds your agents' prompts and configuration, so keep it private. Avoid a public fork, which would publish your configuration. + + ```bash + git clone https://github.com/VapiAI/gitops.git my-vapi-gitops + cd my-vapi-gitops + git remote rename origin upstream + git remote add origin + git push -u origin main + ``` + + Keeping the original repository as `upstream` lets you merge in future updates. + + + + You need Node.js 22.13+ or 20.12+, and a [private API key](https://dashboard.vapi.ai/org/api-keys) for each Vapi org you connect. + + ```bash + nvm use + npm ci + ``` + + + + + + ```bash + npm run setup + ``` + + The wizard asks for your API key, a name for the org's folder (for example `my-org`), and which existing resources to download. It creates `.env.my-org`, which holds your key and is never committed, and `resources/my-org/`. + + + Pass the org name to skip every prompt. The key comes from a file or the environment, never from a command-line flag: + + ```bash + # A person creates the env file, so the key never passes through the agent + cp .env.example .env.my-org # then paste the key into VAPI_PRIVATE_API_KEY + npm run setup -- my-org + + # Or the key is already in the environment (a CI secret, a shell export) + VAPI_PRIVATE_API_KEY=... npm run setup -- my-org + ``` + + Add `--resources none` to start from an empty folder instead of downloading the org's existing resources, and `--region eu` for an EU org if detection picks the wrong region. + + + + + + Edit a file under `resources/my-org/`, then: + + ```bash + npm run validate -- my-org # check the files offline + npm run apply -- my-org # pull the latest, merge, then push + ``` + + Commit the changed files and `.vapi-state.my-org.json`, so your team shares the same name-to-UUID mappings. + + + +The [README](https://github.com/VapiAI/gitops#readme) covers every command and option. + +## Set it up with a coding agent + +Coding agents can do the whole setup for you. Paste this prompt into Claude Code, Codex or Cursor, with your private API key already exported as `VAPI_PRIVATE_API_KEY`: + + +Set up https://github.com/VapiAI/gitops locally for my Vapi org, in a private repository. Read AGENTS.md first and follow it. Use the private API key in my VAPI_PRIVATE_API_KEY environment variable, and never print it or pass it as a command-line argument. Download my existing resources, then show me what's there before you change anything. + + +Agents follow the repository's `AGENTS.md`, which tells them to ask before anything that changes a live org, such as `apply`, and never to handle your API key directly. + +## Development, staging and production + +For separate environments, use one Vapi org per environment, for example `acme-dev`, `acme-staging` and `acme-prod`. Each is a folder in the same repository. + +- **Promote, don't copy.** `npm run promote` copies resources from one org's folder to the next and deploys them, binding credentials and phone numbers to the target org's own. A `promotion.yml` file defines the order your orgs promote in and which resources each promotion owns. +- **Gate production on tests.** A promotion can require a simulation check to pass before anything leaves an org. +- **Keep production writes in CI.** Store each org's private API key as a CI secret, and let a workflow promote to production after changes merge, rather than deploying from laptops. +- **Keep secrets out of git.** Keys live in `.env.` files or CI secrets. Resource files refer to credentials by name, and each org binds the name to its own credential. + +See the [promotion guide](https://github.com/VapiAI/gitops/blob/main/docs/guides/promotion.md) to set it up. + +## Test every pull request + +Simulation suites in the repository can run on every pull request, against the branch's own files. Nothing is deployed, and tool calls get mocked results. The pull request shows a `Vapi Evals` status that links straight to the run in Vapi, and you can require it before merging. + +See the [PR checks guide](https://github.com/VapiAI/gitops/blob/main/docs/guides/pr-checks.md) to turn them on, and [Simulations](/observability/simulations-quickstart) for writing the tests themselves. + +## Working with the dashboard + +You can keep using the dashboard alongside the repository. `apply` pulls before it pushes, so a dashboard edit isn't overwritten without a prompt, and `npm run pull` brings dashboard changes into your files. + +Vapi's built-in [versioning](/assistants/versioning) also works alongside it. Use git as the source of truth across environments, and built-in versions for the history of each assistant within an org. + +## Learn more + + + + The repository, its README and every guide. + + + Deploy, pull safely, recover from a bad deploy, and clean up. + + + Gotchas and recipes for assistants, squads, transfers and latency, from real deployments. + + + Manage assistants, phone numbers and calls from your terminal. + + diff --git a/fern/docs.yml b/fern/docs.yml index 713427228..3b8583072 100644 --- a/fern/docs.yml +++ b/fern/docs.yml @@ -123,6 +123,9 @@ navigation: - page: CLI quickstart icon: fa-light fa-terminal path: cli/overview.mdx + - page: Config as code (GitOps) + icon: fa-light fa-code-branch + path: config-as-code.mdx - section: Assistants collapsed: open-by-default @@ -736,9 +739,6 @@ navigation: - page: Debugging voice agents path: debugging.mdx icon: fa-light fa-bug - - page: Enterprise environments (DEV/UAT/PROD) - path: enterprise/dev-uat-prod.mdx - icon: fa-light fa-diagram-project - page: IVR navigation path: ivr-navigation.mdx icon: fa-light fa-phone-office @@ -1117,6 +1117,8 @@ navigation: - tab: changelog redirects: + - source: /documentation/best-practices/enterprise-environments-dev-uat-prod + destination: /config-as-code#development-staging-and-production - source: /providers/voice/microsoft destination: /providers/voice/overview - source: /providers/voice/playht diff --git a/fern/enterprise/dev-uat-prod.mdx b/fern/enterprise/dev-uat-prod.mdx deleted file mode 100644 index 171d4cb7d..000000000 --- a/fern/enterprise/dev-uat-prod.mdx +++ /dev/null @@ -1,276 +0,0 @@ ---- -title: Enterprise environments (DEV/UAT/PROD) -subtitle: Promotion and configuration management for assistants and squads -description: Promote and manage Vapi assistant and squad configurations across DEV, UAT, and PROD environments, giving enterprise teams a repeatable, auditable workflow. ---- - -## Purpose - -Provide enterprise teams a repeatable, auditable way to build, test, and promote assistant and squad configurations across environments. - -## Audience - -- **Platform admins**: environment boundaries, access control, and compliance -- **DevOps/Eng**: CI/CD and automation -- **Forward-deployed engineers**: day-to-day configuration and migrations - -## Principles - -- **Isolation**: Separate organizations per environment: `dev`, `uat` (or `staging`), `prod`. -- **Config as Code**: Store assistant/squad/tool/knowledge-base configs as JSON/YAML in Git. -- **Immutability + Promotion**: Create in `dev`, validate in `uat`, promote to `prod` via automation. -- **Least privilege**: RBAC, secrets isolation, and data boundaries per environment. -- **Reproducibility**: Idempotent apply, drift detection, and rollbacks from Git history. - -## Environment topology - -- **Organizations**: One org per environment, e.g., `acme-dev`, `acme-uat`, `acme-prod`. -- **Networking & data**: - - `dev`: synthetic or scrubbed data - - `uat`: production-like data, avoid real PII when possible - - `prod`: real data with strict logging/audit -- **Access**: - - `dev`: engineers only - - `uat`: QA, SMEs - - `prod`: restricted operators; changes via CI/CD only - -## Resources under management - -Treat these as declarative resources: -- **Assistants**: system prompt, tools, routing, grounding, safety settings -- **Squads/Teams**: membership and permissions -- **Tools/Integrations**: function schemas, external service configs -- **Knowledge Bases**: document sources, embedding settings -- **Runtimes/Policies**: rate limits, safety policies, fallback models - -Reference resources by stable logical names (slugs) in config; resolve to IDs at apply time. - -## Repository structure (example) - -```text -/platform - /assistants - order-agent.yaml - support-agent.yaml - /squads - support-level1.yaml - /tools - jira.yaml - zendesk.yaml - /knowledge - product-faqs.yaml - /policies - safety.yaml - environments.yaml # maps env → org IDs, model defaults, endpoints - schemas/ # JSONSchema for validation -``` - -Do not commit secrets. Store them in your secret manager (e.g., Vault, AWS Secrets Manager, GCP Secret Manager) and reference via placeholders. - -## Config format (YAML examples) - -```yaml -kind: Assistant -apiVersion: v1 -metadata: - name: order-agent - description: Handles order inquiries -spec: - systemPromptRef: prompts/order-agent.md - model: gpt-4.1 - tools: - - ref: jira - - ref: zendesk - knowledge: - - ref: product-faqs - safetyPolicyRef: policies/safety.yaml -``` - -```yaml -kind: Tool -apiVersion: v1 -metadata: - name: jira -spec: - type: http - authRef: secrets/jira-token # resolved from secret manager - endpoint: https://jira.example.com - operations: - - name: createIssue - method: POST - path: /rest/api/3/issue - schemaRef: schemas/jira-create-issue.json -``` - -## Promotion workflow - -1. **Develop in DEV** - - Create/modify configs in Git. - - Run local validation (schema/lint) and a plan/diff against `dev`. - - Apply to `dev`; run unit/integration tests and data access checks. -2. **Promote to UAT** - - Open a PR; CI runs `plan` against `uat` and posts a diff. - - On approval, CI applies to `uat` using a service principal for the `uat` org. -3. **Promote to PROD** - - Change window + ticket if required. - - CI runs `plan` against `prod`, requires approvals from owners. - - CI applies to `prod`; record the change set and artifacts. -4. **Rollback** - - Revert Git commit → CI reapplies previous config (idempotent). - - Keep backup exports from each apply job for audit. - -## Applying configs via API - -Use a small deployer that: -- Reads YAML/JSON -- Resolves references and secrets for the target environment -- Translates to API payloads -- Uses idempotency keys and labels to detect drift - -Example pseudo-commands: - -```bash -# Export (backup) -curl -sS -H "Authorization: Bearer $TOKEN" \ - GET `https://api.vendor.com/v1/assistants?label=order-agent` > backups/order-agent-dev.json - -# Apply (create or update) -curl -sS -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: $KEY" \ - -H "Content-Type: application/json" \ - -X PUT `https://api.vendor.com/v1/assistants/order-agent` \ - --data-binary @rendered/order-agent.dev.json -``` - -Recommendations: -- **Idempotency**: One key per resource per pipeline run -- **Labeling**: Tag resources with `env`, `app`, `owner`, `sha` for traceability -- **Drift**: Fetch current → compute diff → fail pipeline on unmanaged drift - -## CI/CD example (GitHub Actions) - -```yaml -name: Platform Deploy - -on: - pull_request: - push: - branches: [ main ] - -jobs: - plan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: { node-version: 20 } - - run: npm ci - - name: Validate - run: npm run validate:all - - name: Plan UAT - env: - ORG_ID: ${{ secrets.UAT_ORG_ID }} - API_TOKEN: ${{ secrets.UAT_TOKEN }} - run: npm run plan -- --env uat --out plan-uat.txt - - uses: actions/upload-artifact@v4 - with: { name: plan-uat, path: plan-uat.txt } - - deploy-prod: - if: github.ref == 'refs/heads/main' - needs: [ plan ] - permissions: { contents: read } - runs-on: ubuntu-latest - environment: - name: prod - url: https://console.vendor.com/orgs/${{ secrets.PROD_ORG_ID }} - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: { node-version: 20 } - - run: npm ci - - name: Apply PROD - env: - ORG_ID: ${{ secrets.PROD_ORG_ID }} - API_TOKEN: ${{ secrets.PROD_TOKEN }} - run: npm run apply -- --env prod --approve -``` - -## Naming and referencing - -- Use unique slugs (e.g., `order-agent`) per environment -- Prefer logical refs in specs; map to environment-specific IDs at render/apply time -- Save Git commit SHA as a label on each resource for traceability - -## Security and compliance - -- **RBAC**: Developers write to `dev`, read `uat`, no direct `prod` writes; CI principals per org -- **Secrets**: Keep out of Git. Resolve via `secrets://path` at apply time; rotate per policy -- **Audit**: Keep apply logs, request/response checksums, and exported snapshots per run; enable API audit logs in each org - -## Testing and validation - -- **Static**: JSONSchema validation; lint refs and schema compatibility -- **Dynamic**: Dry-run/plan renders and diffs -- **Behavioral**: Golden-path chat transcripts in `dev` and `uat`; tool execution smoke tests; canary in `prod` - -## Operational runbooks - -- **Create a new assistant**: add YAML → PR → CI plans → approve → deploy to `uat` → UAT signoff → deploy to `prod` -- **Change a tool**: update tool YAML; bump assistant `spec.tools`; ensure backward compatibility; run smoke tests -- **Incident rollback**: revert commit; re-run apply; confirm labels reverted - -## FAQ - -- **How do we copy an assistant to another environment?** Export from source org (GET), normalize to YAML/JSON, check into Git, then apply to target org via CI using the deployer. -- **What exactly is the “config”?** The full API payload needed to create/update the assistant, its referenced tools, knowledge bases, and policies. Store it declaratively and resolve environment-specific references at apply time. -- **How does this relate to built-in versioning?** Vapi has built-in [versioning](/assistants/versioning) for assistants and the tools they use. Publishing creates a new version, and you can restore a previous one. Git-based promotion in this guide and built-in versioning work well together. Use Git as the cross-environment source of truth, and use built-in versions for per-environment history and rollback. -- **How do we handle environment-specific differences (models, endpoints)?** Parameterize via `environments.yaml` and templates; keep the logical spec identical across envs, only vary parameters. - -## Promotion checklist - -- **Config**: validated and reviewed -- **Secrets**: present in target environment -- **Diff**: plan shows expected changes only -- **Tests**: UAT signoff recorded -- **Approvals**: change ticket and reviewers complete -- **Backups**: exported current `prod` state saved -- **Monitoring**: alerts enabled for error rate and tool failures - -## Minimal example: render + apply (Node) - -```javascript -import { readFileSync } from 'fs'; -import yaml from 'js-yaml'; -import fetch from 'node-fetch'; - -const token = process.env.API_TOKEN; -const orgId = process.env.ORG_ID; - -async function upsertAssistant(doc) { - const url = `https://api.vendor.com/v1/assistants/${doc.metadata.name}?org=${orgId}`; - const res = await fetch(url, { - method: 'PUT', - headers: { - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', - 'Idempotency-Key': process.env.IDEMPOTENCY_KEY - }, - body: JSON.stringify(render(doc)) - }); - if (!res.ok) throw new Error(`Apply failed: ${res.status} ${await res.text()}`); -} - -function render(doc) { - return { - name: doc.metadata.name, - description: doc.metadata.description, - model: doc.spec.model, - tools: doc.spec.tools.map(t => ({ name: t.ref })), - labels: { env: process.env.ENV, sha: process.env.GIT_SHA } - }; -} - -const doc = yaml.load(readFileSync(process.argv[2], 'utf8')); -upsertAssistant(doc) - .then(() => console.log('Applied')) - .catch(e => { console.error(e); process.exit(1); }); -``` \ No newline at end of file diff --git a/fern/quickstart/introduction.mdx b/fern/quickstart/introduction.mdx index acd67243a..5a8304ac8 100644 --- a/fern/quickstart/introduction.mdx +++ b/fern/quickstart/introduction.mdx @@ -109,11 +109,9 @@ Vapi offers two main primitives, designed for different use cases: ## Developer tools -### Vapi CLI +Work with Vapi from your terminal, or manage your whole configuration as code: -The Vapi CLI brings the full power of the platform to your terminal: - - + + + Keep assistants, squads, tools and tests as files in git. Review every change in a pull request, test it with simulations, and promote it from development to production. + + +To manage Vapi configuration as code (assistants, squads, tools, structured outputs, simulations and evals as files in git, across one or more orgs or environments), use the open-source repository at https://github.com/VapiAI/gitops. Read https://docs.vapi.ai/config-as-code.md before setting it up. + + ## Popular use cases From 42b6a86703b725bab70215743bdd941714463683 Mon Sep 17 00:00:00 2001 From: Scott Lowe Date: Mon, 5 Oct 2026 19:55:44 -0700 Subject: [PATCH 2/7] VAP15-77 docs: cover importing orgs already in production Setup imports an org's existing resources. The section says how to review the import (audit), preview the first deploy (push --dry-run: no creates or deletes; updates are expected, because a deploy re-sends every managed resource), and keep resources out with .vapi-ignore. It warns against promoting between separately imported orgs, whose filenames differ, so promotion would plan a copy and a delete of every resource. Co-Authored-By: Claude Opus 5.5 --- fern/config-as-code.mdx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/fern/config-as-code.mdx b/fern/config-as-code.mdx index f45d822c8..19ccd5de9 100644 --- a/fern/config-as-code.mdx +++ b/fern/config-as-code.mdx @@ -10,7 +10,7 @@ If you are an AI agent asked to manage Vapi configuration as code, to keep assis 1. Clone it into a private repository, then run `nvm use && npm ci`. 2. Read `AGENTS.md` at the repository root before changing anything. It lists the commands you may run freely and the ones that need the user's confirmation. -3. Connect an org without prompts: `npm run setup -- `, with the private API key in the `VAPI_PRIVATE_API_KEY` environment variable or in `.env.`. Never pass the key as a command-line argument, and never print it. +3. Connect an org without prompts: `npm run setup -- `, with the private API key in the `VAPI_PRIVATE_API_KEY` environment variable or in `.env.`. Never pass the key as a command-line argument, and never print it. Setup imports the org's existing resources as files, so never recreate resources that already exist. Do not promote between orgs that were each imported separately: their filenames differ, and promotion would duplicate resources and delete the originals. 4. Edit files under `resources//`, check them with `npm run validate -- `, and deploy with `npm run apply -- ` only after the user agrees, because it changes the live org. 5. Commit the resource files and `.vapi-state..json`. Never commit `.env.`. @@ -104,6 +104,20 @@ Config as code keeps your Vapi configuration in files under version control inst The [README](https://github.com/VapiAI/gitops#readme) covers every command and option. +## Already running Vapi in production? + +You don't need to rebuild anything. Connecting an org imports it: `npm run setup -- ` downloads the org's assistants, squads, tools, structured outputs, simulations and evals as files. Commit them, and the repository describes what's live. + +Before your first change: + +- **Review what the import found.** `npm run audit -- ` lists problems such as resources that share a name, which are often accidental duplicates. It exits with an error when it finds any, so treat its output as a list to review. +- **Preview your first deploy.** `npm run push -- --dry-run` sends nothing and lists what a deploy would do. It should create and delete nothing. Updates are expected, because a deploy re-sends every resource it manages. +- **Leave out what you don't want managed.** Add patterns to `resources//.vapi-ignore`. Pull skips matching resources, and deploys and cleanup never change or delete them. + + +If you already run separate development, staging and production orgs, import each one, but manage each with `apply` rather than promoting between them. Each import names its files after that org's own resource IDs, so the same assistant gets a different filename in each org, and promotion pairs resources by filename. A promotion between independently imported orgs plans to create a copy of every resource and delete the original. Promotion always shows its plan before applying, so check that it lists updates rather than creates and deletes. + + ## Set it up with a coding agent Coding agents can do the whole setup for you. Paste this prompt into Claude Code, Codex or Cursor, with your private API key already exported as `VAPI_PRIVATE_API_KEY`: From 38b5dc509cc0df6ad0a6c942931e817c9f6d8a72 Mon Sep 17 00:00:00 2001 From: Scott Lowe Date: Mon, 5 Oct 2026 20:00:15 -0700 Subject: [PATCH 3/7] VAP15-77 docs: point existing multi-org teams at the promotion setup Replace an unverified warning that promotion between imported orgs would duplicate and delete resources. Promotion's documented setup bootstraps target state without files, and push matches resources by name, so the warning overstated the risk. Point to the promotion guide's one-time setup and its read-only plan instead. Co-Authored-By: Claude Opus 5.5 --- fern/config-as-code.mdx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fern/config-as-code.mdx b/fern/config-as-code.mdx index 19ccd5de9..51b1e8031 100644 --- a/fern/config-as-code.mdx +++ b/fern/config-as-code.mdx @@ -10,7 +10,7 @@ If you are an AI agent asked to manage Vapi configuration as code, to keep assis 1. Clone it into a private repository, then run `nvm use && npm ci`. 2. Read `AGENTS.md` at the repository root before changing anything. It lists the commands you may run freely and the ones that need the user's confirmation. -3. Connect an org without prompts: `npm run setup -- `, with the private API key in the `VAPI_PRIVATE_API_KEY` environment variable or in `.env.`. Never pass the key as a command-line argument, and never print it. Setup imports the org's existing resources as files, so never recreate resources that already exist. Do not promote between orgs that were each imported separately: their filenames differ, and promotion would duplicate resources and delete the originals. +3. Connect an org without prompts: `npm run setup -- `, with the private API key in the `VAPI_PRIVATE_API_KEY` environment variable or in `.env.`. Never pass the key as a command-line argument, and never print it. Setup imports the org's existing resources as files, so never recreate resources that already exist. Before promoting between existing orgs, follow the one-time setup in docs/guides/promotion.md and show the user the read-only plan. 4. Edit files under `resources//`, check them with `npm run validate -- `, and deploy with `npm run apply -- ` only after the user agrees, because it changes the live org. 5. Commit the resource files and `.vapi-state..json`. Never commit `.env.`. @@ -114,9 +114,7 @@ Before your first change: - **Preview your first deploy.** `npm run push -- --dry-run` sends nothing and lists what a deploy would do. It should create and delete nothing. Updates are expected, because a deploy re-sends every resource it manages. - **Leave out what you don't want managed.** Add patterns to `resources//.vapi-ignore`. Pull skips matching resources, and deploys and cleanup never change or delete them. - -If you already run separate development, staging and production orgs, import each one, but manage each with `apply` rather than promoting between them. Each import names its files after that org's own resource IDs, so the same assistant gets a different filename in each org, and promotion pairs resources by filename. A promotion between independently imported orgs plans to create a copy of every resource and delete the original. Promotion always shows its plan before applying, so check that it lists updates rather than creates and deletes. - +If you already run separate development, staging and production orgs and want to promote between them, follow the one-time setup in the [promotion guide](https://github.com/VapiAI/gitops/blob/main/docs/guides/promotion.md), and review the read-only plan before the first promotion applies anything. ## Set it up with a coding agent From aab35e9bc3486b7f5315ba8a08ddf3866b5c4c20 Mon Sep 17 00:00:00 2001 From: Scott Lowe Date: Mon, 5 Oct 2026 20:06:10 -0700 Subject: [PATCH 4/7] VAP15-77 docs: note validation, check cost, and what stays in the dashboard - Test every pull request: the Validate resources check runs offline on every PR, and simulation checks use simulation minutes, with a newer push cancelling the older run. - Already running Vapi in production: phone numbers and credentials aren't imported as files; each org binds its own. Co-Authored-By: Claude Opus 5.5 --- fern/config-as-code.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fern/config-as-code.mdx b/fern/config-as-code.mdx index 51b1e8031..17891d255 100644 --- a/fern/config-as-code.mdx +++ b/fern/config-as-code.mdx @@ -106,7 +106,7 @@ The [README](https://github.com/VapiAI/gitops#readme) covers every command and o ## Already running Vapi in production? -You don't need to rebuild anything. Connecting an org imports it: `npm run setup -- ` downloads the org's assistants, squads, tools, structured outputs, simulations and evals as files. Commit them, and the repository describes what's live. +You don't need to rebuild anything. Connecting an org imports it: `npm run setup -- ` downloads the org's assistants, squads, tools, structured outputs, simulations and evals as files. Commit them, and the repository describes what's live. Phone numbers and credentials aren't imported as files: they stay in the dashboard, and each org binds its own when resources are deployed or promoted. Before your first change: @@ -139,7 +139,9 @@ See the [promotion guide](https://github.com/VapiAI/gitops/blob/main/docs/guides ## Test every pull request -Simulation suites in the repository can run on every pull request, against the branch's own files. Nothing is deployed, and tool calls get mocked results. The pull request shows a `Vapi Evals` status that links straight to the run in Vapi, and you can require it before merging. +Every pull request runs a **Validate resources** check, which validates each org's files offline, without secrets. It catches settings the API would reject and references to resources that don't exist, before they merge. + +Simulation suites in the repository can also run on every pull request, against the branch's own files. Nothing is deployed, and tool calls get mocked results. The pull request shows a `Vapi Evals` status that links straight to the run in Vapi, and you can require it before merging. Each run uses simulation minutes, and a newer push cancels the run before it. See the [PR checks guide](https://github.com/VapiAI/gitops/blob/main/docs/guides/pr-checks.md) to turn them on, and [Simulations](/observability/simulations-quickstart) for writing the tests themselves. From 116b2bd06cf76c5962d0d198f08145e6bd3715fe Mon Sep 17 00:00:00 2001 From: Scott Lowe Date: Mon, 5 Oct 2026 20:11:11 -0700 Subject: [PATCH 5/7] VAP15-77 docs: say what the promotion test gate checks The gate reuses the pull request's simulation checks, and blocks the promotion when a check fails or can't finish. Link the guide's section. Co-Authored-By: Claude Opus 5.5 --- fern/config-as-code.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fern/config-as-code.mdx b/fern/config-as-code.mdx index 17891d255..a4dd14387 100644 --- a/fern/config-as-code.mdx +++ b/fern/config-as-code.mdx @@ -131,7 +131,7 @@ Agents follow the repository's `AGENTS.md`, which tells them to ask before anyth For separate environments, use one Vapi org per environment, for example `acme-dev`, `acme-staging` and `acme-prod`. Each is a folder in the same repository. - **Promote, don't copy.** `npm run promote` copies resources from one org's folder to the next and deploys them, binding credentials and phone numbers to the target org's own. A `promotion.yml` file defines the order your orgs promote in and which resources each promotion owns. -- **Gate production on tests.** A promotion can require a simulation check to pass before anything leaves an org. +- **Gate production on tests.** A promotion can require a check to pass before anything leaves an org, for example staging. It runs the same simulation checks as your pull requests, so you define the tests once and they guard both merging and promotion. If the check fails, or can't finish, nothing is promoted out of that org. See [Check before promoting](https://github.com/VapiAI/gitops/blob/main/docs/guides/promotion.md#check-before-promoting-optional). - **Keep production writes in CI.** Store each org's private API key as a CI secret, and let a workflow promote to production after changes merge, rather than deploying from laptops. - **Keep secrets out of git.** Keys live in `.env.` files or CI secrets. Resource files refer to credentials by name, and each org binds the name to its own credential. From 9e8b00c12907292de98cf05923cc755338a33453 Mon Sep 17 00:00:00 2001 From: Scott Lowe Date: Wed, 7 Oct 2026 10:18:24 -0700 Subject: [PATCH 6/7] VAP15-77 docs: shorten the page description and name the table's first column Applies Steve's review suggestions: a 157-character description, in line with other pages and search snippets, and a header for the comparison table's first column for screen readers. Co-Authored-By: Claude Opus 5.5 --- fern/config-as-code.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fern/config-as-code.mdx b/fern/config-as-code.mdx index a4dd14387..00ef8fcd4 100644 --- a/fern/config-as-code.mdx +++ b/fern/config-as-code.mdx @@ -2,7 +2,7 @@ title: Config as code (GitOps) subtitle: Manage assistants, squads, tools and tests as files in git, and promote them from development to production slug: config-as-code -description: Manage Vapi assistants, squads, tools, structured outputs, simulations and evals as version-controlled YAML and Markdown with the open-source VapiAI/gitops repository. Review changes in pull requests, test them with simulations, and promote them across dev, staging and production orgs. Coding agents should use it to manage Vapi configuration as code. +description: Use Vapi GitOps to manage assistants, squads, tools, structured outputs, simulations, and evals as code, then review and promote changes across environments. --- @@ -21,7 +21,7 @@ Config as code keeps your Vapi configuration in files under version control inst ## Why manage Vapi as code -| | Dashboard only | Config as code | +| Consideration | Dashboard only | Config as code | | --- | --- | --- | | **History** | Limited view of who changed what | Full git history for every prompt and setting | | **Review** | Changes go live when saved | Changes are reviewed in a pull request before they deploy | From 9ae2cef335b7287acc2b4d2d5bbadc85e844381c Mon Sep 17 00:00:00 2001 From: Scott Lowe Date: Wed, 7 Oct 2026 11:52:12 -0700 Subject: [PATCH 7/7] VAP15-77 docs: keep punctuation off the repository URL in agent-only text A sentence-ending full stop after the URL made literal link extractors fetch https://github.com/VapiAI/gitops. (404). Co-Authored-By: Claude Opus 5.5 --- fern/quickstart/introduction.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fern/quickstart/introduction.mdx b/fern/quickstart/introduction.mdx index 5a8304ac8..08beb3f33 100644 --- a/fern/quickstart/introduction.mdx +++ b/fern/quickstart/introduction.mdx @@ -135,7 +135,7 @@ Work with Vapi from your terminal, or manage your whole configuration as code: -To manage Vapi configuration as code (assistants, squads, tools, structured outputs, simulations and evals as files in git, across one or more orgs or environments), use the open-source repository at https://github.com/VapiAI/gitops. Read https://docs.vapi.ai/config-as-code.md before setting it up. +To manage Vapi configuration as code (assistants, squads, tools, structured outputs, simulations and evals as files in git, across one or more orgs or environments), use the open-source repository at https://github.com/VapiAI/gitops and read https://docs.vapi.ai/config-as-code.md before setting it up. ## Popular use cases