stemedb/ai-lookup/services/sdk.md
jordan 1ce4004807 feat: Complete Phase 2 (The Cortex) - query, lens, and API layers
This commit adds the read path (Cortex) to complement the write path (Spine):

## Crates
- stemedb-api: HTTP API with axum + utoipa OpenAPI
  - /v1/assert, /v1/query, /v1/epoch, /v1/skeptic, /v1/trace, /v1/audit
  - Metered endpoints with quota enforcement
  - Ed25519 signature verification
- stemedb-lens: Truth resolution lenses
  - RecencyLens, ConsensusLens, ConfidenceLens
  - VoteAwareConsensusLens (Ballot Box pattern)
  - TrustAwareAuthorityLens (The Hive pattern)
  - SkepticLens (conflict analysis)
  - EpochAwareLens (paradigm-safe queries)
- stemedb-query: Query engine with materialized views

## Storage Extensions
- VoteStore: Vote aggregation with cached counts
- TrustRankStore: Agent reputation with decay
- AuditStore: Query audit trail
- IndexStore: SP/P/S index structures
- SupersessionStore: Epoch supersession chains

## SDKs
- sdk/go/steme: Go HTTP client with Ed25519 signing
- sdk/go/adk: ADK-Go tools for AI agents

## Documentation
- Updated CLAUDE.md, architecture.md, roadmap.md
- New ai-lookup entries for all services
- Use case docs for consumer health intelligence
- Arena roadmap for simulation advancement

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

9.8 KiB

SDK - Go Client Libraries

Last Updated: 2026-02-01 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

import "github.com/orchard9/stemedb/sdk/go/steme"

Client Creation

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

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

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

err := client.Vote(ctx, steme.VoteRequest{
    AssertionHash: targetHash,
    Upvote:        true,
    AgentID:       myAgentID,
    VoteHash:      voteContentHash,
})

ADK Integration (adk)

Installation

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:

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

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

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

type ConstraintCheckInput struct {
    Context string `json:"context"`  // e.g., "python_http", "auth_jwt"
}

Trace Tool (SRE debugging)

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)

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)

// Blocks tool calls that violate organizational constraints
// Example: Prevents using SHA1 if auth/jwt has "forbidden: sha1"
BeforeToolCallback: adk.ConstraintEnforcementCallback(client)

AuditLogging (AfterModelCallback)

// Logs agent decisions for debugging and replay
AfterModelCallback: adk.AuditLoggingCallback(client)

ConfidenceEscalation (AfterToolCallback)

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

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

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