Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <topic>`, `/ocf:new-component`, `/ocf:new-wrapper`, and `/ocf:review` inside your operator project.

## Contributing
Expand Down
17 changes: 7 additions & 10 deletions docs/component.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
},
})
Expand Down
17 changes: 7 additions & 10 deletions plugin/skills/building-components/references/component.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading