CleanLibrary Go SDK
cleanlib-sdk-go is the Go client library for CleanLibrary. It wraps the same HTTP surface that powers the CLI, the MCP server, and the VS Code extension behind a small, typed API you can drop into any Go program — a service, a CLI tool, a CI gate, or an admission controller.
1. What it does
The Go SDK answers the same package-manager-layer questions as the CLI, but from inside a Go program rather than from a shell:
- Is this version safe to install? —
client.FetchVerdict(ctx, ecosystem, pkg, version) - What does my policy do with this package? —
client.PolicyPreview(ctx, policyYAML, packages) - Should I accept the risk on this finding? —
client.RiskAccept(ctx, verdictID, justification)
The wire contract is identical to every other CleanLibrary client. A verdict returned by the Go SDK has the same shape as a verdict returned by the CLI or the MCP server, so you can mix-and-match clients within one workflow.
2. Install
go get pkg.clnstrt.dev/cleanlib-sdk-go
The module path is a vanity import — go get resolves through pkg.clnstrt.dev to the canonical source. No additional repository configuration is required.
The SDK is pure Go (no cgo), targets Go 1.21+, and has a small dependency footprint (net/http, encoding/json, and the standard context package).
3. Quickstart
package main
import (
"context"
"fmt"
"log"
"os"
cleanlib "pkg.clnstrt.dev/cleanlib-sdk-go"
)
func main() {
client, err := cleanlib.NewClient(
"https://cleanapp.clnstrt.dev",
cleanlib.WithAPIKey(os.Getenv("CLEANLIB_API_KEY")),
)
if err != nil {
log.Fatal(err)
}
verdict, err := client.FetchVerdict(context.Background(), "npm", "lodash", "4.17.21")
if err != nil {
log.Fatal(err)
}
fmt.Printf("verdict_id: %s\n", verdict.VerdictID)
fmt.Printf("decision: %s\n", verdict.Decision)
fmt.Printf("severity: %s\n", verdict.Severity)
fmt.Printf("source: %s\n", verdict.Source)
}
Output:
verdict_id: <stable-identifier>
decision: ALLOW
severity: NONE
source: ALLOWED_NO_FINDINGS
4. Configuration
NewClient follows the functional-options pattern. The first argument is the endpoint; subsequent arguments are option-functions that configure the client.
| Option | Purpose | Default |
|---|---|---|
WithAPIKey(key) | Bearer token (typically from CLEANLIB_API_KEY env var) | (none) |
WithAPIVersion(v) | API version path segment | "v1" |
WithTimeout(d) | Per-request timeout (time.Duration) | 30 * time.Second |
WithHTTPClient(h) | Optional pre-built *http.Client for connection pooling, TLS overrides, or test fakes | new client per NewClient |
The convention for production deployments is to read endpoint and API key from environment variables and let everything else default:
client, err := cleanlib.NewClient(
os.Getenv("CLEANLIB_ENDPOINT"),
cleanlib.WithAPIKey(os.Getenv("CLEANLIB_API_KEY")),
)
5. API reference
(*Client).FetchVerdict(ctx, ecosystem, pkg, version) (*Verdict, error)
Returns a verdict for a single (ecosystem, package, version) tuple.
type Verdict struct {
VerdictID string // stable identifier for this decision
Ecosystem string
PackageName string `json:"package"`
PackageVersion string `json:"version"`
Decision string // ALLOW | DENY | WARN
VerdictLabel string `json:"verdict,omitempty"`
Source string // ALLOWED_NO_FINDINGS | VECTOR_VERDICT | DM_THRESHOLD_BLOCK | INSUFFICIENT_DATA
Confidence float64
CompositeScore int
Severity string // NONE | LOW | MEDIUM | HIGH | CRITICAL
Reasoning string
SuggestedActions []string
// Plus freshness, similar_to, evidence_gaps, attestation, and rich-data fields
}
(*Client).Scan(ctx, packages) (*ScanResponse, error)
Scans a list of PackageRef entries in one round-trip and returns a ScanResponse containing a verdict per package. Suitable for CI pipelines or admission controllers that need a single round-trip.
(*Client).PolicyPreview(ctx, policyYAML, packages) (*PolicyPreviewResponse, error)
Returns what your candidate policy would decide for the given packages, with the matching policy rule attached.
(*Client).RiskAccept(ctx, verdictID, justification) (*RiskAcceptResponse, error)
Records a customer-side risk-acceptance against a specific verdict.
(*Client).Audit(ctx, window) (*AuditWindowResponse, error)
Returns the customer-side audit log for a time window.
(*Client).FetchBytes(ctx, ecosystem, pkg, version) ([]byte, error)
Returns the verified upstream bytes for an (ecosystem, package, version) tuple.
6. Error handling
The SDK returns typed errors. Common error categories:
| Category | When it surfaces |
|---|---|
| Authentication | Missing, malformed, or rejected APIKey |
*VerdictNotFound | The catalog has no verdict for this (ecosystem, package, version) yet |
*PolicyDenyError | A 403 with a verdict-attached policy-deny envelope |
*RiskAcceptanceRequired | A 403 indicating the customer must record risk-acceptance |
*RateLimitError | A 429 with RetryAfter set |
*TransportError | Network, DNS, or TLS failure |
A Verdict is not an error — it's a successful response with a verdict-aware decision. Use verdict.Decision to drive flow control, not err.
7. CI integration
Drop the SDK into a build step and exit non-zero on DENY:
// build/precheck/main.go
package main
import (
"context"
"fmt"
"log"
"os"
cleanlib "pkg.clnstrt.dev/cleanlib-sdk-go"
)
func main() {
client, err := cleanlib.NewClient(
os.Getenv("CLEANLIB_ENDPOINT"),
cleanlib.WithAPIKey(os.Getenv("CLEANLIB_API_KEY")),
)
if err != nil {
log.Fatal(err)
}
v, err := client.FetchVerdict(context.Background(), "npm", "lodash", "4.17.21")
if err != nil {
log.Fatal(err)
}
if v.Decision == "DENY" {
fmt.Fprintf(os.Stderr, "BLOCKED: npm/lodash@4.17.21 — %s\n", v.Reasoning)
os.Exit(1)
}
}
For multi-package scans, prefer client.Scan(...) over a loop of client.FetchVerdict(...) calls — one round-trip is cheaper than N.
8. Versioning
The SDK follows Semantic Versioning. The verdict envelope wire contract is stable across the v0.4 series — clients can mix v0.4.0 and v0.4.3 against the same backend without coordination.
v0.4.x envelopes are byte-identical with the Python, JavaScript, and Rust SDKs against the same backend version — verdicts produced by each SDK derive the same status for the same (ecosystem, package, version) tuple.
9. Where to go next
- CLI — the same verdicts and remediation surface from the terminal, for ad-hoc queries and CI gates
- MCP Server — surface CleanLibrary inside any MCP-compatible AI coding agent
- SDK — Python — Python programmatic access
- SDK — JavaScript — JavaScript / TypeScript programmatic access
- SDK — Rust — Rust programmatic access
- Integration Surfaces — the full integration matrix (admission, CI, IDE, agent)
- Architecture — how CleanLibrary's verdict-and-enrichment surface composes end to end