Config Connector (KCC) Authoring
SkillDatabases & dataAuthors Config Connector (KCC) manifests for Google Cloud resource changes and hands them to submit-suggestion as a pull request under the GitOps repository's clusters/<cluster>/provisioning/ path. Use when a request changes a GKE cluster or node pool (grow, autoscale, adopt), a Cloud SQL instance (add a read replica, resize), or a VPC firewall rule on an install whose GitOps repository holds Config Connector YAML. Decides create versus acquire read-only, validates every field with kubectl explain against the customer's CRDs, and never applies. Don't use for Kubernetes workload manifests (use gke-manifest-generation), imperative cluster creation (use gke-cluster-creation), or Terraform HCL.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Config Connector (KCC) Authoring skill
What this skill tells your AI
The instructions your AI receives, as published by gke-labs/kube-agents in agents/platform/skills/gcp-config-connector/SKILL.md and read by ahel’s review.
A Google Cloud change leaves this agent only one way: as a Config Connector manifest in the GitOps repository, reviewed by a human and applied by the customer's reconciler. This skill writes that manifest. It reads the cluster and the cloud project to decide what to write, validates the result against the CRDs the customer actually runs, and opens the pull request through submit-suggestion. Nothing here mutates a cluster or a project, and the command policy refuses the verbs that would.
When to Use
- A GKE node pool or cluster change — grow or shrink a pool, turn on autoscaling, change a release channel or maintenance window, adopt a cluster the repo does not yet describe.
- A Cloud SQL change — add a read replica, change a tier, enable backups or high availability.
- A VPC firewall rule — open or close a port, narrow a source range, disable a rule, turn on logging.
- Adopting a resource that exists in Google Cloud but has no manifest in the repository (acquisition).
When NOT to Use
- Kubernetes workloads (Deployments, Services, NetworkPolicies): the
gke-manifest-generationskill. - Creating a cluster imperatively with the
gkeMCP tools orgcloud: thegke-cluster-creationskill. - A repository whose
provisioning/holds Terraform HCL rather than KCC YAML: say so and stop. This skill authors KRM only. - Kinds outside the families catalogued in
references/. Other Config Connector kinds follow the same annotations and workflow, but their immutable fields are not catalogued here; validate every field withkubectl explainand say in the PR body that the kind is outside the catalogued set. - Fixing a fleet-audit finding: the
fleet-auditskill opens that PR.
Prerequisites (the customer's, not yours)
Config Connector is a customer platform decision. Never propose installing or enabling it; state the missing piece and stop.
- The CRDs are installed on a cluster your kubeconfig reaches. The
check is
kubectl get crd <kind-plural>.<group>.cnrm.cloud.google.com(Step 1). No CRD means no schema to validate against and no controller to reconcile the manifest. Stop with: "Config Connector is not installed on<context>; this change needs a KCC-enabled cluster before I can author it." - The repository has a KCC path.
clusters/<cluster>/provisioning/in the reference layout, holding YAML withcnrm.cloud.google.comapiVersions. If the repo has no such directory and the user has not named one, ask rather than invent a layout. - A namespace bound to a project. The sibling manifests carry either a
cnrm.cloud.google.com/project-idannotation on each resource or on the namespace (ConfigConnectorContext). Copy what the siblings do. - Read access to the
cnrm.cloud.google.comAPI groups for the create-versus-acquire check. Which identity answers depends on where the KCC objects live: on the management cluster reached in-cluster, the read-only ClusterRole the operator ships grants none of those groups, sokubectl auth can-isaysno; on a separate hub reached throughget-credentials, the Google service account's IAM permission set decides, and the defaultread-onlyset's cluster-viewer role does read custom resources. Either way anois a fact to report, not an absence to infer from.
Workflow
Step 1: Check for Config Connector, then open the repository
The CRD check comes first because it needs no repository and is the stop you hit most often:
kubectl get crd containernodepools.container.cnrm.cloud.google.com
Not found is prerequisite 1 unmet: stop with the message there, before
anything is opened. With the CRD present, open the repository with
submit-suggestion prepare (its Step 1). It needs the branch name up
front, and the convention for this skill is platform-agent/kcc-<kind>-<name>,
the same branch Step 5 submits on. Then list what is already under
provisioning/:
S="$HERMES_HOME"/skills/submit-suggestion/scripts/submit_suggestion.py
SCRATCH=$(mktemp -d)
"$S" prepare --repo "<owner>/<repo>" --branch "platform-agent/kcc-<kind>-<name>"
"$S" list --handle "<handle>" --prefix clusters/<cluster>/provisioning
"$S" fetch --handle "<handle>" --path clusters/<cluster>/provisioning/<sibling>.yaml --to "$SCRATCH"
(Directory mode: ls and cat inside the returned workspace.) From a
sibling manifest take the metadata.namespace, how the project is bound,
the label conventions, and one file per resource or one per kind. A manifest
for the resource you were asked to change may already be there; then the
change is an edit to that file, and Step 2's answer is "edit".
Close the handle on every stop before Step 5. In content mode prepare
cloned the repository on the credential broker, which holds at most eight
open workspaces, releases one only when submit runs against it, and never
times one out; eight abandoned runs and no skill on the install can prepare
until the broker restarts. submit_suggestion.py has no close, so use the
inspect-repository script's, which releases any handle:
python3 "$HERMES_HOME"/skills/inspect-repository/scripts/inspect_repository.py close --handle "<handle>"
Run it before you report Terraform HCL under provisioning/, a stop or a
question from Step 2's table, an immutable field in Step 3, or a CRD Step 4
finds missing. When the user answers and the work resumes, prepare again.
Directory mode has no handle to close; an abandoned lease is reaped after its
TTL.
Step 2: Decide create, acquire, or edit — read-only
Config Connector acquires an existing Google Cloud resource when a new
manifest's name (or spec.resourceID) matches it, and creates one when
nothing matches. A create manifest for a resource that exists silently adopts
it after merge; an acquisition manifest whose stated immutable fields differ
from the live resource fails in status.conditions with cannot make changes to immutable field(s). Decide before you write, and say which in the PR body.
Check permission before the object read, so a Forbidden is reported as
such rather than mistaken for "not there":
kubectl auth can-i get containernodepools.container.cnrm.cloud.google.com -n <namespace>
kubectl get containernodepool <name> -n <namespace> -o yaml
Then the live resource, with the reads the command policy allows:
gcloud container clusters describe <cluster> --location <location> --project <project> --format=json
gcloud container node-pools describe <pool> --cluster <cluster> --location <location> --project <project> --format=json
gcloud compute firewall-rules describe <rule> --project <project> --format=json
| Manifest in repo | KCC object in cluster | Resource in Google Cloud | Decision |
|---|---|---|---|
| yes | any | any | Edit that file. Touch only the fields the request needs. |
| no | yes | yes | Stop. Something outside the repo manages it; report the object. |
| no | yes | no | Stop. A failed or in-flight create; report its status.conditions. |
| no | no | yes | Acquire. references/acquisition.md. |
| no | no | no | Create. |
| no | forbidden / no KCC | unknown | Report what you could not read. Ask the user which it is; do not assume. |
gcloud sql has no entry on the read allowlist. For a SQLInstance the
in-cluster object is the only read you have; when that is forbidden or
absent, ask the user to confirm whether the instance exists rather than
guessing (references/sql.md).
Step 3: Author the manifest
- apiVersion
v1beta1of the kind's group; per-family details inreferences/. metadata.namespace: the siblings' namespace. Neverdefault, never a namespace you did not see in the repo.- Annotations on every manifest (
references/acquisition.mdexplains each):cnrm.cloud.google.com/deletion-policy: abandon— a pruned or deleted manifest detaches the resource instead of destroying it.cnrm.cloud.google.com/state-into-spec: absent— Config Connector leaves fields the manifest omits under external management instead of writing live state back intospec, which a pull reconciler would read as drift.cnrm.cloud.google.com/project-id: <project>when the siblings set it per resource; omit it when they rely on the namespace binding.
- Acquisition adds an explicit
spec.resourceIDequal to the Google Cloud resource name, and every immutable field it does state is copied from the live resource so the spec matches what exists. - Write the fields the request needs plus the required ones, nothing else. An omitted field stays externally managed; a copied default becomes a managed field the next reviewer has to reason about.
- Immutable fields are the line. If the request can only be met by changing one (a machine type, a region, a firewall's network), the answer is replacement, not an edit: say so, name the field, and stop for the user's decision. Never author a replacement unasked.
- Names: Kubernetes names in
metadata.name; a Google Cloud name that is not a valid Kubernetes name goes inspec.resourceID.
Step 4: Validate against the customer's CRDs
Server-side dry-run is a write from the API server's point of view: it needs
write RBAC the platform role lacks, and the command policy refuses apply,
create, and diff regardless. Validate with the schema instead:
kubectl explain containernodepool --api-version=container.cnrm.cloud.google.com/v1beta1
kubectl explain containernodepool.spec.autoscaling --api-version=container.cnrm.cloud.google.com/v1beta1
kubectl explain containernodepool.spec.autoscaling.totalMaxNodeCount --api-version=container.cnrm.cloud.google.com/v1beta1
- Run
explainon the kind and on everyspec.<path>you wrote. A path the CRD does not have is a field the customer's Config Connector version does not know; drop or rename it, do not ship it. - A description that begins
Immutable.marks an immutable field. That is the authority over the lists inreferences/, which were written against one version of the CRDs. explainreads discovery, which every authenticated user has, so it works even whereauth can-i getsaidno.- A missing CRD (
explainreports the resource is not found) is prerequisite 1 unmet: stop with the message there.
Step 5: Hand off as a pull request
Write the manifest into the scratch directory (content mode) or the workspace
(directory mode) at clusters/<cluster>/provisioning/<kind>-<name>.yaml
unless the siblings use another convention, and submit it through
submit-suggestion with branch platform-agent/kcc-<kind>-<name>. Use
this shape for --body, after the skill's standard header:
### Config Connector change
- **Decision:** create | acquire | edit — and the reads that decided it
(object present/absent, the `describe` result, or "user confirmed").
- **Resource:** <kind> `<name>` in project `<project>`, location `<location>`.
- **Immutable fields touched:** none | <field> (this PR proposes replacement; see below).
- **Validated:** `kubectl explain` on <kind> and <n> spec paths against the CRDs on `<context>`.
- **Not run here:** `kubectl apply --dry-run=server`. The agent is read-only; run it on the
KCC cluster before merging, or let CI do it.
- **After merge:** the reconciler applies; KCC reports readiness in the object's `status.conditions`.
Record the PR URL for the user. Addressing review feedback follows submit-suggestion Step 5.
Red Lines
- No
kubectl apply,create,patch,edit,delete,diff, or any--dry-run=server; no mutatinggcloud. The command policy refuses them and a refusal is not a retry prompt. - Never set
deletion-policytononeor remove the annotation. Deleting a resource is a human's PR that flips it deliberately. - Never delete a manifest under
provisioning/to "recreate" a resource. - Never fill in a project, namespace, network, or location you did not read from the repository, the cluster, or the user.
- Never propose enabling Config Connector, granting its IAM, or creating a
ConfigConnectorContext. - Never leave a content-mode handle open when you stop; Step 1 says how to close it.
References
- Acquisition and annotations: how Config Connector matches a manifest to an existing resource, what each annotation does, and the immutable-field failure modes.
- ContainerCluster and ContainerNodePool:
fields, immutables,
describe-to-spec mapping, create and acquire examples. - SQLInstance: read replicas, tier changes, the
missing
gcloud sqlread, create and acquire examples. - ComputeFirewall: rule shape,
immutables,
describe-to-spec mapping, create and acquire examples.
Signals
- GitHub stars
- 61
- Forks
- 36
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
gcp-config-connector- Source
- github.com/gke-labs/kube-agents