feat(api): split api/ into a Go submodule for cross-repo typed import

Open
#175 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
38/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Quiet
Tech stack
go, kubernetes

Research direction

Start by inspecting api/v1alpha1/ for imports from internal/ or cmd/, then compare api/go.mod and the main go.mod requirements. Run cd api && go build ./..., go list -m -json for the api module, and the existing controller test suites. Done means both modules build, consumers can import the typed package without a cycle, and the documented acceptance criteria are met.

Written by the indexing model from the issue text.

Description

Problem

The typed CRD surface at api/v1alpha1/ (SeiNode, SeiNodeDeployment, etc.) lives inside the main github.com/sei-protocol/sei-k8s-controller module. Downstream consumers that want typed access (seictl's new nodedeployment CLI per sei-protocol/seictl/docs/design/nodedeployment-cli.md, future controllers, the seiload harness) cannot import these types directly: sei-k8s-controller/internal/... imports github.com/sei-protocol/seictl/sidecar/client from 17+ sites, so a typed import in the reverse direction creates a Go module-level cycle.

The seictl nodedeployment CLI implementation hits this immediately. The architectural fallback is unstructured.Unstructured everywhere — verbose accessors, no compile-time type safety, ongoing drift risk against schema changes — paid by every consumer that wants typed CRD access.

Impact

  • seictl's PR-1 for the new CLI needs to choose: either ship with unstructured and refactor later, or block on the split landing here.
  • Future consumers (additional controllers, fuzzers, upcoming harnesses) each pay the same unstructured tax until the split lands.
  • "Single source of truth for CRD types" is the standard K8s ecosystem pattern. Cluster-API, Argo CD, Longhorn, Karpenter, and Crossplane all split api/ into a leaf module for exactly this reason.

Relevant experts

  • kubernetes-specialist — kubebuilder/controller-runtime conventions, module structure.

Proposed approach

Extract api/ into a Go submodule (github.com/sei-protocol/sei-k8s-controller/api):

  1. Add api/go.mod declaring the new module path. Direct dependencies should be limited to k8s.io/apimachinery, k8s.io/api, and sigs.k8s.io/controller-runtime/pkg/scheme — no project-internal imports.
  2. Verify api/v1alpha1/ is leaf-clean (no imports from sei-k8s-controller/internal/... or cmd/...). If not, lift the offending shared code into api/ or push it down into internal/.
  3. Update the main module's go.mod to require the api submodule. Use a replace directive pointing at ./api for local development; go work syncs across both.
  4. Update all sei-k8s-controller/internal/... and cmd/... imports of api/v1alpha1 to reference the new module path. The package import path stays the same (github.com/sei-protocol/sei-k8s-controller/api/v1alpha1); only the module boundary changes.
  5. CI: build both modules; run controller tests against the submodule.
  6. Release: tag api/v0.1.0 independently from main module tags. Subsequent CRD changes bump api/ minor; controller-only changes don't touch it.

Standard pattern. References:

Architectural constraints

  • Leaf-clean. The api submodule must not import anything from sei-k8s-controller/internal/, cmd/, or any project-specific package. Any shared utility (e.g., validation helpers) either moves into api/ or stays controller-side.
  • Same import path. Consumers should continue to write import "github.com/sei-protocol/sei-k8s-controller/api/v1alpha1". Only the module boundary changes. This avoids breaking any existing internal consumer of the same package.
  • Independent versioning. api/vX.Y.Z tags are independent from main module tags. Schema changes bump api; controller-only changes don't.

Acceptance criteria

  • api/go.mod exists declaring github.com/sei-protocol/sei-k8s-controller/api.
  • go list -m -json github.com/sei-protocol/sei-k8s-controller/api from the main module resolves cleanly.
  • cd api && go build ./... succeeds with no project-internal imports.
  • Main module imports api via require + replace (local dev) and a tagged version (CI).
  • All controller unit / integration / envtest suites pass against the submodule.
  • api/v0.1.0 (or first cut) tagged and pushed.
  • A consumer outside this repo (initially: sei-protocol/seictl) can import "github.com/sei-protocol/sei-k8s-controller/api/v1alpha1" and successfully construct a typed client without cycle.

Out of scope

  • Moving controller reconcile logic, planner, or task code. This issue is structural-only.
  • Renaming the CRD or any of its fields. Additive schema changes only.
  • Splitting the controller itself into a separate repo. Submodule, not subrepo.

References

  • sei-protocol/seictl#135 — design doc that hit this constraint and worked around it with unstructured.
  • sei-protocol/seictl/docs/design/nodedeployment-cli.md — consumer side; the "Implementation: build on existing libraries" section currently assumes unstructured pending this split.
  • Brandon's directive 2026-05-05: "break the CRD spec model from the sei-k8s-controller and import in both places."
Dominant language
Go
Stars
1
Forks
2
Avg merge
2h 29m
Merged PRs (30d)
56

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from sei-protocol/sei-k8s-controller

All issues in sei-protocol/sei-k8s-controller

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.