// Package main demonstrates basic StemeDB SDK usage. // // This example shows: // - Creating a signer (keypair) // - Building an assertion with the fluent API // - Submitting to StemeDB (auto-signed) // - Understanding eventual consistency // - Querying with a lens package main import ( "context" "fmt" "log" "time" "github.com/orchard9/stemedb-go/steme" ) func main() { // 1. Generate a new keypair // // In production, you'd load this from environment or key management. // For this example, we generate a new one each run. signer, err := steme.GenerateSigner() if err != nil { log.Fatalf("Failed to generate signer: %v", err) } fmt.Printf("Agent ID (public key): %s\n", signer.PublicKey()) fmt.Printf("Seed (save this!): %s\n\n", signer.Seed()) // 2. Create a StemeDB client // // The client automatically signs all assertions using the signer. client := steme.NewClient("http://localhost:3000", signer) // 3. Build an assertion with the fluent API // // This asserts: "Tesla_Inc has_revenue 96.7 (billion USD)" // with 95% confidence, marked as Approved, sourced from Clinical evidence. assertion := steme.NewAssertion("Tesla_Inc", "has_revenue"). WithNumber(96.7). WithConfidence(0.95). WithLifecycle(steme.LifecycleApproved). WithSourceClass(steme.SourceClassClinical). WithSourceHash("0000000000000000000000000000000000000000000000000000000000000000"). Build() // 4. Submit to StemeDB // // The client automatically: // - Signs the assertion with your private key // - Adds a timestamp // - POSTs to /v1/assert // - Returns the content-addressed hash hash, err := client.Assert(context.Background(), assertion) if err != nil { log.Fatalf("Failed to assert: %v", err) } fmt.Printf("✓ Created assertion: %s\n\n", hash) // 5. Understanding Eventual Consistency // // StemeDB is eventually consistent by design. When Assert() returns, // the assertion is durably written to the Write-Ahead Log (WAL), but // the background IngestWorker hasn't necessarily indexed it yet. // // This is intentional for high write throughput. For production code: // - Design workflows that tolerate async (recommended for agents) // - Use polling with timeout when read-after-write is needed // - Check health.AssertionsCount to monitor ingestion progress // // Here we demonstrate polling until the assertion is queryable: params := steme.NewQuery(). WithSubject("Tesla_Inc"). WithPredicate("has_revenue"). WithLens(steme.LensConsensus). Build() fmt.Println("Waiting for ingestion...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() var result *steme.QueryResult for { result, err = client.Query(ctx, params) if err != nil { log.Fatalf("Failed to query: %v", err) } if result.TotalCount > 0 { fmt.Println("✓ Assertion indexed") fmt.Println() break } select { case <-ctx.Done(): // Timeout - assertion created but not yet indexed // This is normal; in production, design for eventual consistency fmt.Println("Note: Assertion created but not yet indexed") fmt.Println("This is expected - StemeDB is eventually consistent") fmt.Println() goto showResults case <-time.After(100 * time.Millisecond): // Continue polling } } showResults: // 6. Display query results fmt.Printf("Query Results:\n") fmt.Printf(" Total: %d assertions\n", result.TotalCount) fmt.Printf(" Has more: %v\n\n", result.HasMore) for i, a := range result.Assertions { fmt.Printf("Assertion #%d:\n", i+1) fmt.Printf(" Hash: %s\n", a.Hash) fmt.Printf(" Subject: %s\n", a.Subject) fmt.Printf(" Predicate: %s\n", a.Predicate) fmt.Printf(" Object: %v (%s)\n", a.Object.Value, a.Object.Type) fmt.Printf(" Confidence: %.2f\n", a.Confidence) fmt.Printf(" Lifecycle: %s\n", a.Lifecycle) fmt.Printf(" Source Class: %s\n", a.SourceClass) fmt.Printf(" Signatures: %d agents\n", len(a.Signatures)) fmt.Printf("\n") } // 7. Health check health, err := client.Health(context.Background()) if err != nil { log.Fatalf("Failed health check: %v", err) } fmt.Printf("StemeDB Health:\n") fmt.Printf(" Status: %s\n", health.Status) fmt.Printf(" Version: %s\n", health.Version) fmt.Printf(" Assertions: %d\n", health.AssertionsCount) }