Skip to content
skyl

ADR-0001: Two-module repository layout

Why the repository is several Go modules rather than one.

Status: Accepted. Superseded in detail by ADR-0003, ADR-0006 and ADR-0007, which added the third and fourth modules.

Context#

skyl is a library. It is also, usefully, an HTTP service and an observability integration. Those are different products with different dependency appetites.

A single Go module means one go.mod, so every dependency any part needs is imposed on everyone who imports any part. Someone who wants a Go library that talks to Gemini would inherit a router, an OpenTelemetry SDK and a vendor SDK they never call — forever, including in their security scanners and their upgrade schedule.

Go module versioning also means one version number for everything, so a patch to the gateway forces a version bump on the library.

Decision#

The repository holds several Go modules, each with its own go.mod and its own tag prefix.

The core library takes zero external dependencies. Anything that brings a dependency graph becomes a separate module.

ModuleImport pathGoDependencies
skylgithub.com/BAGOMBEKA-JOB-DEV/skyl1.22noneThe core library. Zero external dependencies.
provider/anthropicgithub.com/BAGOMBEKA-JOB-DEV/skyl/provider/anthropic1.24anthropic-sdk-goA separate module, because the official SDK brings a dozen transitive dependencies.
gatewaygithub.com/BAGOMBEKA-JOB-DEV/skyl/gateway1.25go-chi/chi, skyl/otelThe optional HTTP service. Importing the core library never pulls in chi.
otelgithub.com/BAGOMBEKA-JOB-DEV/skyl/otel1.25go.opentelemetry.io/otelOpenTelemetry instrumentation. Nobody who does not want it pays for it.

Consequences#

Good. go get on the core library adds nothing to your dependency tree. The Go version floors can differ, so the library stays on 1.22 while the SDK-bound modules sit at 1.24 and 1.25. Modules version independently.

Bad. Releasing is more complicated, and the ordering is not optional — each module's require must point at a version that already exists on the proxy. See Releasing.

Local development needs go.work, and CI must build with GOWORK=off to prove each module resolves on its own.

Alternatives considered#

One module. Simpler to release, and it makes every library user pay for the gateway. Rejected: the whole value of a dependency-light library evaporates.

Separate repositories. Clean dependency separation, at the cost of cross-repository changes for anything touching the seam — and the seam changes most often. Rejected as premature.

Build tags. A single module where optional pieces are excluded by tag. Does not work: go.mod requirements are not tag-conditional, so the dependencies would be inherited regardless.

Edit this page on GitHub