# 02 — The generation-rule-only pattern ## What you'll do Understand the split of responsibilities between this private code collection (rules + templates only) and the shared `rw-generic-codecollection` (the actual Robot runtime). ## Traditional codebundle vs. rules-only codebundle A **traditional** codebundle looks like this: ``` codebundles/k8s-my-thing/ meta.yaml README.md runbook.robot # ← runtime sli.robot # ← runtime .runwhen/ generation-rules/*.yaml templates/*.yaml # templates reference this bundle's own robots ``` A **rules-only** codebundle looks like this — this is the pattern we are teaching: ``` codebundles/gcp-bucket-crossplane-health/ README.md .runwhen/ generation-rules/gcp-bucket-crossplane-health.yaml templates/ gcp-bucket-crossplane-health-slx.yaml gcp-bucket-crossplane-health-sli.yaml gcp-bucket-crossplane-health-taskset.yaml ``` Notice: no `meta.yaml`, no `runbook.robot`, no `sli.robot`. The templates still reference `pathToRobot`, but they point at a **different** code collection. ## The delegation trick Look at [`gcp-bucket-crossplane-health-sli.yaml`](../codebundles/gcp-bucket-crossplane-health/.runwhen/templates/gcp-bucket-crossplane-health-sli.yaml): ```yaml codeBundle: repoUrl: http://rw-airgap-cc-catalog-svc.runwhen-env-airgap:8080/git/rw-generic-codecollection.git ref: main pathToRobot: codebundles/k8s-kubectl-cmd/sli.robot configProvided: - name: KUBECTL_COMMAND value: | kubectl get buckets.storage.gcp.upbound.io {{match_resource.resource.metadata.name}} ... ``` `repoUrl` points at the airgap cc-catalog proxy for `rw-generic-codecollection`. `pathToRobot` picks the generic `k8s-kubectl-cmd/sli.robot`. `configProvided.KUBECTL_COMMAND` is the actual command we want that generic robot to run — parameterized by the discovered resource's name via the `match_resource` Jinja variable. At runtime, the workflow is: ```mermaid sequenceDiagram participant WB as workspace-builder participant CR as Cluster (kubeapi) participant Repo as private CC (Gitea) participant PAPI as RunWhen Platform participant Worker as Runner Worker participant Generic as rw-generic-codecollection WB->>Repo: git clone (with token) WB->>CR: list buckets.storage.gcp.upbound.io CR-->>WB: [ Bucket A, Bucket B, ... ] WB->>WB: match rule; render templates WB->>PAPI: upload N SLXs (each with codeBundle.repoUrl = rw-generic) PAPI->>Worker: schedule SLI + TaskSet runs Worker->>Generic: clone at ref=main; load k8s-kubectl-cmd Worker->>CR: KUBECTL_COMMAND (kubectl + jq) CR-->>Worker: JSON status Worker->>PAPI: push metric / issues ``` ## Why not just put the robot files in the private CC? Because then every consumer of the private CC would need to run the runner-side clone and image handling for those robots. The airgap runner's `runner.codeCollections` list would have to include this repo (with the same token concerns). By keeping the private CC as **rules and templates only**, you never have to update the runner-side collections list — the Robot code always resolves to the same shared, cached, image-baked generic collection that the runner already knows how to load. ## The template variables you have At render time, workspace-builder passes each template a rich context. The most useful entries for our use case: | Variable | Value in our case | |----------|-------------------| | `slx_name` | Generated SLX name, e.g. `shared-cluster-runwhen-nonprod-shared-litellm-logging-xp-bkt-hlth` | | `match_resource.resource` | The full Kubernetes object as returned by the API | | `match_resource.resource.metadata.name` | The Bucket's name | | `match_resource.kind` | `Bucket` (for CRDs, filled by the indexer) | | `match_resource.qualified_name` | The composite ID used by the resource registry | | `qualifiers` | The dict populated per your `qualifiers` list in the rule (`resource`, `cluster`) | | `cluster.name` | The Kubernetes cluster name (e.g. `shared-cluster`) | | `default_location` | Workspace default runner location | | `workspace.owner_email` | From `workspaceInfo.workspaceOwnerEmail` | | `custom.kubeconfig_secret_name` | From the `custom:` block in workspaceInfo | | `wb_version` | Set only in newer workspace-builders (used to gate the newer `kubernetes-auth.yaml` include) | ## Screenshot placeholders - `images/02-side-by-side-file-tree.png` — screenshot of the two directory trees (traditional vs. rules-only) side by side. - `images/02-render-sequence.png` — annotated version of the sequence diagram above (optional). ## Next Continue to [03 — Crossplane CRD discovery](03-crossplane-crd-discovery.md).