stemedb/sdk/go/examples/basic/main.go
jordan c59066949a feat: Add quickstart "Beyond Hello World" sections with Skeptic and Layered endpoints
- Add Layered() method to Go SDK for per-source-class consensus queries
- Add LayeredQueryParams, LayeredResult, TierResolution types to Go SDK
- Create conflict example demonstrating Skeptic and Layered endpoints
- Update quickstart.md with sections 6 (conflict detection) and 7 (authority tiers)
- Remove tracked Go binary and add data/ to .gitignore

The new quickstart sections demonstrate Episteme's differentiating features:
- Skeptic endpoint shows "Trust but Verify" conflict analysis
- Layered endpoint shows per-tier resolution (Clinical vs Anecdotal)

Note: Pre-existing large files flagged by pre-commit hook (technical debt from prior sessions)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:00:59 -07:00

141 lines
4.2 KiB
Go

// 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)
}