Ephemeral PR preview environments
Read references/PR-PREVIEW-ENVIRONMENTS.md before applying any of this.
That file is the standard; everything below it is a summary to help you decide
whether this skill applies and to check your work afterwards.
What this standard covers
- The model in one paragraph
- Naming is the isolation mechanism
- Shared vs per-PR
- The deploy workflow
- Teardown
- Cost posture
Failure modes
| Symptom | Cause |
|---|---|
| Draft PRs stuck "waiting for approval" | The draft-guard job is bound to a protected environment: |
| Two deploys interleave after a force-push | No per-PR concurrency group |
| Preview calls another branch's services | URLs hand-built in one step instead of computed once from the PR number |
| Every PR provisions a new AI account | Shared resources not threaded as parameters; classification doc missing or ignored |
| Teardown fails on half-destroyed environments | Destroy treats a missing resource as an error; make it a skip |
| Orphaned environments after a rename | Destroy list lacks legacy aliases |
| PR thread unreadable | Comment per deploy instead of one sticky comment edited in place |
| Preview extension/installer from the wrong branch | Artifact not pinned by PR label in the distribution channel |
Checklist
-
-pr-{number}suffix everywhere; URLs computed once from the PR number - Shared-vs-per-PR classification committed, rows citing creating
file:line, negatives stated - Per-PR databases created idempotently on the shared server; shared resources passed as parameters
- Draft guard without an environment binding; per-PR concurrency group
- Sticky comment created/updated on deploy, rewritten on destroy
- Close-triggered idempotent teardown + manual escape hatch + legacy aliases
- Preview artifacts pinned by PR label
- Everything scales to zero; on-demand previews as the next cost lever
Generated from docs/guides/PR-PREVIEW-ENVIRONMENTS.md by scripts/build-marketplace.mjs. Do not edit this file: change the source document, or its entry in catalog/marketplace.catalog.json, and re-run the generator.