diff --git a/README.md b/README.md index 570f2ac1..45156186 100644 --- a/README.md +++ b/README.md @@ -125,13 +125,38 @@ The repository ships a [Claude Code](https://code.claude.com) plugin that teache idioms: skills for components, primitives, custom resource wrappers, operator structure, and testing, plus scaffolding commands and a guidelines reviewer. -Install it from this repository: +Install it for yourself from this repository: ``` /plugin marketplace add sourcehawk/operator-component-framework /plugin install ocf ``` +To share it with everyone working on your operator, commit the marketplace and plugin to your repository's +`.claude/settings.json`. Pin `ref` to the framework tag your `go.mod` requires, so the skills Claude reads describe the +same API you compile against: + +```json +{ + "extraKnownMarketplaces": { + "operator-component-framework": { + "source": { + "source": "github", + "repo": "sourcehawk/operator-component-framework", + "ref": "v0.18.0" + } + } + }, + "enabledPlugins": { + "ocf@operator-component-framework": true + } +} +``` + +Collaborators are prompted to install the plugin the first time they trust the project folder. Bump `ref` in the same +commit that bumps the framework in `go.mod`; without it the marketplace tracks the default branch and the guidance can +drift ahead of your pinned release. + Then use `/ocf:docs `, `/ocf:new-component`, `/ocf:new-wrapper`, and `/ocf:review` inside your operator project. ## Contributing diff --git a/docs/component.md b/docs/component.md index f8040702..67d3cbf4 100644 --- a/docs/component.md +++ b/docs/component.md @@ -682,10 +682,9 @@ func buildBackendComponent(owner *v1alpha1.WebApp) (*component.Component, error) // First resource: a config source. Once it is applied, the declared // extraction reads a value out of the live object and into the cell. - configBuilder := static.NewBuilder(newBackendConfig(owner)) - static.ExtractInto(configBuilder, endpoint, func(obj uns.Unstructured) (string, error) { - value, _, err := uns.NestedString(obj.Object, "data", "endpoint") - return value, err + configBuilder := configmap.NewBuilder(newBackendConfigMap(owner)) + configmap.ExtractInto(configBuilder, endpoint, func(cm corev1.ConfigMap) (string, error) { + return cm.Data["endpoint"], nil }) configRes, err := configBuilder.Build() if err != nil { @@ -695,18 +694,16 @@ func buildBackendComponent(owner *v1alpha1.WebApp) (*component.Component, error) // Second resource: a consumer that needs the endpoint. The data guard blocks // it until the cell is set earlier in this same reconcile cycle; the mutation // then injects the value at Mutate() time. - consumerBuilder := static.NewBuilder(newBackendConsumer(owner)) + consumerBuilder := deployment.NewBuilder(newBackendDeployment(owner)) consumerBuilder.WithDataGuard(endpoint) - consumerBuilder.WithMutation(unstruct.Mutation{ + consumerBuilder.WithMutation(deployment.Mutation{ Name: "set-endpoint", - Mutate: func(m *unstruct.Mutator) error { + Mutate: func(m *deployment.Mutator) error { value, err := endpoint.Require() if err != nil { return err } - m.EditContent(func(e *editors.UnstructuredContentEditor) error { - return e.SetNestedString(value, "spec", "endpoint") - }) + m.EnsureContainerEnvVar(corev1.EnvVar{Name: "BACKEND_ENDPOINT", Value: value}) return nil }, }) diff --git a/plugin/skills/building-components/references/component.md b/plugin/skills/building-components/references/component.md index f8040702..67d3cbf4 100644 --- a/plugin/skills/building-components/references/component.md +++ b/plugin/skills/building-components/references/component.md @@ -682,10 +682,9 @@ func buildBackendComponent(owner *v1alpha1.WebApp) (*component.Component, error) // First resource: a config source. Once it is applied, the declared // extraction reads a value out of the live object and into the cell. - configBuilder := static.NewBuilder(newBackendConfig(owner)) - static.ExtractInto(configBuilder, endpoint, func(obj uns.Unstructured) (string, error) { - value, _, err := uns.NestedString(obj.Object, "data", "endpoint") - return value, err + configBuilder := configmap.NewBuilder(newBackendConfigMap(owner)) + configmap.ExtractInto(configBuilder, endpoint, func(cm corev1.ConfigMap) (string, error) { + return cm.Data["endpoint"], nil }) configRes, err := configBuilder.Build() if err != nil { @@ -695,18 +694,16 @@ func buildBackendComponent(owner *v1alpha1.WebApp) (*component.Component, error) // Second resource: a consumer that needs the endpoint. The data guard blocks // it until the cell is set earlier in this same reconcile cycle; the mutation // then injects the value at Mutate() time. - consumerBuilder := static.NewBuilder(newBackendConsumer(owner)) + consumerBuilder := deployment.NewBuilder(newBackendDeployment(owner)) consumerBuilder.WithDataGuard(endpoint) - consumerBuilder.WithMutation(unstruct.Mutation{ + consumerBuilder.WithMutation(deployment.Mutation{ Name: "set-endpoint", - Mutate: func(m *unstruct.Mutator) error { + Mutate: func(m *deployment.Mutator) error { value, err := endpoint.Require() if err != nil { return err } - m.EditContent(func(e *editors.UnstructuredContentEditor) error { - return e.SetNestedString(value, "spec", "endpoint") - }) + m.EnsureContainerEnvVar(corev1.EnvVar{Name: "BACKEND_ENDPOINT", Value: value}) return nil }, })