Telescope Go SDK Guide

March 28, 2026 · View on GitHub

The Telescope SDK provides a stable public Go API for using Telescope as a library. It wraps the core graph engine, pipeline runner, and snapshot manager into a single high-level interface suitable for CLI tools and other external consumers.

Quick Start

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/sailpoint-oss/telescope/server/core/graph"
	"github.com/sailpoint-oss/telescope/server/sdk"
)

func main() {
	ctx := context.Background()

	ws, err := sdk.New()
	if err != nil {
		log.Fatal(err)
	}
	defer ws.Close()

	// Add a synthetic OpenAPI document
	content := []byte(`openapi: "3.1.0"
info:
  title: My API
  version: "1.0"
paths:
  /users:
    get:
      operationId: listUsers
      summary: List users
      responses:
        "200":
          description: OK
`)

	src := graph.NewSyntheticSource("file:///spec.yaml", content, graph.ClassificationHint{
		IsOpenAPI:      true,
		OpenAPIVersion: "3.1",
	})
	ws.AddSource(src)

	result, err := ws.Analyze(ctx)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Analyzed %d documents in %v\n", result.NodeCount, result.Duration)
	fmt.Printf("Total diagnostics: %d\n", result.TotalDiagnostics())
	if result.HasErrors() {
		for uri, diags := range result.Diagnostics {
			for _, d := range diags {
				if d.Severity == sdk.SeverityError {
					fmt.Printf("%s: %s\n", uri, d.Message)
				}
			}
		}
	}
}

Creating a Workspace

Use sdk.New() with optional configuration:

ws, err := sdk.New(
	sdk.WithBuiltinRules(true),       // Enable built-in Telescope rules (default: true)
	sdk.WithCustomRules(false),       // Enable Bun sidecar for TS custom rules
	sdk.WithLogger(slog.Default()),
	sdk.WithConfig(cfg),              // Use a specific Telescope config
	sdk.WithGoroutinePoolSize(8),     // Limit concurrent analysis goroutines
	sdk.WithStages(customStages),     // Override default pipeline stages (advanced)
)
OptionDescription
WithBuiltinRules(bool)Enable or disable built-in rules. Default: true.
WithCustomRules(bool)Enable Bun sidecar for TypeScript custom rules. Default: false.
WithLogger(*slog.Logger)Set the logger for pipeline and workspace operations.
WithConfig(*config.Config)Set a specific Telescope configuration.
WithGoroutinePoolSize(int)Limit the number of concurrent analysis goroutines.
WithStages([]graph.Stage)Override the default pipeline stages. Use for custom processing.

Adding Documents

Synthetic Source (Programmatic)

For in-memory content (e.g., linting generated or transient specs):

content := []byte(`openapi: "3.1.0" ...`)
src := graph.NewSyntheticSource(
	"file:///path/to/spec.yaml",
	content,
	graph.ClassificationHint{
		IsOpenAPI:      true,
		OpenAPIVersion: "3.1",
		IsFragment:     false,
	},
)
ws.AddSource(src)

ClassificationHint helps the classifier avoid re-scanning content. If IsOpenAPI is true, the document is treated as OpenAPI; IsFragment indicates a $ref fragment rather than a root document.

Filesystem Source

For files on disk:

src := graph.NewFilesystemSource("/path/to/openapi.yaml", graph.ClassificationHint{})
ws.AddSource(src)

Updating Synthetic Content

If you need to update content after adding:

if src, ok := node.Source.(*graph.SyntheticSource); ok {
	src.Update(newContent)
}
ws.Graph().Invalidate(uri)

Running Analysis

Full Workspace Analysis

result, err := ws.Analyze(ctx)
if err != nil {
	return err
}

// Result contains:
// - Diagnostics: map[URI][]Diagnostic
// - NodeCount, EdgeCount, RootDocuments
// - Duration, SnapshotID

Single Document Analysis

diags, err := ws.AnalyzeURI(ctx, "file:///spec.yaml")
if err != nil {
	return err
}
for _, d := range diags {
	fmt.Printf("%s: %s\n", d.Code, d.Message)
}

Working with Results

AnalysisResult

FieldTypeDescription
Diagnosticsmap[string][]ctypes.DiagnosticURI → diagnostics
NodeCountintNumber of documents in the graph
EdgeCountintNumber of $ref edges
RootDocuments[]stringRoot OpenAPI document URIs
Durationtime.DurationAnalysis duration
SnapshotIDuint64ID of the built snapshot
StageDurationsmap[string]time.DurationPer-stage cumulative timing
RuleDurationsmap[string]time.DurationPer-rule cumulative timing

Helper Methods

total := result.TotalDiagnostics()
diags := result.DiagnosticsForURI("file:///spec.yaml")
hasErr := result.HasErrors()

Graph Access

For advanced use cases, get a read-only view of the workspace graph:

g := ws.Graph()

// Query structure
nodes := g.AllNodes()
roots := g.Roots()
deps := g.Dependencies(uri)
dependents := g.Dependents(uri)
edges := g.EdgesFrom(uri)
cycles := g.DetectCycles()

Snapshots

Snapshots are immutable point-in-time views of the graph. Built automatically after Analyze():

snap := ws.Snapshot()
if snap != nil {
	for uri, diags := range snap.Diagnostics {
		// Process diagnostics per document
	}
}

Register a callback for when new snapshots are built:

ws.OnSnapshot(func(snap *graph.Snapshot) {
	fmt.Printf("Snapshot %d: %d nodes\n", snap.ID, len(snap.Nodes))
})

Integration Patterns

CI Linter

ws, _ := sdk.New()
for _, path := range os.Args[1:] {
	src := graph.NewFilesystemSource(path, graph.ClassificationHint{})
	ws.AddSource(src)
}
result, err := ws.Analyze(ctx)
if err != nil {
	os.Exit(1)
}
if result.HasErrors() {
	for uri, diags := range result.Diagnostics {
		for _, d := range diags {
			if d.Severity == sdk.SeverityError {
				fmt.Fprintf(os.Stderr, "%s:%d: %s\n", uri, d.Range.Start.Line+1, d.Message)
			}
		}
	}
	os.Exit(1)
}

API Reference

Workspace

MethodSignatureDescription
NewNew(opts ...Option) (*Workspace, error)Create a workspace.
AddSourceAddSource(src graph.DocumentSource)Add a document source.
RemoveSourceRemoveSource(uri string)Remove a document.
AnalyzeAnalyze(ctx context.Context) (*AnalysisResult, error)Run full pipeline on all documents.
AnalyzeURIAnalyzeURI(ctx context.Context, uri string) ([]ctypes.Diagnostic, error)Run pipeline for a single document.
GraphGraph() graph.ReadOnlyGraphRead-only graph access.
SnapshotSnapshot() *graph.SnapshotCurrent snapshot (nil if none built).
OnSnapshotOnSnapshot(fn func(*graph.Snapshot))Register snapshot callback.
CloseClose() errorRelease resources.

DocumentSource Implementations

TypeConstructorUse Case
SyntheticSourcegraph.NewSyntheticSource(uri, content, hint)Programmatic injection
FilesystemSourcegraph.NewFilesystemSource(path, hint)Files on disk
LSPSourcegraph.NewLSPSource(uri, provider, hint)LSP document overlays

Core Types

Diagnostics use core/types:

  • ctypes.Diagnostic — Range, Severity, Code, Message, Tags, Related, Data
  • ctypes.Range — Start, End (Position)
  • ctypes.Severity — Error (1), Warning (2), Info (3), Hint (4)