Skip to content

feat(sdk): proposal for Go SDK following client-go conventions #2044

Closed

Description

@rhuss

Problem Statement

Why

#1719 puts a Kubernetes operator on the roadmap. You can write an operator in any language, but Go is the natural fit for the Kubernetes ecosystem, and a Go client for the OpenShell gRPC API would make that path much smoother.

The Kubernetes world runs on Go. Operators, controllers, admission webhooks, CLI tools, platform integrations: they're overwhelmingly written in Go and they all expect client libraries that follow the k8s.io/client-go conventions. Typed sub-clients per resource, domain types in a dedicated package, watch primitives with channels, functional options, and a fake client for testing. These patterns exist because they solve real problems: typed watchers keep controllers reliable, fake clients make tests fast and deterministic, and domain types separated from proto keep the public API clean when the wire format changes.

A Go SDK that follows these conventions means anyone building on top of OpenShell in the Kubernetes world can pick it up without learning a new paradigm. The patterns are the same ones they already use every day.

What Would This Look Like

A Go SDK covering the full OpenShell gRPC API surface, following k8s.io/client-go conventions:

  • Typed sub-clients per resource: client.Sandboxes(), client.Providers(), client.Exec(), client.Services(), similar to clientset.CoreV1().Pods()
  • Domain types in a dedicated types package, no proto leakage into the public API
  • Watch primitives with ResultChan() and Stop(), matching watch.Interface from client-go
  • Typed errors with helpers: IsNotFound(), IsAlreadyExists(), IsConflict()
  • Fake client for testing without a gRPC server, with in-memory stores and watch event broadcasting
  • Internal converter layer handling all proto-to-domain translations

The API surface would map to something like this:

Client
  ├── Sandboxes()   → SandboxInterface    (create, get, list, delete, watch, wait)
  ├── Exec()        → ExecInterface       (run, stream, interactive)
  ├── Files()       → FileInterface       (upload, download)
  ├── Health()      → HealthInterface     (gateway health check)
  ├── Services()    → ServiceInterface    (expose, get, list, delete)
  └── Providers()   → ProviderInterface   (CRUD + ensure)
        ├── Profiles() → ProfileInterface (list, get, import, update, lint, delete)
        └── Refresh()  → RefreshInterface (configure, status, rotate, delete)

Example Usage

client, err := v1.NewClient(v1.Config{
    Address: "gateway.example.com:443",
    Auth:    v1.StaticToken("my-token"),
})
defer client.Close()

// Create a sandbox and wait for it
sandbox, _ := client.Sandboxes().Create(ctx, "my-sb", &v1.SandboxSpec{
    Template: &v1.SandboxTemplate{Image: "python:3.12"},
}, nil)
sandbox, _ = client.Sandboxes().WaitReady(ctx, sandbox.Name)

// Run a command
result, _ := client.Exec().Run(ctx, sandbox.Name,
    []string{"python3", "-c", "print('hello')"},
    v1.ExecOptions{},
)

Testing with a fake client (no gRPC server needed):

func TestMyController(t *testing.T) {
    fc := fake.NewClient()
    defer fc.Close()

    var client v1.ClientInterface = fc

    sandbox, err := client.Sandboxes().Create(ctx, "test-sb", &v1.SandboxSpec{
        Template: &v1.SandboxTemplate{Image: "python:3.12"},
    }, nil)
    require.NoError(t, err)

    sandbox, err = client.Sandboxes().WaitReady(ctx, "test-sb")
    require.NoError(t, err)
    assert.Equal(t, "Ready", string(sandbox.Status.Phase))
}

Existing Implementation

As a side note: I have already built a fully functional Go SDK following these ideas. It covers the Phase 1 and Phase 2a API surfaces (Sandbox, Provider, Exec, File, Health, Watch, Services, Profiles, Credential Refresh), includes a complete fake client package, CI pipeline, and a proto sync workflow. 32 test files, 368 test functions. It currently lives in my personal repo, but I'd be happy to contribute it as a starting point if the community thinks this direction is right.

Discussion

Go SDK support was already mentioned in the 1.0 stability discussion (SDK Interfaces listed alongside Python and TypeScript). I'd love to hear whether this direction makes sense, and where a Go SDK should live relative to the main project.

Proposed Design

See https://github.com/rhuss/openshell-sdk-go and especially the specs/ directory for detailed design documents (created with Speckit / cc-spex, a spec-driven development framework).

Alternatives Considered

Using the generated proto stubs directly. This is the zero-effort option: import the .pb.go files and call the gRPC methods. It works, but it leaks proto types into consumer code, makes testing harder (you need a running gRPC server or mock the generated interface), and every upstream proto change ripples through the entire codebase. The SDK wraps this layer so consumers don't have to deal with it.

Writing a thin wrapper without the client-go patterns. A simpler SDK that just wraps the gRPC calls without typed sub-clients, watch primitives, or a fake client. Lower upfront effort, but it shifts the complexity to every consumer who then has to build their own testing infrastructure, error handling, and type conversions. The client-go patterns pay for themselves as soon as you have more than one consumer.

Using the Python SDK. OpenShell already has a Python SDK. For operator development on Kubernetes, Python is an unusual choice. The controller-runtime ecosystem, kubebuilder, and the entire operator toolchain assume Go. A Python operator would be swimming against the current.

Agent Investigation

No response

Checklist

  • I've reviewed existing issues and the architecture docs
  • This is a design proposal, not a "please build this" request

Activity

  1. rhuss commented on Jul 11, 2026

    @rhuss
    ContributorAuthor

    Update: Go SDK contribution ready for review

    The SDK described in this proposal is now ready as a contribution. I've opened three draft PRs against this repo:

    • PR #2225 (1/3): Foundation and core clients (types, converters, proto bindings, all API clients)
    • PR #2226 (2/3): Gateway client, OIDC auth, fakes, edge client
    • PR #2227 (3/3): Documentation (Fern MDX) and CI job

    The PRs should be reviewed and merged in order (1 -> 2 -> 3). Each builds on the previous.

    The SDK covers the full API surface proposed in this issue, including typed sub-clients, domain types isolated from proto, fake client for testing, and watch primitives. It follows the client-go conventions discussed in the proposal.

    I also have design specifications (created with Speckit) available in a separate PR on my fork if the team is interested in keeping specs alongside the SDK code.

    Looking forward to feedback!

  2. rhuss commented on Jul 12, 2026

    @rhuss
    ContributorAuthor

    Following the discussion with @maxdubrinsky on #1764 and the community meeting decision captured by Drew, the Go SDK PRs are now open:

    PR Scope Files Status
    #2225 Foundation: types, converters, core clients, proto bindings 117 Ready for review
    #2226 Gateway client, OIDC auth, fakes, edge client 70 Draft
    #2227 Fern docs (4 MDX pages), CI job, mise tasks 7 Draft

    The SDK targets go 1.24, follows client-go conventions (typed sub-clients, watch primitives, IsNotFound() helpers, functional options), and keeps proto types fully internal. CI includes a proto:check task that verifies generated code stays in sync with upstream.

    #2225 compiles and passes tests independently. The draft PRs will be prepared for review after #2225 is merged.

    Design specs from the development process are available in my fork's PR #12 if useful for review context, but I've kept them out of the upstream chain unless you'd like them committed.

  3. rhuss commented on Jul 15, 2026

    @rhuss
    ContributorAuthor

    Implementation is underway via the decomposed PR plan in #2270. The design rationale in this issue remains the reference for the SDK's architecture decisions.

    First PR ready for review: #2271

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions