Repository navigation
feat(engine): pin each org folder to its Vapi org - #84
Merged
Merged
Conversation
Contributor
Author
This stack of pull requests is managed by Graphite. Learn more about stacking. |
scott-lowe-vapi
marked this pull request as ready for review
October 28, 2026 06:09
roshan-vapi
approved these changes
Oct 28, 2026
Contributor
Author
Merge activity
|
scott-lowe-vapi
changed the base branch from
feat/per-org-api-keys
to
graphite-base/84
October 28, 2026 17:53
Nothing tied resources/<org>/ to an org: the key alone decided where a command read and wrote. A key for the wrong org, from an exported variable, a copied .env file or a mislabelled CI secret, pulled another org's resources into the folder or pushed the folder into another org. - The first command that can see the key's org records it in resources/<org>/.vapi-org.json, committed with the folder. Promotion skips dotfiles, so the pin never travels to another org. - Every command then checks the key before its first request: pull, push, apply, promote (through its child commands), cleanup and rollback. A key for another org stops the command, naming both org IDs and where the key came from, never the key. So does a key whose org lists nothing while the folder is pinned. - A private key can't ask which org it belongs to (/org and /org/me reject private keys), so the org ID comes from one-item list calls. If those fail, the command warns that the key wasn't checked and goes on. A folder with no pin and no files makes no extra request. - README, AGENTS.md and the configuration guide describe the file, and AGENTS.md tells agents never to edit or delete it to get past a stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scott-lowe-vapi
force-pushed
the
feat/org-pinning
branch
from
October 28, 2026 17:54
26f7860 to
2a45f8e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Value
V.A.L.U.E. tier: small. It adds a check before every command's first request, a new committed file per org folder, and a new way for commands to stop. Stacked on #83.
resources/<org>/to a Vapi org. The key alone decides where a command reads and writes. feat(setup): per-org API key variables; stop one org's key reaching another #83 removes one way to get the wrong key (an exported generic variable), but not the others: a mistyped per-org variable, a.envfile copied between orgs, a CI secret holding the wrong org's key. With any of these,applypushes the folder into the wrong org,cleanupdeletes from it, andpullfills the folder with another org's resources. Each one runs without an error.resources/<org>/.vapi-org.json, which is committed with the folder. Promotion skips dotfiles, so the pin never travels to another org.pull,push,apply,promote(through its child commands),cleanupandrollback. It stops when the key belongs to another org, naming both org IDs and where the key came from, never the key. It also stops when the key's org has no resources but the folder is pinned to an org that had some, since pushing would fill a fresh org with this folder./organd/org/mereturn 401), so the org ID comes from one-item list calls:/assistant?limit=1, then other types until one lists something. A matching key costs one extra request per command. If the probes fail (5xx, network), the command warns that the key wasn't checked and continues. A folder with no pin and no files makes no extra request..vapi-org.jsonin a reviewed commit. There's no flag or environment variable to skip the check. The test preload sets an internal switch so tests that count requests stay deterministic, andorg-pin.test.tsturns it back on.call,simandcheckdon't check the pin. They don't change configuration, but they could run against the wrong org.Evidence of value
resources/acme/pinned to org A{ results }pages, empty, failed, 401), every check outcome, a corrupt pin, and no requests for an unpinned org with no folder. An end-to-end test runspullagainst a stub API returning org B for a folder pinned to org A: exit 1, and only/assistant?limit=1reached the API.pull --bootstrap --bindings-only): the first run pinned the folder to the right org. With a fake org ID planted in the pin, the next run stopped at its first request, before listing anything. With the pin restored, it ran with no extra output.Testing plan
npm run buildandnpm test(575) pass.npm run pull -- <org>once per org and commit the new.vapi-org.jsonfiles. Then runapply --dry-runwith another org's key exported as that org's per-org variable, and check that it stops.🤖 Generated with Claude Code