Skip to main content

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:

  1. Is this version safe to install?client.FetchVerdict(ctx, ecosystem, pkg, version)
  2. What does my policy do with this package?client.PolicyPreview(ctx, policyYAML, packages)
  3. 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.

OptionPurposeDefault
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 fakesnew 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:

CategoryWhen it surfaces
AuthenticationMissing, malformed, or rejected APIKey
*VerdictNotFoundThe catalog has no verdict for this (ecosystem, package, version) yet
*PolicyDenyErrorA 403 with a verdict-attached policy-deny envelope
*RiskAcceptanceRequiredA 403 indicating the customer must record risk-acceptance
*RateLimitErrorA 429 with RetryAfter set
*TransportErrorNetwork, 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