← Control PlaneCONTENT HISTORY

Update to Control Plane

Snapshot Oct 30, 2026 · 00:05 UTC · version 1.2.0

Collection source: downloaded plugin package.

WHAT CHANGED

Instructions updated for environment-promotion

Skill instructions — Now says: Terraform with `mcp__cpln__export_terraform`: one self link, bulk by path depth (a whole GVC or org), or a `manifest` converted to HCL after a dry-run...

Observed in instructions or declared skills. Runtime behavior has not been tested.

Save Control Plane and check future changes in Following.

Up to 10 plugins free · no card required.

All fields and original values.

Skill instructions

Before

Oct 28, 2026 · 18:05 UTC

Terraform: `mcp__cpln__export_terraform` (one self link, or bulk by path depth — a whole GVC or org), `mcp__cpln__convert_to_terraform` (manifest to HCL, dry-run validated). An unsupported kind is rejected with the supported list. - **On...

After

Oct 30, 2026 · 00:05 UTC

Terraform with `mcp__cpln__export_terraform`: one self link, bulk by path depth (a whole GVC or org), or a `manifest` converted to HCL after a dry-run validation. An unsupported kind is rejected with the supported list. - **One workload ...

Compare saved observations

Download comparison JSON

SKILL.md text changes

− removed · + added

--- before
+++ after
@@ -27,8 +27,8 @@
 
 - Bootstrap manifests from a live environment with `cpln <resource> get REF -o yaml-slim` (plain `yaml` output breaks apply).
 - Environment differences (env vars, scaling, firewall) belong in the manifests per environment — or patch after apply with `mcp__cpln__update_workload` / `mcp__cpln__update_gvc` (both PATCH semantics).
-- For IaC-based promotion, export live resources to Terraform: `mcp__cpln__export_terraform` (one self link, or bulk by path depth — a whole GVC or org), `mcp__cpln__convert_to_terraform` (manifest to HCL, dry-run validated). An unsupported kind is rejected with the supported list.
-- **One workload into another GVC:** `mcp__cpln__promote_workload` (`workload`, `gvc`, `targetGvc`, optional `image` and `env` overrides) copies the spec without its identity or `cpln/` tags, creates or updates the target, grants its secret references, and waits. A volume set mount is refused: create the storage in the target GVC first.
+- For IaC-based promotion, export live resources to Terraform with `mcp__cpln__export_terraform`: one self link, bulk by path depth (a whole GVC or org), or a `manifest` converted to HCL after a dry-run validation. An unsupported kind is rejected with the supported list.
+- **One workload into another GVC:** `mcp__cpln__promote_workload` (needs `?toolsets=full`; `workload`, `gvc`, `targetGvc`, optional `image` and `env` overrides) copies the spec without its identity or `cpln/` tags, points internal firewall links to workloads of the source GVC at the same names in the target, creates or updates the target, grants its secret references, and waits. Each volume set it mounts is created in the target GVC from the source's settings, custom encryption keys included, or updated to them (capacity only grows; an existing one keeps its own keys); data is never copied. Before anything is written it refuses a referenced secret that does not exist, an existing `{targetGvc}-{workload}-secrets-policy` policy of another target kind, an existing target workload of another type, and a target volume set with another file system or performance class or one another workload uses.
 
 ## Sharing images across orgs
 
@@ -45,8 +45,8 @@
 
 The target org pulls directly from the source org's registry. Four steps:
 
-1. **Source org — puller credentials**: `mcp__cpln__add_key_to_service_account` (full profile; creates the service account if missing; the key is shown **once**).
-2. **Source org — grant pull**: `mcp__cpln__create_policy` with `targetKind: image`, `targetAll: true` (or `targetQuery` by repository), `addPermissions: ["pull"]`, `addServiceAccounts: [LINK]` — bindings go in the create call.
+1. **Source org — puller credentials**: `mcp__cpln__add_key_to_service_account` (needs `?toolsets=full`; creates the service account if missing; the key is shown **once**).
+2. **Source org, grant pull**: `mcp__cpln__create_policy` with `targetKind: image`, `targetAll: true` (or `targetQuery` by repository), `addPermissions: ["pull"]`, `addServiceAccounts: [LINK]`; bindings go in the create call.
 3. **Target org — docker secret**: have the user create a `docker` secret with this `dockerConfigJson` — offer a manifest scaffold (`data` is this JSON as one string; `setup-secret` skill); the username is the **literal string `<token>`** (the registry rejects anything else; the password is the service-account key):
 
 ```json
@@ -107,7 +107,7 @@
 cpln workload get-deployments my-app --gvc my-gvc --org my-org    # verify every location reports ready
 ```
 
-- MCP path: `mcp__cpln__rollback_workload` (`name`, optional `image`) re-points the first container at the newest earlier image the deployments recorded, or at the image passed, and waits.
+- MCP path: `mcp__cpln__rollback_workload` (`name`, optional `image`) restores the previous image of every container whose image changed, read from the workload's audit trail (last 30 days; failing that, from an earlier version its deployments still run), or puts the image passed on the first container, and waits. Only images change.
 - Org-per-environment: confirm the older image still exists in **this** org's registry first (`mcp__cpln__list_resources` kind="image") — it may only have been copied forward once.
 - **Restart without changing the image**: `mcp__cpln__restart_workload`, or `cpln workload force-redeployment my-app --gvc GVC`; both stamp the `cpln/deployTimestamp` tag, a rolling restart.
 - Helm-managed releases are the exception with real revision history: `cpln helm rollback RELEASE [REVISION]`.
Full technical diff · 1 changed fields

changed /skill_md_contents

BEFORE
"---\nname: environment-promotion\ndescription: \"Promotes workloads across dev/staging/production on Control Plane. Use when the user asks about environment promotion, org-per-environment, cross-org image pulls, image promotion, deploying to production, or rollback.\"\n---\n\n# Environment Promotion\n\nControl Plane has **no built-in promote or rollback primitive** — promotion is applying the same artifacts (image + manifests) to the next environment. Two topologies exist: **org-per-environment (the documented best practice)** and GVC-per-environment. The recurring failure is image access: a staging/prod org cannot pull the dev org's images until you either copy the image or wire up a cross-org pull secret.\n\n## Choosing a topology\n\n| Topology | Isolation | Image sharing | Best for |\n|---|---|---|---|\n| **Org per environment** (recommended) | Strongest — policies, secrets, users, audit fully separate | `cpln image copy` or cross-org pull secret | Production, compliance-sensitive teams |\n| **GVC per environment** (one org) | Weak — shared org policies and access | Same org registry; no pull secret needed | Small teams, rapid iteration |\n\nWith org-per-environment, GVCs and workloads keep **identical names** in every org, so the same manifests apply unchanged — no environment suffixes in resource names. Org creation is account-level: Console, or `cpln org create --accountId ID --invitee EMAIL`.\n\n## Promoting manifests\n\nKeep manifests in git and apply them per environment — `cpln apply` is idempotent (PUT upsert) and resolves resource ordering:\n\n```bash\ncpln apply --file ./manifests/ --org my-org-staging --gvc my-gvc --ready   # org-per-env: same files, next org\ncpln apply --file ./manifests/ --org my-org --gvc staging-gvc --ready     # gvc-per-env: same files, next GVC\n```\n\n- Bootstrap manifests from a live environment with `cpln <resource> get REF -o yaml-slim` (plain `yaml` output breaks apply).\n- Environment differences (env vars, scaling, firewall) belong in the manifests per environment — or patch after apply with `mcp__cpln__update_workload` / `mcp__cpln__update_gvc` (both PATCH semantics).\n- For IaC-based promotion, export live resources to Terraform: `mcp__cpln__export_terraform` (one self link, or bulk by path depth — a whole GVC or org), `mcp__cpln__convert_to_terraform` (manifest to HCL, dry-run validated). An unsupported kind is rejected with the supported list.\n- **One workload into another GVC:** `mcp__cpln__promote_workload` (`workload`, `gvc`, `targetGvc`, optional `image` and `env` overrides) copies the spec without its identity or `cpln/` tags, creates or updates the target, grants its secret references, and waits. A volume set mount is refused: create the storage in the target GVC first.\n\n## Sharing images across orgs\n\n### Option A — copy the image (one-time promotions)\n\n```bash\ncpln image copy my-app:abc1234 --to-org my-org-prod              # same credentials for both orgs\ncpln image copy my-app:abc1234 --to-org my-org-prod --to-profile prod-profile --cleanup\n```\n\nCLI-only (no MCP tool) and **still requires a running Docker daemon — `copy` has no `--remote` mode** — it docker-logins both registries, then pulls, tags, pushes. `--to-name` renames during copy; `--cleanup` removes the local images (use in CI). Needs `pull` permission on the source image and `create` on images in the target org. After the copy the target references it as `//image/my-app:abc1234` — no pull secret.\n\n### Option B — cross-org pull secret (continuous access)\n\nThe target org pulls directly from the source org's registry. Four steps:\n\n1. **Source org — puller credentials**: `mcp__cpln__add_key_to_service_account` (full profile; creates the service account if missing; the key is shown **once**).\n2. **Source org — grant pull**: `mcp__cpln__create_policy` with `targetKind: image`, `targetAll: true` (or `targetQuery` by repository), `addPermissions: [\"pull\"]`, `addServiceAccounts: [LINK]` — bindings go in the create call.\n3. **Target org — docker secret**: have the user create a `docker` secret with this `dockerConfigJson` — offer a manifest scaffold (`data` is this JSON as one string; `setup-secret` skill); the username is the **literal string `<token>`** (the registry rejects anything else; the password is the service-account key):\n\n```json\n{ \"auths\": { \"my-org-dev.registry.cpln.io\": { \"username\": \"<token>\", \"password\": \"SERVICE_ACCOUNT_KEY\" } } }\n```\n\n4. **Target org — attach to the GVC**: `mcp__cpln__update_gvc` with `pullSecretLinks: [\"//secret/dev-registry-pull\"]` (merged with existing), then reference the image by its **full registry hostname** in the workload spec:\n\n```yaml\nspec:\n  containers:\n    - name: main\n      image: my-org-dev.registry.cpln.io/my-app:abc1234\n```\n\nCLI fallback for the same four steps:\n\n```bash\ncpln serviceaccount create --name image-puller --org my-org-dev                            # CLI does NOT auto-create on add-key\ncpln serviceaccount add-key image-puller --description \"cross-org pull\" --org my-org-dev   # save the key\ncpln policy create --name image-pull --target-kind image --all --org my-org-dev\ncpln policy add-binding image-pull --serviceaccount image-puller --permission pull --org my-org-dev\n# the user creates the dev-registry-pull docker secret in my-org-prod, then:\ncpln gvc update my-gvc --set 'spec.pullSecretLinks+=//secret/dev-registry-pull' --org my-org-prod\n```\n\nSame-org images never need a pull secret — the platform injects a default registry credential for the org's own registry automatically.\n\n## Image tags across environments\n\n- **Promote immutable tags** (git SHA `my-app:abc1234` or semver `my-app:v1.2.3`) — promote the exact artifact you tested; mutable tags (`latest`, `staging`) make rollback unreliable. Digest pins (`my-app@sha256:...`) are maximally reproducible.\n- **`supportDynamicTags`** (workload spec, default `false`): redeploys the workload automatically when a tag's underlying digest changes (within ~5 minutes) — useful for dev environments on mutable tags, wrong for production promotion.\n\n## CI/CD promotion pipeline\n\nThe CLI is the primary interface in pipelines; `CPLN_TOKEN` alone is enough (no profile needed — see the `cpln` skill). The shape that works:\n\n```yaml\n# Build once in dev, then per stage: copy the image + apply the manifests\n- run: cpln image build --name my-app:${{ github.sha }} --push     # CPLN_TOKEN + CPLN_ORG=my-org-dev\n- run: cpln apply --file ./manifests/ --gvc my-gvc --ready\n\n# staging / prod stages (gate each with environment approvals):\n- run: cpln image copy my-app:${{ github.sha }} --to-org my-org-prod --cleanup   # dev-org token\n- run: cpln apply --file ./manifests/ --gvc my-gvc --org my-org-prod --ready     # prod-org token\n```\n\n- **One service-account token per org** — a dev-org token must not be able to touch prod; the copy step runs with source-org credentials plus a `--to-profile` (or pre-run `cpln image docker-login`) for the target.\n- **`--ready` gates promotion** — it polls until workloads are healthy (5s interval, up to 5 min) and fails the job otherwise.\n- Approval gates (GitHub environments, GitLab manual jobs) go between stages. Full pipeline setup, npm install (`@controlplane/cli`), runners: `gitops-cicd` skill.\n\n## Rollback\n\nThere is no deployment-history rollback — rolling back means **re-pointing the workload at the previous known-good image** (keep the previous tag in git history or your pipeline metadata):\n\n```bash\ncpln workload update my-app --set spec.containers.main.image=//image/my-app:v1.1.0 --gvc my-gvc --org my-org\ncpln workload get-deployments my-app --gvc my-gvc --org my-org    # verify every location reports ready\n```\n\n- MCP path: `mcp__cpln__rollback_workload` (`name`, optional `image`) re-points the first container at the newest earlier image the deployments recorded, or at the image passed, and waits.\n- Org-per-environment: confirm the older image still exists in **this** org's registry first (`mcp__cpln__list_resources` kind=\"image\") — it may only have been copied forward once.\n- **Restart without changing the image**: `mcp__cpln__restart_workload`, or `cpln workload force-redeployment my-app --gvc GVC`; both stamp the `cpln/deployTimestamp` tag, a rolling restart.\n- Helm-managed releases are the exception with real revision history: `cpln helm rollback RELEASE [REVISION]`.\n"
AFTER
"---\nname: environment-promotion\ndescription: \"Promotes workloads across dev/staging/production on Control Plane. Use when the user asks about environment promotion, org-per-environment, cross-org image pulls, image promotion, deploying to production, or rollback.\"\n---\n\n# Environment Promotion\n\nControl Plane has **no built-in promote or rollback primitive** — promotion is applying the same artifacts (image + manifests) to the next environment. Two topologies exist: **org-per-environment (the documented best practice)** and GVC-per-environment. The recurring failure is image access: a staging/prod org cannot pull the dev org's images until you either copy the image or wire up a cross-org pull secret.\n\n## Choosing a topology\n\n| Topology | Isolation | Image sharing | Best for |\n|---|---|---|---|\n| **Org per environment** (recommended) | Strongest — policies, secrets, users, audit fully separate | `cpln image copy` or cross-org pull secret | Production, compliance-sensitive teams |\n| **GVC per environment** (one org) | Weak — shared org policies and access | Same org registry; no pull secret needed | Small teams, rapid iteration |\n\nWith org-per-environment, GVCs and workloads keep **identical names** in every org, so the same manifests apply unchanged — no environment suffixes in resource names. Org creation is account-level: Console, or `cpln org create --accountId ID --invitee EMAIL`.\n\n## Promoting manifests\n\nKeep manifests in git and apply them per environment — `cpln apply` is idempotent (PUT upsert) and resolves resource ordering:\n\n```bash\ncpln apply --file ./manifests/ --org my-org-staging --gvc my-gvc --ready   # org-per-env: same files, next org\ncpln apply --file ./manifests/ --org my-org --gvc staging-gvc --ready     # gvc-per-env: same files, next GVC\n```\n\n- Bootstrap manifests from a live environment with `cpln <resource> get REF -o yaml-slim` (plain `yaml` output breaks apply).\n- Environment differences (env vars, scaling, firewall) belong in the manifests per environment — or patch after apply with `mcp__cpln__update_workload` / `mcp__cpln__update_gvc` (both PATCH semantics).\n- For IaC-based promotion, export live resources to Terraform with `mcp__cpln__export_terraform`: one self link, bulk by path depth (a whole GVC or org), or a `manifest` converted to HCL after a dry-run validation. An unsupported kind is rejected with the supported list.\n- **One workload into another GVC:** `mcp__cpln__promote_workload` (needs `?toolsets=full`; `workload`, `gvc`, `targetGvc`, optional `image` and `env` overrides) copies the spec without its identity or `cpln/` tags, points internal firewall links to workloads of the source GVC at the same names in the target, creates or updates the target, grants its secret references, and waits. Each volume set it mounts is created in the target GVC from the source's settings, custom encryption keys included, or updated to them (capacity only grows; an existing one keeps its own keys); data is never copied. Before anything is written it refuses a referenced secret that does not exist, an existing `{targetGvc}-{workload}-secrets-policy` policy of another target kind, an existing target workload of another type, and a target volume set with another file system or performance class or one another workload uses.\n\n## Sharing images across orgs\n\n### Option A — copy the image (one-time promotions)\n\n```bash\ncpln image copy my-app:abc1234 --to-org my-org-prod              # same credentials for both orgs\ncpln image copy my-app:abc1234 --to-org my-org-prod --to-profile prod-profile --cleanup\n```\n\nCLI-only (no MCP tool) and **still requires a running Docker daemon — `copy` has no `--remote` mode** — it docker-logins both registries, then pulls, tags, pushes. `--to-name` renames during copy; `--cleanup` removes the local images (use in CI). Needs `pull` permission on the source image and `create` on images in the target org. After the copy the target references it as `//image/my-app:abc1234` — no pull secret.\n\n### Option B — cross-org pull secret (continuous access)\n\nThe target org pulls directly from the source org's registry. Four steps:\n\n1. **Source org — puller credentials**: `mcp__cpln__add_key_to_service_account` (needs `?toolsets=full`; creates the service account if missing; the key is shown **once**).\n2. **Source org, grant pull**: `mcp__cpln__create_policy` with `targetKind: image`, `targetAll: true` (or `targetQuery` by repository), `addPermissions: [\"pull\"]`, `addServiceAccounts: [LINK]`; bindings go in the create call.\n3. **Target org — docker secret**: have the user create a `docker` secret with this `dockerConfigJson` — offer a manifest scaffold (`data` is this JSON as one string; `setup-secret` skill); the username is the **literal string `<token>`** (the registry rejects anything else; the password is the service-account key):\n\n```json\n{ \"auths\": { \"my-org-dev.registry.cpln.io\": { \"username\": \"<token>\", \"password\": \"SERVICE_ACCOUNT_KEY\" } } }\n```\n\n4. **Target org — attach to the GVC**: `mcp__cpln__update_gvc` with `pullSecretLinks: [\"//secret/dev-registry-pull\"]` (merged with existing), then reference the image by its **full registry hostname** in the workload spec:\n\n```yaml\nspec:\n  containers:\n    - name: main\n      image: my-org-dev.registry.cpln.io/my-app:abc1234\n```\n\nCLI fallback for the same four steps:\n\n```bash\ncpln serviceaccount create --name image-puller --org my-org-dev                            # CLI does NOT auto-create on add-key\ncpln serviceaccount add-key image-puller --description \"cross-org pull\" --org my-org-dev   # save the key\ncpln policy create --name image-pull --target-kind image --all --org my-org-dev\ncpln policy add-binding image-pull --serviceaccount image-puller --permission pull --org my-org-dev\n# the user creates the dev-registry-pull docker secret in my-org-prod, then:\ncpln gvc update my-gvc --set 'spec.pullSecretLinks+=//secret/dev-registry-pull' --org my-org-prod\n```\n\nSame-org images never need a pull secret — the platform injects a default registry credential for the org's own registry automatically.\n\n## Image tags across environments\n\n- **Promote immutable tags** (git SHA `my-app:abc1234` or semver `my-app:v1.2.3`) — promote the exact artifact you tested; mutable tags (`latest`, `staging`) make rollback unreliable. Digest pins (`my-app@sha256:...`) are maximally reproducible.\n- **`supportDynamicTags`** (workload spec, default `false`): redeploys the workload automatically when a tag's underlying digest changes (within ~5 minutes) — useful for dev environments on mutable tags, wrong for production promotion.\n\n## CI/CD promotion pipeline\n\nThe CLI is the primary interface in pipelines; `CPLN_TOKEN` alone is enough (no profile needed — see the `cpln` skill). The shape that works:\n\n```yaml\n# Build once in dev, then per stage: copy the image + apply the manifests\n- run: cpln image build --name my-app:${{ github.sha }} --push     # CPLN_TOKEN + CPLN_ORG=my-org-dev\n- run: cpln apply --file ./manifests/ --gvc my-gvc --ready\n\n# staging / prod stages (gate each with environment approvals):\n- run: cpln image copy my-app:${{ github.sha }} --to-org my-org-prod --cleanup   # dev-org token\n- run: cpln apply --file ./manifests/ --gvc my-gvc --org my-org-prod --ready     # prod-org token\n```\n\n- **One service-account token per org** — a dev-org token must not be able to touch prod; the copy step runs with source-org credentials plus a `--to-profile` (or pre-run `cpln image docker-login`) for the target.\n- **`--ready` gates promotion** — it polls until workloads are healthy (5s interval, up to 5 min) and fails the job otherwise.\n- Approval gates (GitHub environments, GitLab manual jobs) go between stages. Full pipeline setup, npm install (`@controlplane/cli`), runners: `gitops-cicd` skill.\n\n## Rollback\n\nThere is no deployment-history rollback — rolling back means **re-pointing the workload at the previous known-good image** (keep the previous tag in git history or your pipeline metadata):\n\n```bash\ncpln workload update my-app --set spec.containers.main.image=//image/my-app:v1.1.0 --gvc my-gvc --org my-org\ncpln workload get-deployments my-app --gvc my-gvc --org my-org    # verify every location reports ready\n```\n\n- MCP path: `mcp__cpln__rollback_workload` (`name`, optional `image`) restores the previous image of every container whose image changed, read from the workload's audit trail (last 30 days; failing that, from an earlier version its deployments still run), or puts the image passed on the first container, and waits. Only images change.\n- Org-per-environment: confirm the older image still exists in **this** org's registry first (`mcp__cpln__list_resources` kind=\"image\") — it may only have been copied forward once.\n- **Restart without changing the image**: `mcp__cpln__restart_workload`, or `cpln workload force-redeployment my-app --gvc GVC`; both stamp the `cpln/deployTimestamp` tag, a rolling restart.\n- Helm-managed releases are the exception with real revision history: `cpln helm rollback RELEASE [REVISION]`.\n"
Full snapshot data
{
  "description": "Promotes workloads across dev/staging/production on Control Plane. Use when the user asks about environment promotion, org-per-environment, cross-org image pulls, image promotion, deploying to production, or rollback.",
  "included_files": [],
  "name": "environment-promotion",
  "skill_md_contents": "---\nname: environment-promotion\ndescription: \"Promotes workloads across dev/staging/production on Control Plane. Use when the user asks about environment promotion, org-per-environment, cross-org image pulls, image promotion, deploying to production, or rollback.\"\n---\n\n# Environment Promotion\n\nControl Plane has **no built-in promote or rollback primitive** — promotion is applying the same artifacts (image + manifests) to the next environment. Two topologies exist: **org-per-environment (the documented best practice)** and GVC-per-environment. The recurring failure is image access: a staging/prod org cannot pull the dev org's images until you either copy the image or wire up a cross-org pull secret.\n\n## Choosing a topology\n\n| Topology | Isolation | Image sharing | Best for |\n|---|---|---|---|\n| **Org per environment** (recommended) | Strongest — policies, secrets, users, audit fully separate | `cpln image copy` or cross-org pull secret | Production, compliance-sensitive teams |\n| **GVC per environment** (one org) | Weak — shared org policies and access | Same org registry; no pull secret needed | Small teams, rapid iteration |\n\nWith org-per-environment, GVCs and workloads keep **identical names** in every org, so the same manifests apply unchanged — no environment suffixes in resource names. Org creation is account-level: Console, or `cpln org create --accountId ID --invitee EMAIL`.\n\n## Promoting manifests\n\nKeep manifests in git and apply them per environment — `cpln apply` is idempotent (PUT upsert) and resolves resource ordering:\n\n```bash\ncpln apply --file ./manifests/ --org my-org-staging --gvc my-gvc --ready   # org-per-env: same files, next org\ncpln apply --file ./manifests/ --org my-org --gvc staging-gvc --ready     # gvc-per-env: same files, next GVC\n```\n\n- Bootstrap manifests from a live environment with `cpln <resource> get REF -o yaml-slim` (plain `yaml` output breaks apply).\n- Environment differences (env vars, scaling, firewall) belong in the manifests per environment — or patch after apply with `mcp__cpln__update_workload` / `mcp__cpln__update_gvc` (both PATCH semantics).\n- For IaC-based promotion, export live resources to Terraform with `mcp__cpln__export_terraform`: one self link, bulk by path depth (a whole GVC or org), or a `manifest` converted to HCL after a dry-run validation. An unsupported kind is rejected with the supported list.\n- **One workload into another GVC:** `mcp__cpln__promote_workload` (needs `?toolsets=full`; `workload`, `gvc`, `targetGvc`, optional `image` and `env` overrides) copies the spec without its identity or `cpln/` tags, points internal firewall links to workloads of the source GVC at the same names in the target, creates or updates the target, grants its secret references, and waits. Each volume set it mounts is created in the target GVC from the source's settings, custom encryption keys included, or updated to them (capacity only grows; an existing one keeps its own keys); data is never copied. Before anything is written it refuses a referenced secret that does not exist, an existing `{targetGvc}-{workload}-secrets-policy` policy of another target kind, an existing target workload of another type, and a target volume set with another file system or performance class or one another workload uses.\n\n## Sharing images across orgs\n\n### Option A — copy the image (one-time promotions)\n\n```bash\ncpln image copy my-app:abc1234 --to-org my-org-prod              # same credentials for both orgs\ncpln image copy my-app:abc1234 --to-org my-org-prod --to-profile prod-profile --cleanup\n```\n\nCLI-only (no MCP tool) and **still requires a running Docker daemon — `copy` has no `--remote` mode** — it docker-logins both registries, then pulls, tags, pushes. `--to-name` renames during copy; `--cleanup` removes the local images (use in CI). Needs `pull` permission on the source image and `create` on images in the target org. After the copy the target references it as `//image/my-app:abc1234` — no pull secret.\n\n### Option B — cross-org pull secret (continuous access)\n\nThe target org pulls directly from the source org's registry. Four steps:\n\n1. **Source org — puller credentials**: `mcp__cpln__add_key_to_service_account` (needs `?toolsets=full`; creates the service account if missing; the key is shown **once**).\n2. **Source org, grant pull**: `mcp__cpln__create_policy` with `targetKind: image`, `targetAll: true` (or `targetQuery` by repository), `addPermissions: [\"pull\"]`, `addServiceAccounts: [LINK]`; bindings go in the create call.\n3. **Target org — docker secret**: have the user create a `docker` secret with this `dockerConfigJson` — offer a manifest scaffold (`data` is this JSON as one string; `setup-secret` skill); the username is the **literal string `<token>`** (the registry rejects anything else; the password is the service-account key):\n\n```json\n{ \"auths\": { \"my-org-dev.registry.cpln.io\": { \"username\": \"<token>\", \"password\": \"SERVICE_ACCOUNT_KEY\" } } }\n```\n\n4. **Target org — attach to the GVC**: `mcp__cpln__update_gvc` with `pullSecretLinks: [\"//secret/dev-registry-pull\"]` (merged with existing), then reference the image by its **full registry hostname** in the workload spec:\n\n```yaml\nspec:\n  containers:\n    - name: main\n      image: my-org-dev.registry.cpln.io/my-app:abc1234\n```\n\nCLI fallback for the same four steps:\n\n```bash\ncpln serviceaccount create --name image-puller --org my-org-dev                            # CLI does NOT auto-create on add-key\ncpln serviceaccount add-key image-puller --description \"cross-org pull\" --org my-org-dev   # save the key\ncpln policy create --name image-pull --target-kind image --all --org my-org-dev\ncpln policy add-binding image-pull --serviceaccount image-puller --permission pull --org my-org-dev\n# the user creates the dev-registry-pull docker secret in my-org-prod, then:\ncpln gvc update my-gvc --set 'spec.pullSecretLinks+=//secret/dev-registry-pull' --org my-org-prod\n```\n\nSame-org images never need a pull secret — the platform injects a default registry credential for the org's own registry automatically.\n\n## Image tags across environments\n\n- **Promote immutable tags** (git SHA `my-app:abc1234` or semver `my-app:v1.2.3`) — promote the exact artifact you tested; mutable tags (`latest`, `staging`) make rollback unreliable. Digest pins (`my-app@sha256:...`) are maximally reproducible.\n- **`supportDynamicTags`** (workload spec, default `false`): redeploys the workload automatically when a tag's underlying digest changes (within ~5 minutes) — useful for dev environments on mutable tags, wrong for production promotion.\n\n## CI/CD promotion pipeline\n\nThe CLI is the primary interface in pipelines; `CPLN_TOKEN` alone is enough (no profile needed — see the `cpln` skill). The shape that works:\n\n```yaml\n# Build once in dev, then per stage: copy the image + apply the manifests\n- run: cpln image build --name my-app:${{ github.sha }} --push     # CPLN_TOKEN + CPLN_ORG=my-org-dev\n- run: cpln apply --file ./manifests/ --gvc my-gvc --ready\n\n# staging / prod stages (gate each with environment approvals):\n- run: cpln image copy my-app:${{ github.sha }} --to-org my-org-prod --cleanup   # dev-org token\n- run: cpln apply --file ./manifests/ --gvc my-gvc --org my-org-prod --ready     # prod-org token\n```\n\n- **One service-account token per org** — a dev-org token must not be able to touch prod; the copy step runs with source-org credentials plus a `--to-profile` (or pre-run `cpln image docker-login`) for the target.\n- **`--ready` gates promotion** — it polls until workloads are healthy (5s interval, up to 5 min) and fails the job otherwise.\n- Approval gates (GitHub environments, GitLab manual jobs) go between stages. Full pipeline setup, npm install (`@controlplane/cli`), runners: `gitops-cicd` skill.\n\n## Rollback\n\nThere is no deployment-history rollback — rolling back means **re-pointing the workload at the previous known-good image** (keep the previous tag in git history or your pipeline metadata):\n\n```bash\ncpln workload update my-app --set spec.containers.main.image=//image/my-app:v1.1.0 --gvc my-gvc --org my-org\ncpln workload get-deployments my-app --gvc my-gvc --org my-org    # verify every location reports ready\n```\n\n- MCP path: `mcp__cpln__rollback_workload` (`name`, optional `image`) restores the previous image of every container whose image changed, read from the workload's audit trail (last 30 days; failing that, from an earlier version its deployments still run), or puts the image passed on the first container, and waits. Only images change.\n- Org-per-environment: confirm the older image still exists in **this** org's registry first (`mcp__cpln__list_resources` kind=\"image\") — it may only have been copied forward once.\n- **Restart without changing the image**: `mcp__cpln__restart_workload`, or `cpln workload force-redeployment my-app --gvc GVC`; both stamp the `cpln/deployTimestamp` tag, a rolling restart.\n- Helm-managed releases are the exception with real revision history: `cpln helm rollback RELEASE [REVISION]`.\n"
}

SHA-256 of public snapshot: 2cb73a551e300ad260e46cf01aa961bea18fe5d335568231790757fd17a4e9d8