# SDK - Go Client Libraries **Last Updated:** 2026-02-19 **Confidence:** High ## Summary Official Go SDK for Episteme with two layers: a low-level HTTP client (`steme`) and an ADK-Go integration layer (`adk`) for building AI agents. Both libraries handle Ed25519 signing, content-addressing, and fluent assertion building. The ADK layer exposes Episteme as Google ADK-Go tools with pre-flight constraint checking and audit callbacks. **Key Facts:** - Languages: Go (initial), Python/TypeScript planned - Location: `sdk/go/steme/` (core client), `sdk/go/adk/` (ADK integration) - Signing: Ed25519 with BLAKE3 content-addressing - Transport: HTTP/JSON (matches `stemedb-api`) - ADK Tools: Query, Assert, ConstraintCheck, Trace, Supersede - Test Coverage: 26 tests passing (12 core + 14 ADK) **File Pointers:** - `sdk/go/steme/client.go` - HTTP client with auto-signing - `sdk/go/steme/assertion.go` - Fluent builder for assertions - `sdk/go/steme/signer.go` - Ed25519 signature generation - `sdk/go/adk/tools.go` - ADK tool definitions - `sdk/go/adk/callbacks.go` - Pre-flight checks and audit hooks - `sdk/go/adk/config.go` - Agent configurations (Lead, Research, Implementation, etc.) ## Core SDK (`steme`) ### Installation ```go import "github.com/orchard9/stemedb/sdk/go/steme" ``` ### Client Creation ```go // Create with Ed25519 keypair privateKey := ed25519.NewKeyFromSeed(seed) client := steme.NewClient("https://episteme.example.com", privateKey) // Or use environment-based config client := steme.NewClientFromEnv() // STEME_URL, STEME_PRIVATE_KEY ``` ### Fluent Assertion Builder ```go assertion, err := steme.NewAssertion(). Subject("auth/jwt"). Predicate("signing_algorithm"). StringObject("RS256"). Confidence(0.95). SourceHash(evidenceHash). Lifecycle("approved"). Build() // Client auto-signs on submit hash, err := client.Assert(ctx, assertion) ``` ### Query API ```go result, err := client.Query(ctx, steme.QueryRequest{ Subject: "auth/jwt", Predicate: "signing_algorithm", Lens: "authority", Lifecycle: "approved", MinConfidence: 0.8, AsOf: time.Now().Add(-24 * time.Hour), // Time-travel }) fmt.Printf("Value: %v (confidence: %.2f)\n", result.Value, result.Confidence) ``` ### Voting ```go err := client.Vote(ctx, steme.VoteRequest{ AssertionHash: targetHash, Upvote: true, AgentID: myAgentID, VoteHash: voteContentHash, }) ``` ## ADK Integration (`adk`) ### Installation ```go import ( "github.com/orchard9/stemedb/sdk/go/adk" "google.golang.org/adk/llmagent" ) ``` ### Agent Configuration Pre-configured agent personas with appropriate tool access and callbacks: ```go // Implementation Agent - Uses approved patterns only config := adk.ImplementationAgentConfig(stemeClient, model) agent, err := llmagent.New(config) // Research Agent - Stores conflicting information without flattening config := adk.ResearchAgentConfig(stemeClient, model) agent, err := llmagent.New(config) // Lead Agent - Fast queries with confidence thresholds config := adk.LeadAgentConfig(stemeClient, model) agent, err := llmagent.New(config) // Supervisor Agent - Time-travel and corrections config := adk.SupervisorAgentConfig(stemeClient, model) agent, err := llmagent.New(config) // On-Call Agent - Traces and debugging config := adk.OnCallAgentConfig(stemeClient, model) agent, err := llmagent.New(config) ``` ### Available Tools All tools are ADK-compatible with structured input/output and OpenAPI schema generation: **Query Tool** ```go type QueryInput struct { Subject string `json:"subject"` Predicate string `json:"predicate"` Lens string `json:"lens,omitempty"` Lifecycle string `json:"lifecycle,omitempty"` MinConfidence float32 `json:"min_confidence,omitempty"` AsOf string `json:"as_of,omitempty"` } ``` **Assert Tool** ```go type AssertInput struct { Subject string `json:"subject"` Predicate string `json:"predicate"` Object interface{} `json:"object"` SourceHash string `json:"source_hash"` Confidence float32 `json:"confidence"` Lifecycle string `json:"lifecycle,omitempty"` ParentHash string `json:"parent_hash,omitempty"` } ``` **ConstraintCheck Tool** ```go type ConstraintCheckInput struct { Context string `json:"context"` // e.g., "python_http", "auth_jwt" } ``` **Trace Tool** (SRE debugging) ```go type TraceInput struct { AgentID string `json:"agent_id"` From string `json:"from"` // ISO8601 or relative like "-6h" Subject string `json:"subject,omitempty"` // Filter pattern } ``` **Supersede Tool** (corrections) ```go type SupersedeInput struct { Hash string `json:"hash"` // Assertion to correct Reason string `json:"reason"` // Why it's being invalidated Type string `json:"type"` // "Invalidate" or "Update" } ``` ### Callbacks Three callback hooks for safety and observability: **ConstraintEnforcement** (BeforeToolCallback) ```go // Blocks tool calls that violate organizational constraints // Example: Prevents using SHA1 if auth/jwt has "forbidden: sha1" BeforeToolCallback: adk.ConstraintEnforcementCallback(client) ``` **AuditLogging** (AfterModelCallback) ```go // Logs agent decisions for debugging and replay AfterModelCallback: adk.AuditLoggingCallback(client) ``` **ConfidenceEscalation** (AfterToolCallback) ```go // Escalates to human when confidence drops below threshold // Triggers Gardener on tool failures for TrustRank back-propagation AfterToolCallback: adk.ConfidenceEscalationCallback(client, 0.7) ``` ### Custom Agent Example ```go import ( "github.com/orchard9/stemedb/sdk/go/adk" "google.golang.org/adk/llmagent" "google.golang.org/adk/tool" ) func main() { stemeClient := steme.NewClientFromEnv() model := llm.NewClient() // Build ADK tools queryTool, _ := adk.NewQueryTool(stemeClient) assertTool, _ := adk.NewAssertTool(stemeClient) constraintTool, _ := adk.NewConstraintCheckTool(stemeClient) // Create agent with callbacks agent, err := llmagent.New(llmagent.Config{ Name: "custom_agent", Model: model, Tools: []tool.Tool{queryTool, assertTool, constraintTool}, // Pre-flight constraint checking BeforeToolCallback: adk.ConstraintEnforcementCallback(stemeClient), // Audit all decisions AfterModelCallback: adk.AuditLoggingCallback(stemeClient), // Learn from failures AfterToolCallback: adk.ConfidenceEscalationCallback(stemeClient, 0.8), }) // Run agent ctx := context.Background() response, err := agent.Generate(ctx, llmagent.Input{ Prompt: "Check if we have an approved JWT signing algorithm", }) } ``` ## E2E Test Coverage The SDK implementation is validated by comprehensive integration tests: **File:** `crates/stemedb-api/tests/e2e_flow_test.rs` **Tests:** 1. `test_basic_write_materialize_query` - Write → MV → Read flow 2. `test_write_multiple_query_recency` - Recency lens with multiple assertions 3. `test_vote_and_query_consensus` - Voting + Consensus lens 4. `test_event_driven_materialization` - MV updates on write events **Coverage:** - Real Ed25519 signature generation and verification - Event-driven materialization (WAL → MV update) - All lens types (Recency, Consensus, Authority) - Time-travel queries - Vote aggregation with TrustRank ## Type Hierarchy ``` Go SDK (serde JSON) Rust API (serde JSON) Rust Core (rkyv) | | | Assertion struct dto::AssertionRequest types::Assertion | | | +-- Subject: string +-- subject: String +-- subject: EntityId +-- Predicate: string +-- predicate: String +-- predicate: RelationId +-- Object: interface{} +-- object: Value +-- object: ObjectValue +-- Confidence: float32 +-- confidence: f32 +-- confidence: f32 +-- SourceHash: string +-- source_hash: Hash +-- source_hash: Hash +-- Lifecycle: string +-- lifecycle: String +-- lifecycle: LifecycleStage ``` ## Design Principles **Content-Addressed Identity** - Assertion hash = BLAKE3(canonical JSON serialization) - Same content = same hash across all SDKs - Idempotent writes (re-asserting produces same hash) **Multi-Signature Support** - Client signs entire assertion with Ed25519 - API verifies signature before writing to WAL - Multiple agents can co-sign the same assertion (multi-sig) **Fluent Builder Pattern** - Type-safe construction with compile-time validation - Prevents partial/invalid assertions - Generates content hash automatically on Build() **Zero Dependencies on Rust** - Pure Go implementation with standard library + ADK - JSON over HTTP (no gRPC/protobuf yet) - Works with any Episteme deployment ## Error Handling ```go // SDK errors implement error interface _, err := client.Assert(ctx, assertion) if err != nil { var apiErr *steme.APIError if errors.As(err, &apiErr) { switch apiErr.Code { case steme.ErrInvalidSignature: // Re-sign with correct key case steme.ErrDuplicateHash: // Already exists (idempotent - not an error) case steme.ErrConstraintViolation: // Check constraints with ConstraintCheck tool default: // Log and retry with backoff } } } ``` ## Related Topics - [API Surface](./api.md) - HTTP endpoints and OpenAPI schema - [Assertion](./assertion.md) - Core data structure - [Lens](./lens.md) - Read-time resolution strategies - [ADK Integration Pattern](../patterns/adk-integration.md) - Tool and callback details - [Query Audit](../features/query-audit.md) - Trace agent decisions - [TrustRank](../features/trust-rank.md) - Agent reputation and Gardener