# StemeDB Go SDK The official Go SDK for StemeDB - A probabilistic knowledge graph database. ## Overview The Go SDK provides a type-safe, ergonomic API for interacting with StemeDB. It handles all the cryptographic complexity (Ed25519 signing, BLAKE3 hashing) and provides fluent builders for constructing assertions and queries. ## Installation ```bash go get github.com/orchard9/stemedb-go/steme ``` ## Quick Start ```go package main import ( "context" "log" "github.com/orchard9/stemedb-go/steme" ) func main() { // Create a signer (or load from environment) signer, err := steme.GenerateSigner() if err != nil { log.Fatal(err) } // Create client client := steme.NewClient("http://localhost:3000", signer) // Build and submit an assertion assertion := steme.NewAssertion("Tesla_Inc", "has_revenue"). WithNumber(96.7). WithConfidence(0.95). WithSourceHash("0000000000000000000000000000000000000000000000000000000000000000"). Build() hash, err := client.Assert(context.Background(), assertion) if err != nil { log.Fatal(err) } log.Printf("Created assertion: %s", hash) } ``` ## Core Concepts ### 1. Signers Every assertion submitted to StemeDB must be cryptographically signed using Ed25519. The SDK abstracts this complexity. ```go // Generate new keypair signer, err := steme.GenerateSigner() // Load from hex-encoded seed signer, err := steme.NewSignerFromHex("your-64-char-hex-seed") // Load from environment variable signer, err := steme.SignerFromEnv("STEME_PRIVATE_KEY") // Get your agent_id (public key) agentID := signer.PublicKey() // 64-char hex string // Save seed for recovery seed := signer.Seed() // Store this securely! ``` ### 2. Assertions Assertions are the atomic units of knowledge in StemeDB. Use the fluent builder API. ```go assertion := steme.NewAssertion("Subject", "Predicate"). WithNumber(42.5). // Object value WithConfidence(0.95). // 0.0 to 1.0 WithLifecycle(steme.LifecycleApproved). // Stage WithSourceClass(steme.SourceClassClinical). // Authority tier WithSourceHash("..."). // Evidence hash Build() ``` #### Object Values StemeDB supports four value types: ```go // Text assertion.WithText("hello world") // Number (float64) assertion.WithNumber(96.7) // Boolean assertion.WithBoolean(true) // Reference (entity ID) assertion.WithReference("Other_Entity") ``` #### Lifecycle Stages Assertions progress through lifecycle stages: ```go steme.LifecycleProposed // Initial idea/RFC steme.LifecycleUnderReview // Active debate steme.LifecycleApproved // Current truth steme.LifecycleDeprecated // Was true, now superseded steme.LifecycleRejected // Explicitly declined ``` #### Source Authority Tiers Sources are tiered from most authoritative (Tier 0) to least (Tier 5): ```go steme.SourceClassRegulatory // Tier 0: FDA, EMA, WHO steme.SourceClassClinical // Tier 1: Peer-reviewed trials steme.SourceClassObservational // Tier 2: Real-world evidence steme.SourceClassExpert // Tier 3: Guidelines steme.SourceClassCommunity // Tier 4: Curated forums steme.SourceClassAnecdotal // Tier 5: Social media ``` ### 3. Queries Query assertions with optional filters and lens-based conflict resolution. ```go params := steme.NewQuery(). WithSubject("Tesla_Inc"). WithPredicate("has_revenue"). WithLifecycle(steme.LifecycleApproved). WithLens(steme.LensConsensus). WithLimit(10). Build() result, err := client.Query(ctx, params) ``` #### Lenses Lenses resolve conflicts among competing assertions: ```go steme.LensRecency // Latest timestamp wins steme.LensConsensus // Most common value steme.LensAuthority // Weighted by source tier steme.LensVoteAwareConsensus // Highest vote weight steme.LensTrustAwareAuthority // Weighted by TrustRank ``` ### 4. Skeptic Queries ("Trust but Verify") Unlike standard queries that pick a winner, Skeptic shows all competing claims. ```go result, err := client.Skeptic(ctx, steme.SkepticQueryParams{ Subject: "Semaglutide", Predicate: "muscle_effect", }) // Resolution status switch result.Status { case steme.ResolutionUnanimous: // All sources agree case steme.ResolutionAgreed: // >75% weight on one claim case steme.ResolutionContested: // Significant disagreement } // Conflict score: 0.0 (unanimous) to 1.0 (chaos) fmt.Printf("Conflict: %.2f\n", result.ConflictScore) // All competing claims for _, claim := range result.Claims { fmt.Printf("%v: %.1f%% support (%d assertions)\n", claim.Value.Value, claim.WeightShare*100, claim.AssertionCount, ) } ``` ## Advanced Features ### Context Support All API calls accept `context.Context` for cancellation and timeouts. ```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() result, err := client.Query(ctx, params) ``` ### Custom HTTP Client Customize timeouts, TLS, or add middleware. ```go httpClient := &http.Client{ Timeout: 10 * time.Second, Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, // Don't do this in production! }, }, } client := steme.NewClient("https://stemedb.example.com", signer). WithHTTPClient(httpClient) ``` ### Forking Assertions Create a new assertion that supersedes an existing one. ```go originalHash := "abc123..." // Hash from previous assertion updated := steme.NewAssertion("Tesla_Inc", "has_revenue"). WithNumber(102.5). // New value WithParentHash(originalHash). // Link to original WithLifecycle(steme.LifecycleApproved). WithSourceHash("..."). Build() newHash, err := client.Assert(ctx, updated) ``` ### Validation Assertions are validated client-side before submission. ```go assertion := steme.NewAssertion("Tesla_Inc", "has_revenue"). WithNumber(96.7). WithConfidence(1.5). // Invalid! Must be 0.0-1.0 Build() if err := assertion.Validate(); err != nil { // Handle validation error fmt.Printf("Validation failed: %v\n", err) } ``` ## Error Handling The SDK uses typed errors for common failure modes. ```go hash, err := client.Assert(ctx, assertion) if err != nil { switch e := err.(type) { case *steme.APIError: // HTTP error from server fmt.Printf("API error [%d]: %s (code: %s)\n", e.StatusCode, e.Message, e.Code) case *steme.ValidationError: // Client-side validation failure fmt.Printf("Invalid %s: %s\n", e.Field, e.Message) default: // Other errors (network, etc.) fmt.Printf("Error: %v\n", err) } } ``` ## Examples ### Basic Usage See `sdk/go/examples/basic/main.go` for a complete example showing: - Keypair generation - Assertion creation - Automatic signing - Querying with lenses ```bash cd sdk/go/examples/basic go run main.go ``` ### Skeptic Lens See `sdk/go/examples/skeptic/main.go` for a "Trust but Verify" example showing: - Seeding conflicting assertions - Analyzing disagreement - Interpreting conflict scores ```bash cd sdk/go/examples/skeptic go run main.go ``` ## Testing Run unit tests: ```bash cd sdk/go/steme go test -v ``` Integration tests require a running StemeDB server: ```bash # Start StemeDB server cd /path/to/stemedb cargo run --bin stemedb-api # Run integration tests export STEMEDB_URL=http://localhost:3000 cd sdk/go/steme go test -v ``` ## Best Practices ### Key Management 1. Never commit private keys to version control 2. Use environment variables or key management services 3. Rotate keys periodically 4. Use different keys for dev/staging/production ```go // Good: Load from environment signer, err := steme.SignerFromEnv("STEME_PRIVATE_KEY") // Bad: Hardcoded seed signer, err := steme.NewSignerFromHex("abc123...") // Don't do this! ``` ### Source Hashing 1. Use BLAKE3 for source document hashing 2. Include timestamp + URL for web sources 3. Include file hash + timestamp for local files ```go import "lukechampine.com/blake3" // Hash a source document sourceBytes := []byte(documentContent) sourceHash := blake3.Sum256(sourceBytes) sourceHashHex := hex.EncodeToString(sourceHash[:]) assertion.WithSourceHash(sourceHashHex) ``` ### Confidence Scores 1. Start conservative (0.7-0.8 for human-submitted claims) 2. Use 0.95+ only for regulatory/peer-reviewed sources 3. Use 0.5-0.6 for anecdotal evidence 4. Never use 1.0 (implies certainty) ```go // Good: Conservative confidence assertion.WithConfidence(0.85) // Bad: False certainty assertion.WithConfidence(1.0) ``` ## Migration from Manual HTTP If you're currently using raw HTTP calls, migration is straightforward. ### Before (Manual HTTP) ```go // Build JSON payload payload := map[string]interface{}{ "subject": "Tesla_Inc", "predicate": "has_revenue", "object": map[string]interface{}{"type": "Number", "value": 96.7}, "confidence": 0.95, // ... compute signature manually ... } // POST to API resp, err := http.Post("http://localhost:3000/v1/assert", "application/json", ...) ``` ### After (SDK) ```go assertion := steme.NewAssertion("Tesla_Inc", "has_revenue"). WithNumber(96.7). WithConfidence(0.95). WithSourceHash("..."). Build() hash, err := client.Assert(ctx, assertion) ``` ## Performance Considerations ### Batching For high-volume ingestion, batch assertions: ```go for i := 0; i < 1000; i++ { assertion := steme.NewAssertion(fmt.Sprintf("Entity_%d", i), "predicate"). WithNumber(float64(i)). WithSourceHash("..."). Build() if _, err := client.Assert(ctx, assertion); err != nil { log.Printf("Failed to assert %d: %v", i, err) } } ``` Future SDK versions will include a `BatchAssert()` method for improved performance. ### Connection Pooling The SDK uses `http.Client` which automatically reuses connections. Reuse the same `Client` instance. ```go // Good: Reuse client client := steme.NewClient(baseURL, signer) for i := 0; i < 1000; i++ { client.Assert(ctx, assertions[i]) } // Bad: Create new client each time for i := 0; i < 1000; i++ { client := steme.NewClient(baseURL, signer) // Wasteful! client.Assert(ctx, assertions[i]) } ``` ## Contributing See the main repository's `CONTRIBUTING.md` for guidelines. ## License MIT