Add a GitHub Actions workflow triggered on pull_request with types: [opened, synchronize, reopened] to create the environment and a separate trigger on pull_request with types: [closed] to destroy it.
In the create job, use kubectl create namespace pr-${{ github.event.pull_request.number }} (or a sanitized slug) to provision an isolated namespace for the PR.
Deploy your application into the namespace using helm upgrade --install or kubectl apply -f with --namespace pr-${{ github.event.pull_request.number }} to scope all resources to the PR namespace.
Post the preview URL as a pull request comment using the GitHub REST API (POST /repos/{owner}/{repo}/issues/{pr_number}/comments) so reviewers can access the environment.
In the cleanup job (triggered on PR close), run kubectl delete namespace pr-${{ github.event.pull_request.number }} to remove all resources in that namespace automatically.
Store the kubeconfig in a GitHub Actions encrypted secret and export it to KUBECONFIG in the workflow; restrict the service account used to only the necessary namespaces and verbs.
Known gotchas
Namespace names must be valid DNS labels (lowercase alphanumeric and hyphens, 63 characters max); sanitize the PR branch name or number before constructing the namespace name.
If the PR is force-pushed rapidly, multiple workflow runs can attempt to create the same namespace concurrently; use kubectl create namespace --dry-run=client | kubectl apply -f - to make creation idempotent.
Namespace deletion is asynchronous; dependent resources with finalizers (e.g., PVCs or custom resources) can block termination indefinitely—monitor for Terminating namespaces in long-running clusters.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp