skyl leans on Go's type system, so a correctly configured editor catches most mistakes as you type. Three checks in particular pay for themselves.
You will learn
- Which language server and linters to run
- The two
go vetchecks that catch the most common skyl mistakes - Why an unchecked
stream.Err()is worth a lint rule of its own
Language server#
gopls is the only requirement, and every mainstream editor uses it.
go install golang.org/x/tools/gopls@latestBecause Part is a closed interface, gopls will complete the four
implementations — Text, Image, ToolCall, ToolResult — and reject
anything else at the point you type it, rather than at runtime.
Vet and staticcheck#
go vet ./...
go install honnef.co/go/tools/cmd/staticcheck@latest && staticcheck ./...Two checks matter most for skyl code:
lostcancel catches a context.WithTimeout whose cancel is never called.
Since you bound a whole retry sequence with your own context, this is code you
will write often.
// vet: the cancel function is not used on all paths
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
resp, err := client.Complete(ctx, req) // ← missing defer cancel()// vet: the cancel function is not used on all paths
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
resp, err := client.Complete(ctx, req) // ← missing defer cancel()errcheck (in staticcheck) catches an ignored stream.Close().
golangci-lint#
If you already run it, the configuration skyl itself uses is a reasonable
starting point — errcheck, govet, staticcheck, ineffassign,
unconvert, and bodyclose.
linters:
enable:
- errcheck
- govet
- staticcheck
- ineffassign
- unconvert
- bodycloselinters:
enable:
- errcheck
- govet
- staticcheck
- ineffassign
- unconvert
- bodyclosebodyclose is worth calling out: if you supply your own *http.Client via
openai.WithHTTPClient and wrap its transport, this catches a response body you
forgot to close in that wrapper.
Deep diveWhy skyl needs no code generation or build tags in your project
Some SDKs require a generation step for typed model constants or for tool
schemas. skyl deliberately has neither: model IDs are opaque strings, and tool
parameters are a map[string]any holding JSON Schema.
That means no go:generate line, no generated file to keep in sync, and no
build tag. The build tags you will see (sandbox, integration) belong to
skyl's own test suite, not to code that imports it.
Recap
goplsalone gives you completion over the closedPartinterface.go vet'slostcancelcatches the missingdefer cancel()you will write often.staticcheckcatches an ignoredstream.Close().- No linter catches a missing
stream.Err()— make it a review habit. - skyl requires no code generation and no build tags in your project.
Try out some challenges
Each of these is solvable with what this page covered. Run them against the sandbox — no API key needed.
Write the review checklist
Your team is adopting skyl. Write the four-line checklist a reviewer should apply to any diff that touches it.
Show hint
Think about the failure modes that are silent rather than loud.
Show solution
- Is
stream.Err()checked after everyfor stream.Next()loop? - Is
defer stream.Close()present on every stream? - Are errors branched on with
errors.Isagainst a sentinel, never on message text? - Is the client constructed once and reused, not per request?
Every one of these is a mistake that compiles, passes tests against a fake, and fails quietly in production — which is exactly the kind a checklist is for.