← 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 setup-secret

Skill instructions — Now says: env, and refuses a referenced secret that does not exist before it builds or writes anything. - **`grant_workload_secret_access`** (`gvc`, `workloadName`,...

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

env. - **`grant_workload_secret_access`** (`gvc`, `workloadName`, `secretName`) creates the identity if missing (default `{gvc}-{workloadName}`), creates or updates a `reveal` policy (default `{gvc}-{workloadName}-secrets-policy`), links...

After

Oct 30, 2026 · 00:05 UTC

env, and refuses a referenced secret that does not exist before it builds or writes anything. - **`grant_workload_secret_access`** (`gvc`, `workloadName`, `secretName`) creates the identity if missing (default `{gvc}-{workloadName}`), cr...

Compare saved observations

Download comparison JSON

SKILL.md text changes

− removed · + added

--- before
+++ after
@@ -21,10 +21,11 @@
 
 ## Wiring access
 
-- **`deploy_app`** wires all three steps for the references in its env.
-- **`grant_workload_secret_access`** (`gvc`, `workloadName`, `secretName`) creates the identity if missing (default `{gvc}-{workloadName}`), creates or updates a `reveal` policy (default `{gvc}-{workloadName}-secrets-policy`), links the identity, and redeploys a workload already waiting on the secret. It does not add the reference. The workload must exist first: create it (its deployment pauses on the reference), then grant, and it resumes.
+- **`deploy_app`** wires all three steps for the references in its env, and refuses a referenced secret that does not exist before it builds or writes anything.
+- **`grant_workload_secret_access`** (`gvc`, `workloadName`, `secretName`) creates the identity if missing (default `{gvc}-{workloadName}`), creates or updates a `reveal` policy (default `{gvc}-{workloadName}-secrets-policy`), links the identity, and redeploys a workload already waiting on the secret. Before writing anything it checks that the secret exists and that an existing policy of that name targets secrets. It does not add the reference. The workload must exist first: create it (its deployment pauses on the reference), then grant, and it resumes.
 - The platform checks access once per deployed version. A version it refused stays refused after the policy changes, until a new version deploys, so the tool grants before it links and redeploys a workload still waiting.
 - **By hand**, only when the tool cannot: `create_identity`, then `create_policy` with target kind `secret` and a `reveal` binding for the identity (`access-control` skill), then `update_workload` to set `spec.identityLink` last.
+- **Revoking:** `grant_workload_secret_access` with `remove: true` takes the secret out of that policy (deleting the policy once it targets nothing) and keeps the identity; it refuses, changing nothing, a policy that also binds another principal or grants by `target: all` or a query. Also drop the `cpln://secret/` reference with `update_workload`: a deploy that still references a revoked secret fails, and running replicas keep the value until they are replaced.
 - Identities are GVC-scoped: one per workload, shareable within a GVC, never across GVCs.
 
 ## References
@@ -73,7 +74,7 @@
 | `gcp` | **JSON string** | a full service-account key: `type`, `project_id`, `private_key_id`, `private_key`, `client_email`, `client_id`, `auth_uri`, `token_uri`, `auth_provider_x509_cert_url`, `client_x509_cert_url` |
 | `azure-sdk` | **JSON string** | `subscriptionId`, `tenantId`, `clientId` (UUIDs) and `clientSecret` |
 
-`get_resource_schema` (kind "secret") has the apply schema and REST endpoints.
+`get_resource` (kind "secret", `schema: true`) has the apply schema and REST endpoints.
 
 ## Verify
 
Full technical diff · 1 changed fields

changed /skill_md_contents

BEFORE
"---\nname: setup-secret\ndescription: Secret access wiring and manifest authoring. Use when a workload needs to read a secret, the user asks to create a secret or generate secret YAML, configure a pull secret, or fix a deployment paused on a secret reference.\n---\n\n# Secret Access Setup\n\nA workload reads a secret only when three things are in place. Miss one and the value is silently absent, or the deployment pauses on the unresolved reference.\n\n| Step | What must be true | Without it |\n|---|---|---|\n| **Identity** | an identity linked to the workload (`spec.identityLink`) | the workload reads nothing |\n| **Policy** | a policy granting that identity `reveal` on the secret | the reference resolves to empty |\n| **Reference** | `cpln://secret/NAME` or `cpln://secret/NAME.KEY` in env or a volume | nothing to read |\n\n`reveal`, not `view`: `view` shows metadata only. This is the most common mistake.\n\n## Creating and rotating\n\n`mcp__cpln__create_secret` creates secrets without a value passing through the chat, and `mcp__cpln__rotate_secret` rotates them; their descriptions cover both paths. Values Control Plane generates and values the user enters belong in separate secrets. Confirm a secret exists (`get_resource`, kind \"secret\") before anything references it.\n\n## Wiring access\n\n- **`deploy_app`** wires all three steps for the references in its env.\n- **`grant_workload_secret_access`** (`gvc`, `workloadName`, `secretName`) creates the identity if missing (default `{gvc}-{workloadName}`), creates or updates a `reveal` policy (default `{gvc}-{workloadName}-secrets-policy`), links the identity, and redeploys a workload already waiting on the secret. It does not add the reference. The workload must exist first: create it (its deployment pauses on the reference), then grant, and it resumes.\n- The platform checks access once per deployed version. A version it refused stays refused after the policy changes, until a new version deploys, so the tool grants before it links and redeploys a workload still waiting.\n- **By hand**, only when the tool cannot: `create_identity`, then `create_policy` with target kind `secret` and a `reveal` binding for the identity (`access-control` skill), then `update_workload` to set `spec.identityLink` last.\n- Identities are GVC-scoped: one per workload, shareable within a GVC, never across GVCs.\n\n## References\n\n| Type | Keys | Example |\n|---|---|---|\n| opaque | `payload` | `cpln://secret/api-key.payload` |\n| userpass | `username`, `password` | `cpln://secret/creds.password` |\n| tls | `key`, `cert`, `chain` | `cpln://secret/web-tls.cert` |\n| keypair | `secretKey`, `publicKey`, `passphrase` | `cpln://secret/deploy-key.secretKey` |\n| dictionary | user-defined | `cpln://secret/cfg.DB_HOST` |\n| aws / ecr | `accessKey`, `secretKey`, `roleArn`, `externalId` | `cpln://secret/aws.accessKey` |\n\nInject as an env var or a volume (`{ uri: \"cpln://secret/NAME\", path: \"/secrets/x\" }`). Secret mounts are read-only, at most 15 volumes per container, and `/dev`, `/dev/log`, `/tmp`, `/var`, and `/var/log` are rejected. A workload reads a secret when it starts, so a value changed any way other than `rotate_secret` needs a redeploy.\n\n## Pull secrets need no identity or policy\n\nTo pull from a private registry, add a secret of type `docker`, `ecr`, or `gcp` to the GVC's `spec.pullSecretLinks`, and every workload in that GVC can pull. The user enters the registry credentials through the Console link from `create_secret`.\n\n## Manifests for CLI and GitOps users\n\nUsers who keep secrets as code may want a manifest instead of the Console link. Write it with UPPERCASE placeholders, then tell them to fill it in locally, apply it with `cpln apply -f secret.yaml --org ORG` or the Console's cpln apply button, keep the filled file out of git, and delete it after. Never ask for the real value, and never apply the file yourself.\n\n`data` has a fixed shape per type. The trap: for `docker`, `gcp`, and `azure-sdk`, `data` is one JSON string, never a YAML mapping.\n\n```yaml\nkind: secret\nname: my-registry\ntype: docker\ndata: >-\n  {\"auths\":{\"REGISTRY_HOST\":{\"username\":\"USERNAME\",\"password\":\"PASSWORD\"}}}\n```\n\n| `type` | `data` | Validation |\n|---|---|---|\n| `opaque` | `{payload, encoding?}` | `payload` valid base64 when `encoding: base64` (default `plain`) |\n| `dictionary` | object of string values | keys match `[-._a-zA-Z0-9]+` |\n| `userpass` | `{username, password, encoding?}` | none |\n| `tls` | `{cert, key?, chain?}` | `cert` and `key` valid PEM |\n| `keypair` | `{secretKey, publicKey?, passphrase?}` | `secretKey` a valid PEM private key |\n| `aws` | `{accessKey, secretKey, roleArn?, externalId?}` | `accessKey` starts with `AKIA`, `roleArn` with `arn:` |\n| `ecr` | aws fields plus `repos` (1 to 20) | each `ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com[/REPO]` |\n| `azure-connector` | `{url, code}` | `url` is https |\n| `nats-account` | `{accountId, privateKey}` | `accountId` a public nkey (`A…`), `privateKey` a seed (`SA…`) |\n| `docker` | **JSON string** | parses with an `auths` object keyed by registry host |\n| `gcp` | **JSON string** | a full service-account key: `type`, `project_id`, `private_key_id`, `private_key`, `client_email`, `client_id`, `auth_uri`, `token_uri`, `auth_provider_x509_cert_url`, `client_x509_cert_url` |\n| `azure-sdk` | **JSON string** | `subscriptionId`, `tenantId`, `clientId` (UUIDs) and `clientSecret` |\n\n`get_resource_schema` (kind \"secret\") has the apply schema and REST endpoints.\n\n## Verify\n\n- `get_resource` (kind \"workload\"): `spec.identityLink` is set and the env or volume reads `cpln://secret/…`.\n- `get_resource` (kind \"policy\"): the binding grants `reveal` to that identity.\n\n## Common mistakes\n\n- A YAML mapping as `data` on a docker, gcp, or azure-sdk secret.\n- No `identityLink` on the workload, or `view` instead of `reveal`.\n- The bare secret name instead of `cpln://secret/NAME`.\n- Granting before the workload exists, or sharing an identity across GVCs.\n- Editing a policy by hand to unpause a deployment: nothing checks again until the next deploy. Run `grant_workload_secret_access` again instead.\n- An identity and policy for a pull secret, which needs only `pullSecretLinks`.\n"
AFTER
"---\nname: setup-secret\ndescription: Secret access wiring and manifest authoring. Use when a workload needs to read a secret, the user asks to create a secret or generate secret YAML, configure a pull secret, or fix a deployment paused on a secret reference.\n---\n\n# Secret Access Setup\n\nA workload reads a secret only when three things are in place. Miss one and the value is silently absent, or the deployment pauses on the unresolved reference.\n\n| Step | What must be true | Without it |\n|---|---|---|\n| **Identity** | an identity linked to the workload (`spec.identityLink`) | the workload reads nothing |\n| **Policy** | a policy granting that identity `reveal` on the secret | the reference resolves to empty |\n| **Reference** | `cpln://secret/NAME` or `cpln://secret/NAME.KEY` in env or a volume | nothing to read |\n\n`reveal`, not `view`: `view` shows metadata only. This is the most common mistake.\n\n## Creating and rotating\n\n`mcp__cpln__create_secret` creates secrets without a value passing through the chat, and `mcp__cpln__rotate_secret` rotates them; their descriptions cover both paths. Values Control Plane generates and values the user enters belong in separate secrets. Confirm a secret exists (`get_resource`, kind \"secret\") before anything references it.\n\n## Wiring access\n\n- **`deploy_app`** wires all three steps for the references in its env, and refuses a referenced secret that does not exist before it builds or writes anything.\n- **`grant_workload_secret_access`** (`gvc`, `workloadName`, `secretName`) creates the identity if missing (default `{gvc}-{workloadName}`), creates or updates a `reveal` policy (default `{gvc}-{workloadName}-secrets-policy`), links the identity, and redeploys a workload already waiting on the secret. Before writing anything it checks that the secret exists and that an existing policy of that name targets secrets. It does not add the reference. The workload must exist first: create it (its deployment pauses on the reference), then grant, and it resumes.\n- The platform checks access once per deployed version. A version it refused stays refused after the policy changes, until a new version deploys, so the tool grants before it links and redeploys a workload still waiting.\n- **By hand**, only when the tool cannot: `create_identity`, then `create_policy` with target kind `secret` and a `reveal` binding for the identity (`access-control` skill), then `update_workload` to set `spec.identityLink` last.\n- **Revoking:** `grant_workload_secret_access` with `remove: true` takes the secret out of that policy (deleting the policy once it targets nothing) and keeps the identity; it refuses, changing nothing, a policy that also binds another principal or grants by `target: all` or a query. Also drop the `cpln://secret/` reference with `update_workload`: a deploy that still references a revoked secret fails, and running replicas keep the value until they are replaced.\n- Identities are GVC-scoped: one per workload, shareable within a GVC, never across GVCs.\n\n## References\n\n| Type | Keys | Example |\n|---|---|---|\n| opaque | `payload` | `cpln://secret/api-key.payload` |\n| userpass | `username`, `password` | `cpln://secret/creds.password` |\n| tls | `key`, `cert`, `chain` | `cpln://secret/web-tls.cert` |\n| keypair | `secretKey`, `publicKey`, `passphrase` | `cpln://secret/deploy-key.secretKey` |\n| dictionary | user-defined | `cpln://secret/cfg.DB_HOST` |\n| aws / ecr | `accessKey`, `secretKey`, `roleArn`, `externalId` | `cpln://secret/aws.accessKey` |\n\nInject as an env var or a volume (`{ uri: \"cpln://secret/NAME\", path: \"/secrets/x\" }`). Secret mounts are read-only, at most 15 volumes per container, and `/dev`, `/dev/log`, `/tmp`, `/var`, and `/var/log` are rejected. A workload reads a secret when it starts, so a value changed any way other than `rotate_secret` needs a redeploy.\n\n## Pull secrets need no identity or policy\n\nTo pull from a private registry, add a secret of type `docker`, `ecr`, or `gcp` to the GVC's `spec.pullSecretLinks`, and every workload in that GVC can pull. The user enters the registry credentials through the Console link from `create_secret`.\n\n## Manifests for CLI and GitOps users\n\nUsers who keep secrets as code may want a manifest instead of the Console link. Write it with UPPERCASE placeholders, then tell them to fill it in locally, apply it with `cpln apply -f secret.yaml --org ORG` or the Console's cpln apply button, keep the filled file out of git, and delete it after. Never ask for the real value, and never apply the file yourself.\n\n`data` has a fixed shape per type. The trap: for `docker`, `gcp`, and `azure-sdk`, `data` is one JSON string, never a YAML mapping.\n\n```yaml\nkind: secret\nname: my-registry\ntype: docker\ndata: >-\n  {\"auths\":{\"REGISTRY_HOST\":{\"username\":\"USERNAME\",\"password\":\"PASSWORD\"}}}\n```\n\n| `type` | `data` | Validation |\n|---|---|---|\n| `opaque` | `{payload, encoding?}` | `payload` valid base64 when `encoding: base64` (default `plain`) |\n| `dictionary` | object of string values | keys match `[-._a-zA-Z0-9]+` |\n| `userpass` | `{username, password, encoding?}` | none |\n| `tls` | `{cert, key?, chain?}` | `cert` and `key` valid PEM |\n| `keypair` | `{secretKey, publicKey?, passphrase?}` | `secretKey` a valid PEM private key |\n| `aws` | `{accessKey, secretKey, roleArn?, externalId?}` | `accessKey` starts with `AKIA`, `roleArn` with `arn:` |\n| `ecr` | aws fields plus `repos` (1 to 20) | each `ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com[/REPO]` |\n| `azure-connector` | `{url, code}` | `url` is https |\n| `nats-account` | `{accountId, privateKey}` | `accountId` a public nkey (`A…`), `privateKey` a seed (`SA…`) |\n| `docker` | **JSON string** | parses with an `auths` object keyed by registry host |\n| `gcp` | **JSON string** | a full service-account key: `type`, `project_id`, `private_key_id`, `private_key`, `client_email`, `client_id`, `auth_uri`, `token_uri`, `auth_provider_x509_cert_url`, `client_x509_cert_url` |\n| `azure-sdk` | **JSON string** | `subscriptionId`, `tenantId`, `clientId` (UUIDs) and `clientSecret` |\n\n`get_resource` (kind \"secret\", `schema: true`) has the apply schema and REST endpoints.\n\n## Verify\n\n- `get_resource` (kind \"workload\"): `spec.identityLink` is set and the env or volume reads `cpln://secret/…`.\n- `get_resource` (kind \"policy\"): the binding grants `reveal` to that identity.\n\n## Common mistakes\n\n- A YAML mapping as `data` on a docker, gcp, or azure-sdk secret.\n- No `identityLink` on the workload, or `view` instead of `reveal`.\n- The bare secret name instead of `cpln://secret/NAME`.\n- Granting before the workload exists, or sharing an identity across GVCs.\n- Editing a policy by hand to unpause a deployment: nothing checks again until the next deploy. Run `grant_workload_secret_access` again instead.\n- An identity and policy for a pull secret, which needs only `pullSecretLinks`.\n"
Full snapshot data
{
  "description": "Secret access wiring and manifest authoring. Use when a workload needs to read a secret, the user asks to create a secret or generate secret YAML, configure a pull secret, or fix a deployment paused on a secret reference.",
  "included_files": [],
  "name": "setup-secret",
  "skill_md_contents": "---\nname: setup-secret\ndescription: Secret access wiring and manifest authoring. Use when a workload needs to read a secret, the user asks to create a secret or generate secret YAML, configure a pull secret, or fix a deployment paused on a secret reference.\n---\n\n# Secret Access Setup\n\nA workload reads a secret only when three things are in place. Miss one and the value is silently absent, or the deployment pauses on the unresolved reference.\n\n| Step | What must be true | Without it |\n|---|---|---|\n| **Identity** | an identity linked to the workload (`spec.identityLink`) | the workload reads nothing |\n| **Policy** | a policy granting that identity `reveal` on the secret | the reference resolves to empty |\n| **Reference** | `cpln://secret/NAME` or `cpln://secret/NAME.KEY` in env or a volume | nothing to read |\n\n`reveal`, not `view`: `view` shows metadata only. This is the most common mistake.\n\n## Creating and rotating\n\n`mcp__cpln__create_secret` creates secrets without a value passing through the chat, and `mcp__cpln__rotate_secret` rotates them; their descriptions cover both paths. Values Control Plane generates and values the user enters belong in separate secrets. Confirm a secret exists (`get_resource`, kind \"secret\") before anything references it.\n\n## Wiring access\n\n- **`deploy_app`** wires all three steps for the references in its env, and refuses a referenced secret that does not exist before it builds or writes anything.\n- **`grant_workload_secret_access`** (`gvc`, `workloadName`, `secretName`) creates the identity if missing (default `{gvc}-{workloadName}`), creates or updates a `reveal` policy (default `{gvc}-{workloadName}-secrets-policy`), links the identity, and redeploys a workload already waiting on the secret. Before writing anything it checks that the secret exists and that an existing policy of that name targets secrets. It does not add the reference. The workload must exist first: create it (its deployment pauses on the reference), then grant, and it resumes.\n- The platform checks access once per deployed version. A version it refused stays refused after the policy changes, until a new version deploys, so the tool grants before it links and redeploys a workload still waiting.\n- **By hand**, only when the tool cannot: `create_identity`, then `create_policy` with target kind `secret` and a `reveal` binding for the identity (`access-control` skill), then `update_workload` to set `spec.identityLink` last.\n- **Revoking:** `grant_workload_secret_access` with `remove: true` takes the secret out of that policy (deleting the policy once it targets nothing) and keeps the identity; it refuses, changing nothing, a policy that also binds another principal or grants by `target: all` or a query. Also drop the `cpln://secret/` reference with `update_workload`: a deploy that still references a revoked secret fails, and running replicas keep the value until they are replaced.\n- Identities are GVC-scoped: one per workload, shareable within a GVC, never across GVCs.\n\n## References\n\n| Type | Keys | Example |\n|---|---|---|\n| opaque | `payload` | `cpln://secret/api-key.payload` |\n| userpass | `username`, `password` | `cpln://secret/creds.password` |\n| tls | `key`, `cert`, `chain` | `cpln://secret/web-tls.cert` |\n| keypair | `secretKey`, `publicKey`, `passphrase` | `cpln://secret/deploy-key.secretKey` |\n| dictionary | user-defined | `cpln://secret/cfg.DB_HOST` |\n| aws / ecr | `accessKey`, `secretKey`, `roleArn`, `externalId` | `cpln://secret/aws.accessKey` |\n\nInject as an env var or a volume (`{ uri: \"cpln://secret/NAME\", path: \"/secrets/x\" }`). Secret mounts are read-only, at most 15 volumes per container, and `/dev`, `/dev/log`, `/tmp`, `/var`, and `/var/log` are rejected. A workload reads a secret when it starts, so a value changed any way other than `rotate_secret` needs a redeploy.\n\n## Pull secrets need no identity or policy\n\nTo pull from a private registry, add a secret of type `docker`, `ecr`, or `gcp` to the GVC's `spec.pullSecretLinks`, and every workload in that GVC can pull. The user enters the registry credentials through the Console link from `create_secret`.\n\n## Manifests for CLI and GitOps users\n\nUsers who keep secrets as code may want a manifest instead of the Console link. Write it with UPPERCASE placeholders, then tell them to fill it in locally, apply it with `cpln apply -f secret.yaml --org ORG` or the Console's cpln apply button, keep the filled file out of git, and delete it after. Never ask for the real value, and never apply the file yourself.\n\n`data` has a fixed shape per type. The trap: for `docker`, `gcp`, and `azure-sdk`, `data` is one JSON string, never a YAML mapping.\n\n```yaml\nkind: secret\nname: my-registry\ntype: docker\ndata: >-\n  {\"auths\":{\"REGISTRY_HOST\":{\"username\":\"USERNAME\",\"password\":\"PASSWORD\"}}}\n```\n\n| `type` | `data` | Validation |\n|---|---|---|\n| `opaque` | `{payload, encoding?}` | `payload` valid base64 when `encoding: base64` (default `plain`) |\n| `dictionary` | object of string values | keys match `[-._a-zA-Z0-9]+` |\n| `userpass` | `{username, password, encoding?}` | none |\n| `tls` | `{cert, key?, chain?}` | `cert` and `key` valid PEM |\n| `keypair` | `{secretKey, publicKey?, passphrase?}` | `secretKey` a valid PEM private key |\n| `aws` | `{accessKey, secretKey, roleArn?, externalId?}` | `accessKey` starts with `AKIA`, `roleArn` with `arn:` |\n| `ecr` | aws fields plus `repos` (1 to 20) | each `ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com[/REPO]` |\n| `azure-connector` | `{url, code}` | `url` is https |\n| `nats-account` | `{accountId, privateKey}` | `accountId` a public nkey (`A…`), `privateKey` a seed (`SA…`) |\n| `docker` | **JSON string** | parses with an `auths` object keyed by registry host |\n| `gcp` | **JSON string** | a full service-account key: `type`, `project_id`, `private_key_id`, `private_key`, `client_email`, `client_id`, `auth_uri`, `token_uri`, `auth_provider_x509_cert_url`, `client_x509_cert_url` |\n| `azure-sdk` | **JSON string** | `subscriptionId`, `tenantId`, `clientId` (UUIDs) and `clientSecret` |\n\n`get_resource` (kind \"secret\", `schema: true`) has the apply schema and REST endpoints.\n\n## Verify\n\n- `get_resource` (kind \"workload\"): `spec.identityLink` is set and the env or volume reads `cpln://secret/…`.\n- `get_resource` (kind \"policy\"): the binding grants `reveal` to that identity.\n\n## Common mistakes\n\n- A YAML mapping as `data` on a docker, gcp, or azure-sdk secret.\n- No `identityLink` on the workload, or `view` instead of `reveal`.\n- The bare secret name instead of `cpln://secret/NAME`.\n- Granting before the workload exists, or sharing an identity across GVCs.\n- Editing a policy by hand to unpause a deployment: nothing checks again until the next deploy. Run `grant_workload_secret_access` again instead.\n- An identity and policy for a pull secret, which needs only `pullSecretLinks`.\n"
}

SHA-256 of public snapshot: bb938e6ee95dd9cacdc9be7097a1198991f38236a0e101f765077064d130766b