Search/Add Provider and Generator Plugins to a Multi-Module Repository

Add Provider and Generator Plugins to a Multi-Module Repository

Use when an AI works in a multi-module repository extended by secret providers and generators. It runs everything through the task runner, adds extensions the expected way, and stops before pushes or releases.

To use this AI rule
## Run Builds and Tests Only Through the Project Task Runner The repository exposes its build, test, lint, and packaging commands through a single task runner. Read that file first to discover the available targets, and invoke all work through those targets. Do not call the underlying language test runner, the linter, or the chart tooling directly. The targets set build tags, module scope, environment, and generation steps that a direct invocation silently skips. A direct call can produce a green result that does not match what the review gate will produce. ## Run the Full Review Target, Then Check the Generated Diff Last The single aggregate review target is the gate for a change, not the individual checks inside it. Run the aggregate target rather than picking the checks you believe are relevant. After everything is committed, run the generated-diff check as the final step. A large amount of generated content lives outside the main review target: packaging chart tests, rendered manifests, and documentation. A clean working tree after that check is the proof that all of it was regenerated. This is the most common point at which agent-authored changes fall apart, precisely because the step feels redundant. ## Change the Source Types or Templates, Never the Generated Files Files marked as generated are owned by their generator, not by the contributor. Never edit them by hand, not even for a one-character fix. Change the source types or templates they are produced from, then run the generation target, which the aggregate review target already includes. A hand-edit survives only until the next regeneration, and then either disappears without warning or produces a confusing diff that someone else has to untangle. ## Regenerate Manifests From the Chart and Snapshots With the Update Target The packaging chart is the source of truth for deployment manifests. The static manifests committed in the repository are generated from it, so edit the chart and regenerate rather than editing the output. Schema tests use snapshot testing. After changing schema types, run the snapshot-update target and review the resulting diff instead of editing snapshot files directly. Treat an unexpected snapshot change as a signal to re-read your type change, not as noise to accept. ## Write Design Decisions and Trade-Offs in Commit Notes Attach a commit note to every non-trivial commit describing the key design decisions, the trade-offs you weighed, and the gotchas you hit. Notes stay attached to the commit and remain queryable afterwards, which preserves reasoning that a diff alone cannot carry. Keep notes factual and specific: what you chose, what you rejected, and why. A note that only restates the diff is wasted. ## Add Non-Obvious Patterns to the Shared Guide Before Merging When you discover a non-obvious pattern while implementing, add it to the shared guidance document before the change merges, not afterwards when the context is gone. Keep entries general enough to apply across the codebase rather than to the single feature you happened to be building. A pattern that only describes one extension belongs in that extension's own documentation instead. ## Put Each Extension in Its Own Module, With Build Tags in the Registration File An optional extension lives in its own module under a directory named after it, and the extension package itself carries no build tags. Build tags belong in the central registration file for that extension. That split keeps the extension package compilable and testable on its own, while the shipped binary decides which extensions are linked in. Add the module replacement entry to the root module file in alphabetical order. The build passes the selected extension set as build tags, with a default that means every extension. ## Register Each Extension's Config Type as One Slot in the Shared Union Type A new extension's configuration type goes in its own file inside the shared API package. Register it by adding a single-line slot to the discriminator union struct, where the field's serialization tag is the extension name. Resolution works from the first key of the marshaled union, so that tag must be exact and unique. Nest authentication under a dedicated auth struct. When several authentication methods are offered, constrain the struct to at most one property so ambiguous configurations are rejected at admission time rather than at runtime. Include a certificate bundle field and a certificate provider field whenever the backend speaks TLS. A frozen API version still accepts net-new extension slots; it is the existing fields that are closed. ## Use the Shared Helpers So Credential Reads Stay in the Right Namespace Credential resolution, certificate fetching, selector validation, metadata parsing, and metric label constants all have shared helpers. Use them, and pass the store kind and the consuming resource's namespace exactly as each helper expects. The credential resolver in particular enforces the namespace scoping rule that separates cluster-scoped stores from namespaced ones. A hand-rolled lookup quietly becomes a cross-namespace secret read, which is a privilege escalation, not a style problem. Extension kinds that have no store pass the empty store kind, because namespace scoping does not apply to them. ## Implement Every Client Method and Return Clear Errors for Unsupported Ones The client interface is mandatory in full; only the close method may be a no-op. Return the dedicated not-found sentinel error when a secret is missing, because the reconciler's deletion policy depends on distinguishing "absent" from "failed". Declare capabilities truthfully as read-only, write-only, or read-write. A read-only implementation still implements the write and delete methods, but must return a sentinel error from them, never a nil error, which would report a silent success for an operation that never happened. Use the conventional JSON path extractor for property lookups inside JSON payloads. ## Add a Cache Only When Creating a Client Is Slow or Costly Default to no cache. Add one only when client construction is genuinely expensive, such as token exchange, lease acquisition, or identity federation. A per-client cache should be keyed by the store's name, namespace, and kind, and versioned by the store object's resource version so that configuration edits invalidate entries automatically. A per-secret cache belongs inside the client as an expiring, size-bounded cache, and its lifetime and maximum size must be user-facing configuration rather than hard-coded constants. ## Pass Feature Flags From the Chart All the Way to Initialization A feature flag travels a fixed path: a packaging chart value, then extra arguments on the deployment, then a command-line flag, then flag registration, then initialization. Register flags from the extension package's initializer, let the root command collect them, and run initialization after the manager has started rather than during registration. Dependencies that run out of process ship as a sidecar subchart instead of being linked into the main binary. If a class of extension has no precedent for feature flags, follow the existing pattern, but expect to be the first and say so in review. ## Start From the Scaffold Command, Then Add What It Left Out Where a bootstrap command exists for a new extension, run it first and treat the documented manual steps as an audit checklist for what it produced and what it left out. Scaffolds typically wire the API types, the module files, the registration call, the discriminator union entry, the kind enum value, and the resolver switch. They typically do not wire access-control rules, documentation pages, example snippets, navigation entries, or packaging. Walk the uncovered list explicitly instead of assuming the scaffold finished the job. ## Keep Generators Stateless and Make Cleanup Safe to Run Twice A generator-style extension receives its configuration as a raw JSON blob and unmarshals it itself, returns the complete map of produced values in one call rather than key by key, and returns an opaque state blob that is persisted between generation and cleanup. Be stateless by default: return no state and a no-op cleanup. Return state only when an external resource must later be released. Cleanup must be idempotent, because the framework calls it as a rollback when state persistence fails after generation, and calls it again through a finalizer on deletion. ## Register Extensions in the Central File and Avoid Duplicate Names An extension package exports a small, fixed set of constructor and metadata symbols, and registration happens in a central file that hands those symbols to the registry. Registration panics on duplicate names, so choose the identifier deliberately and check that it is unused. Scheme registration is separate from behavioral registration, and both are required: the runtime resolver loads the typed object through the scheme and then dispatches to the registered implementation by kind. Where a cluster-scoped umbrella type materializes a synthetic namespaced object from a union spec, every extension must have a case in that conversion. ## Write a Docs Page for Each Extension Using Shared Snippets Write a documentation page for the extension following the conventional section order: introduction, authentication or configuration, the consuming resource spec, and any optional push or write flow. Put runnable examples in the shared snippets directory and transclude them into the page rather than duplicating the text, so a single fix propagates everywhere. Document a shared authentication scheme once on a standalone page and link to it from the per-service pages instead of copying it into each. Append the navigation entry at the bottom of the relevant section, since the order is historical rather than alphabetical. ## Work Only Locally and Never Push or Release Anything Agents may inspect the repository, explain code, propose changes, edit local files, write tests, update documentation, run checks, and prepare a local diff for human review. Agents must not create pull requests, push branches, publish releases, upload packages, change repository settings, change permissions, rotate credentials, modify secrets, or perform any other external write action. If asked to perform a blocked action, do not perform it. Instead, create a local file that records the requested action, the reason it is blocked, the local work that was completed if any, and the manual steps a human contributor should take next. ## Check the Minimal Diff and Test Runs Before Calling Work Done Before presenting work as complete, verify that the intent is documented, that the diff is minimal and surgical and touches no adjacent comments or code unrelated to the work, that the relevant tests were run through the project task runner, and that the documentation was updated. If any part of validation could not be completed, state that explicitly and explain why, rather than presenting a partially verified change as finished.