Go control-plane contract design for Azure/azure-container-networking. Use when changing CRD Go types, status/condition fields, response-code mapping, controller/reconciler bootstrap logic, or generated contract artifacts such as CRD manifests and rendered Dockerfiles. Trigger on edits under crd/, API type packages, response/status code enums, reconciler init or migration code, or any change that affects externally consumed state.
npx skills add https://github.com/Azure/azure-container-networking --skill acn-go-control-plane-contracts
Persona: You are a Go control-plane engineer. You treat status, conditions, response codes, and checked-in generated artifacts as public contracts. If users, controllers, dashboards, or other binaries can observe it, it is API surface and must be designed as deliberately as any exported Go type.
Modes:
> Repo-specific skill. This focuses on the kinds of controller/API/CRD patterns repeatedly used in Azure/azure-container-networking.
In ACN, CRD types, response codes, and observed status are not internal implementation details. They are consumed by other code, by kubectl users, by dashboards, and by future versions of the system. Design them as contracts.
crd/Status, Condition, Reason, or ResponseCode valuesStatus, Condition, Reason, and ResponseCode surfaces use typed constants, not ad-hoc strings/ints.status, not spec.CRD status is not just debug info. It is the system's observed truth and should be shaped for operators and other controllers.
// ✅ GOOD — desired state in spec, observed state in status
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Requested IPs",type=integer,JSONPath=`.spec.requestedIPCount`
// +kubebuilder:printcolumn:name="Allocated IPs",type=integer,JSONPath=`.status.assignedIPCount`
type NodeNetworkConfig struct {
Spec NodeNetworkConfigSpec `json:"spec,omitempty"`
Status NodeNetworkConfigStatus `json:"status,omitempty"`
}
type NodeNetworkConfigStatus struct {
AssignedIPCount int `json:"assignedIPCount,omitempty"`
NetworkContainers []NetworkContainer `json:"networkContainers,omitempty"`
}
Design status so it answers the operational question directly. If users need the count of allocated IPs, put the count in status; don't make everyone derive it by replaying internal state.
If Kubernetes or the control plane already provides the semantic, don't invent a second shadow status for it.
// ❌ BAD — inventing a second "Deleting" contract
type MTPNCStatus struct {
Status string `json:"status,omitempty"` // now who sets "Deleting"?
}
// ✅ GOOD — use the platform's deletion signal
if !obj.DeletionTimestamp.IsZero() {
// object is deleting
}
Using DeletionTimestamp.IsZero() is the canonical contract. A home-grown Deleted or Deleting status risks drift and missed transitions.
Any value that crosses an API/controller boundary should be typed.
// ✅ GOOD — public response codes are typed
type ResponseCode int
const (
Success ResponseCode = 0
InvalidRequest ResponseCode = 23
NotFound ResponseCode = 14
UnexpectedError ResponseCode = 99
)
The same rule applies to Status, Condition, Reason, and other public contract values:
type PodNetworkStatus string
const (
PodNetworkStatusPending PodNetworkStatus = "Pending"
PodNetworkStatusReady PodNetworkStatus = "Ready"
)
func IsTerminalStatus(s PodNetworkStatus) bool {
return s == PodNetworkStatusReady
}
Internal Go errors are for code. Public response codes and status values are for contracts.
// ✅ GOOD — internal error mapped to public code
respCode := types.Success
if err := req.Validate(); err != nil {
logger.Error("invalid request", zap.Error(err))
respCode = types.InvalidRequest
}
response := cns.PostNetworkContainersResponse{
Response: cns.Response{
ReturnCode: respCode,
},
}
Do not expose behavior by matching on err.Error() strings at the boundary. Convert once into a typed public code/status.
Control-plane startup often needs to restore or reconcile from prior state. That logic must be safe, restartable, and version-aware.
// ✅ GOOD — bootstrap from prior provider, then converge normally
func reconcileInitialCNSState(
nnc *v1alpha.NodeNetworkConfig,
ipamReconciler ipamStateReconciler,
podInfoByIPProvider cns.PodInfoByIPProvider,
isSwiftV2 bool,
) error {
if len(nnc.Status.NetworkContainers) == 0 {
return errors.New("no network containers found in NNC status")
}
// restore prior PodInfo state
// transform to current request format
// hand off to normal reconciliation path
return nil
}
Patterns to prefer:
Patterns to avoid:
A reconcile loop should converge to the desired observed state. Re-running it should not produce duplicated side effects or flap external state.
// ✅ GOOD — state-derived, replay-safe reconciliation
for _, nc := range nnc.Status.NetworkContainers {
if err := sink(nc); err != nil {
return reconcile.Result{}, errors.Wrap(err, "failed to push NC update")
}
}
Keep reconciliation:
If a loop can flap because upstream state trails reality, prefer sticky state or hysteresis rather than churn. See acn-go-design-boundaries for the detailed hysteresis rule.
Generated artifacts in this repo are checked-in contract surfaces. Do not hand-edit the rendered output.
CRD manifests are generated from Go types and checked in. Change the API type, then regenerate:
make regenerate-crd
If you update crd/**/api/... without regenerating the manifest, the checked-in contract is stale.
Rendered Dockerfiles explicitly point back to their source template:
# SOURCE: cns/Dockerfile.tmpl
Edit the template, not the rendered file, then regenerate rendered outputs through the repo tooling. The checked-in rendered file is contract output, not authoring source.
Repo tooling is versioned and reproducible (build/tools/go.mod, go tool -modfile=..., renderkit, golangci-lint). Do not assume local global tools are the source of truth.
| Mistake | Fix |
| --- | --- |
| Raw string status values in public structs | Define typed Status/Condition/Reason constants |
| Returning behavior via err.Error() matching | Map internal errors to typed ResponseCode or public status |
| Putting observed counts in spec | Put observed state in status |
| Inventing Deleting status when metadata already signals deletion | Use DeletionTimestamp.IsZero() |
| Startup bootstrap with hidden retries and side effects | Make bootstrap explicit, replay-safe, and idempotent |
| Hand-editing generated CRD manifest | Edit API type, regenerate CRD |
| Editing rendered Dockerfile directly | Edit Dockerfile.tmpl, regenerate rendered file |
| Reconcile loop that keeps churning external state | Use state-derived idempotence and stable convergence |
acn-go-types-parsing for typed enums, predicate helpers, and strong domain typesacn-go-design-boundaries for behavior-vs-scenario config, fail-fast invariants, and hysteresisacn-go-interfaces-dependencies for narrow dependency surfaces and migration shimsacn-go-context-lifecycle for bootstrap ownership and controller/process lifecycleRun Python code in the cloud with serverless containers, GPUs, and autoscaling. Use when deploying ML models, running batch processing jobs, scheduling compute-intensive tasks, or serving APIs that require GPU acceleration or dynamic scaling.
Advanced GitHub Actions workflow automation with AI swarm coordination, intelligent CI/CD pipelines, and comprehensive repository management
Google Cloud Platform CLI - manage GCP resources including Compute Engine, Cloud Run, GKE, Cloud Functions, Storage, BigQuery, and more.
Expert backend architect specializing in scalable API design, microservices architecture, and distributed systems. Masters REST/GraphQL/gRPC APIs, event-driven architectures, service mesh patterns, and modern backend frameworks. Handles service boundary definition, inter-service communication, resilience patterns, and observability. Use PROACTIVELY when creating new backend services or APIs.
Run Python code in the cloud with serverless containers, GPUs, and autoscaling. Use when deploying ML models, running batch processing jobs, scheduling compute-intensive tasks, or serving APIs that require GPU acceleration or dynamic scaling.
Aspire skill covering the Aspire CLI, AppHost orchestration, service discovery, integrations, MCP server, VS Code extension, Dev Containers, GitHub Codespaces, templates, dashboard, and deployment. Use when the user asks to create, run, debug, configure, deploy, or troubleshoot an Aspire distributed application.
Audits Python + BigQuery pipelines for cost safety, idempotency, and production readiness. Returns a structured report with exact patch locations.
Microsoft Store Developer CLI (msstore) for publishing Windows applications to the Microsoft Store. Use when asked to configure Store credentials, list Store apps, check submission status, publish submissions, manage package flights, set up CI/CD for Store publishing, or integrate with Partner Center. Supports Windows App SDK/WinUI, UWP, .NET MAUI, Flutter, Electron, React Native, and PWA applications.
Take azure/acn-go-control-plane-contracts from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.