# BZZZ SDK Documentation

**Version 2.0 - Phase 2B Edition**  
Software Development Kit for integrating with and extending BZZZ's semantic context publishing platform.

## Table of Contents

1. [SDK Overview](#sdk-overview)
2. [Installation](#installation)
3. [Core SDK](#core-sdk)
4. [Crypto SDK](#crypto-sdk)
5. [DHT SDK](#dht-sdk)
6. [Decision SDK](#decision-sdk)
7. [Election SDK](#election-sdk)
8. [Configuration SDK](#configuration-sdk)
9. [Examples](#examples)
10. [Language Bindings](#language-bindings)

## SDK Overview

The BZZZ SDK provides programmatic access to all BZZZ functionality, enabling developers to:
- Integrate BZZZ into existing applications
- Build custom agents and decision publishers
- Implement custom crypto providers
- Create specialized storage backends
- Develop monitoring and analytics tools

### Architecture

```
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Client App    │    │   BZZZ SDK      │    │   BZZZ Node     │
│                 │────│                 │────│                 │
│ - Custom Logic  │    │ - Go Packages   │    │ - Core Services │
│ - UI/CLI        │    │ - HTTP Client   │    │ - P2P Network   │ 
│ - Integrations  │    │ - Type Safety   │    │ - DHT Storage   │
└─────────────────┘    └─────────────────┘    └─────────────────┘
```

### Key Features

- **Type-Safe**: Full Go type safety with comprehensive error handling
- **Async Operations**: Non-blocking operations with context cancellation
- **Encryption Support**: Built-in Age encryption with role-based access
- **DHT Integration**: Direct access to distributed storage
- **Real-time Events**: WebSocket-based event streaming
- **Configuration Management**: Programmatic configuration updates

**Cross-References**:
- Core implementation: `pkg/` packages
- HTTP API: [API_REFERENCE.md](API_REFERENCE.md)
- Examples: `examples/sdk/` directory

## Installation

### Go Module

Add BZZZ SDK to your Go project:

```bash
go mod init your-project
go get github.com/anthonyrawlins/bzzz/sdk
```

### Import SDK

```go
import (
    "github.com/anthonyrawlins/bzzz/sdk/bzzz"
    "github.com/anthonyrawlins/bzzz/sdk/crypto"
    "github.com/anthonyrawlins/bzzz/sdk/dht"
    "github.com/anthonyrawlins/bzzz/sdk/decisions"
    "github.com/anthonyrawlins/bzzz/sdk/elections"
)
```

### SDK Client

Create the main SDK client:

```go
package main

import (
    "context"
    "log"
    
    "github.com/anthonyrawlins/bzzz/sdk/bzzz"
)

func main() {
    // Create SDK client
    client, err := bzzz.NewClient(bzzz.Config{
        Endpoint: "http://localhost:8080",
        Role:     "backend_developer",
        Timeout:  30 * time.Second,
    })
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
    
    // Use the client
    status, err := client.GetStatus(context.Background())
    if err != nil {
        log.Fatal(err)
    }
    
    log.Printf("Connected to BZZZ node: %s", status.NodeID)
}
```

## Core SDK

The core SDK provides basic connectivity and agent management.

### Client Configuration

```go
// SDK configuration
type Config struct {
    Endpoint     string        `yaml:"endpoint"`     // BZZZ node endpoint
    Role         string        `yaml:"role"`         // Client role
    Timeout      time.Duration `yaml:"timeout"`      // Request timeout
    RetryCount   int           `yaml:"retry_count"`  // Retry attempts
    RateLimit    int           `yaml:"rate_limit"`   // Requests per second
    
    // Authentication (optional)
    AuthToken    string        `yaml:"auth_token,omitempty"`
    
    // TLS Configuration (optional)
    TLSConfig    *tls.Config   `yaml:"-"`
    
    // Crypto configuration
    AgeKeys      *AgeKeyPair   `yaml:"age_keys,omitempty"`
}

// Create client with configuration
client, err := bzzz.NewClient(Config{
    Endpoint:   "http://localhost:8080",
    Role:       "backend_developer", 
    Timeout:    30 * time.Second,
    RetryCount: 3,
    RateLimit:  10,
})
```

### Agent Operations

```go
// Get agent status
status, err := client.GetStatus(ctx)
if err != nil {
    return fmt.Errorf("failed to get status: %w", err)
}

fmt.Printf("Agent: %s\n", status.AgentID)
fmt.Printf("Role: %s\n", status.Role)
fmt.Printf("Authority: %s\n", status.AuthorityLevel)
fmt.Printf("Can decrypt: %v\n", status.CanDecrypt)

// Get connected peers
peers, err := client.GetPeers(ctx)
if err != nil {
    return fmt.Errorf("failed to get peers: %w", err)
}

for _, peer := range peers.ConnectedPeers {
    fmt.Printf("Peer: %s (%s)\n", peer.AgentID, peer.Role)
}

// Update agent configuration
err = client.UpdateRole(ctx, bzzz.RoleUpdate{
    Role:           "senior_software_architect",
    Specialization: "architecture",
    Models:         []string{"gpt-4", "claude-3"},
})
if err != nil {
    return fmt.Errorf("failed to update role: %w", err)
}
```

### Event Streaming

```go
// Subscribe to real-time events
events, err := client.SubscribeEvents(ctx)
if err != nil {
    return fmt.Errorf("failed to subscribe to events: %w", err)
}
defer events.Close()

for {
    select {
    case event := <-events.Events():
        switch event.Type {
        case "decision_published":
            fmt.Printf("New decision: %s\n", event.Data["address"])
        case "admin_changed":
            fmt.Printf("Admin changed: %s -> %s\n", 
                event.Data["old_admin"], event.Data["new_admin"])
        case "peer_connected":
            fmt.Printf("Peer connected: %s\n", event.Data["agent_id"])
        }
        
    case err := <-events.Errors():
        log.Printf("Event stream error: %v", err)
        
    case <-ctx.Done():
        return ctx.Err()
    }
}
```

**Cross-Reference**: Core client implementation in `sdk/bzzz/client.go`

## Crypto SDK

The crypto SDK provides Age encryption functionality with role-based access control.

### Basic Encryption

```go
import "github.com/anthonyrawlins/bzzz/sdk/crypto"

// Create crypto client
cryptoClient := crypto.NewClient(client)

// Generate new Age key pair
keyPair, err := cryptoClient.GenerateKeyPair(ctx)
if err != nil {
    return fmt.Errorf("failed to generate keys: %w", err)
}

fmt.Printf("Public Key: %s\n", keyPair.PublicKey)
// Store keyPair.PrivateKey securely

// Encrypt content for specific role
content := []byte("Sensitive decision content")
encrypted, err := cryptoClient.EncryptForRole(ctx, content, "backend_developer")
if err != nil {
    return fmt.Errorf("encryption failed: %w", err)
}

// Decrypt content (if you have permission)
decrypted, err := cryptoClient.DecryptWithRole(ctx, encrypted)
if err != nil {
    return fmt.Errorf("decryption failed: %w", err)
}

fmt.Printf("Decrypted: %s\n", string(decrypted))
```

### Multi-Role Encryption

```go
// Encrypt for multiple roles
roles := []string{"backend_developer", "senior_software_architect", "admin"}
encrypted, err := cryptoClient.EncryptForMultipleRoles(ctx, content, roles)
if err != nil {
    return fmt.Errorf("multi-role encryption failed: %w", err)
}

// Check if current role can decrypt content from another role
canDecrypt, err := cryptoClient.CanDecryptFrom(ctx, "admin")
if err != nil {
    return fmt.Errorf("permission check failed: %w", err)
}

if !canDecrypt {
    return fmt.Errorf("insufficient permissions to decrypt admin content")
}
```

### Key Management

```go
// Validate existing keys
valid, err := cryptoClient.ValidateKeys(ctx, crypto.KeyValidation{
    PublicKey:  "age1...",
    PrivateKey: "AGE-SECRET-KEY-1...",
    TestEncryption: true,
})
if err != nil {
    return fmt.Errorf("key validation failed: %w", err)
}

if !valid.Valid {
    return fmt.Errorf("invalid keys: %s", valid.Error)
}

// Get current role permissions
permissions, err := cryptoClient.GetPermissions(ctx)
if err != nil {
    return fmt.Errorf("failed to get permissions: %w", err)
}

fmt.Printf("Current role: %s\n", permissions.CurrentRole)
fmt.Printf("Can decrypt: %v\n", permissions.CanDecrypt)
fmt.Printf("Authority level: %s\n", permissions.AuthorityLevel)
```

### Custom Crypto Providers

```go
// Implement custom crypto provider
type CustomCrypto struct {
    // Custom implementation fields
}

func (cc *CustomCrypto) Encrypt(content []byte, recipients []string) ([]byte, error) {
    // Custom encryption logic
    return nil, nil
}

func (cc *CustomCrypto) Decrypt(encrypted []byte, key string) ([]byte, error) {
    // Custom decryption logic  
    return nil, nil
}

// Register custom provider
cryptoClient.RegisterProvider("custom", &CustomCrypto{})

// Use custom provider
encrypted, err := cryptoClient.EncryptWithProvider(ctx, "custom", content, recipients)
```

**Cross-Reference**: Crypto implementation in `pkg/crypto/` and `sdk/crypto/`

## DHT SDK

The DHT SDK provides direct access to distributed hash table storage operations.

### Basic DHT Operations

```go
import "github.com/anthonyrawlins/bzzz/sdk/dht"

// Create DHT client
dhtClient := dht.NewClient(client)

// Store content with automatic encryption
err = dhtClient.StoreContent(ctx, dht.StoreRequest{
    Address:     "my_agent/backend_developer/project/task/12345",
    Content:     []byte("Task completion data"),
    ContentType: "decision",
    Metadata: map[string]interface{}{
        "language": "go",
        "files_changed": 3,
    },
})
if err != nil {
    return fmt.Errorf("failed to store content: %w", err)
}

// Retrieve and decrypt content
content, metadata, err := dhtClient.RetrieveContent(ctx, "my_agent/backend_developer/project/task/12345")
if err != nil {
    return fmt.Errorf("failed to retrieve content: %w", err)
}

fmt.Printf("Content: %s\n", string(content))
fmt.Printf("Creator: %s\n", metadata.CreatorRole)
fmt.Printf("Size: %d bytes\n", metadata.Size)
```

### Search and Discovery

```go
// Search for content by criteria
results, err := dhtClient.Search(ctx, dht.SearchRequest{
    Role:        "backend_developer",
    Project:     "user_auth", 
    ContentType: "decision",
    Since:       time.Now().Add(-24 * time.Hour),
    Limit:       10,
})
if err != nil {
    return fmt.Errorf("search failed: %w", err)
}

for _, result := range results.Items {
    fmt.Printf("Found: %s (%s)\n", result.Address, result.ContentType)
}

// Discover peers with specific content
peers, err := dhtClient.DiscoverPeers(ctx, "agent/role/project/task/node")
if err != nil {
    return fmt.Errorf("peer discovery failed: %w", err)
}

fmt.Printf("Content available on %d peers\n", len(peers.Peers))
```

### DHT Metrics

```go
// Get DHT performance metrics
metrics, err := dhtClient.GetMetrics(ctx)
if err != nil {
    return fmt.Errorf("failed to get metrics: %w", err)
}

fmt.Printf("Stored items: %d\n", metrics.StoredItems)
fmt.Printf("Cache hit rate: %.2f%%\n", metrics.CacheHitRate*100)
fmt.Printf("Average store time: %v\n", metrics.AverageStoreTime)
fmt.Printf("Connected peers: %d\n", metrics.ConnectedPeers)
```

### Raw DHT Access (Admin Only)

```go
// Admin-only: Direct DHT operations
if client.IsAdmin() {
    // Store raw encrypted content
    err = dhtClient.StoreRaw(ctx, dht.RawStoreRequest{
        Address:     "admin/admin/system/backup/12345",
        Content:     encryptedBackupData,
        Metadata:    backupMetadata,
    })
    
    // Retrieve raw encrypted content
    rawContent, err := dhtClient.RetrieveRaw(ctx, "admin/admin/system/backup/12345")
    if err != nil {
        return fmt.Errorf("failed to retrieve raw content: %w", err)
    }
}
```

**Cross-Reference**: DHT implementation in `pkg/dht/` and `sdk/dht/`

## Decision SDK

The decision SDK simplifies publishing and querying decision content.

### Publishing Decisions

```go
import "github.com/anthonyrawlins/bzzz/sdk/decisions"

// Create decision client
decisionClient := decisions.NewClient(client)

// Publish architectural decision
err = decisionClient.PublishArchitectural(ctx, decisions.ArchitecturalDecision{
    Task:     "migrate_to_microservices",
    Decision: "Split monolith into 5 domain-based microservices",
    Rationale: "Improve scalability and team autonomy",
    Alternatives: []string{
        "Keep monolith with better modularization",
        "Partial split into 2 services",
    },
    Implications: []string{
        "Increased operational complexity",
        "Better fault isolation",
        "Need for service mesh",
    },
    NextSteps: []string{
        "Define service boundaries",
        "Plan data migration strategy",
    },
})
if err != nil {
    return fmt.Errorf("failed to publish decision: %w", err)
}

// Publish code decision with test results
err = decisionClient.PublishCode(ctx, decisions.CodeDecision{
    Task:     "implement_user_auth",
    Decision: "Implemented JWT authentication with refresh tokens",
    FilesModified: []string{
        "internal/auth/jwt.go",
        "internal/middleware/auth.go",
    },
    LinesChanged: 245,
    TestResults: &decisions.TestResults{
        Passed:   18,
        Failed:   1,
        Skipped:  2,
        Coverage: 87.5,
        FailedTests: []string{"TestJWT_ExpiredToken"},
    },
    Dependencies: []string{
        "github.com/golang-jwt/jwt/v5",
        "golang.org/x/crypto/bcrypt",
    },
})
if err != nil {
    return fmt.Errorf("failed to publish code decision: %w", err)
}

// Publish system status
err = decisionClient.PublishSystemStatus(ctx, decisions.SystemStatus{
    Status: "All systems operational",
    Metrics: map[string]interface{}{
        "uptime_hours":    24,
        "active_peers":    4,
        "decisions_count": 25,
    },
    HealthChecks: map[string]bool{
        "database": true,
        "dht":      true,
        "crypto":   true,
    },
})
```

### Querying Decisions

```go
// Query recent decisions
recent, err := decisionClient.QueryRecent(ctx, decisions.QueryRequest{
    Role:    "backend_developer",
    Project: "user_auth",
    Since:   time.Now().Add(-7 * 24 * time.Hour), // Last week
    Limit:   20,
})
if err != nil {
    return fmt.Errorf("failed to query decisions: %w", err)
}

for _, decision := range recent.Decisions {
    fmt.Printf("Decision: %s\n", decision.Address)
    fmt.Printf("  Task: %s\n", decision.Task)
    fmt.Printf("  Success: %t\n", decision.Success)
    fmt.Printf("  Created: %s\n", decision.Timestamp.Format(time.RFC3339))
}

// Get specific decision content
content, err := decisionClient.GetContent(ctx, "agent/role/project/task/node")
if err != nil {
    return fmt.Errorf("failed to get decision content: %w", err)
}

fmt.Printf("Decision: %s\n", content.Decision)
if content.TestResults != nil {
    fmt.Printf("Tests: %d passed, %d failed\n", 
        content.TestResults.Passed, content.TestResults.Failed)
}
```

### Custom Decision Types

```go
// Define custom decision type
type DataScienceDecision struct {
    decisions.TaskDecision
    ModelName        string            `json:"model_name"`
    TrainingAccuracy float64           `json:"training_accuracy"`
    DatasetSize      int               `json:"dataset_size"`
    HyperParams      map[string]float64 `json:"hyperparameters"`
}

// Publish custom decision
customDecision := &DataScienceDecision{
    TaskDecision: decisions.TaskDecision{
        Task:     "train_sentiment_model",
        Decision: "Trained BERT model for sentiment analysis",
        Success:  true,
    },
    ModelName:        "bert-base-sentiment",
    TrainingAccuracy: 0.94,
    DatasetSize:      50000,
    HyperParams: map[string]float64{
        "learning_rate": 0.001,
        "batch_size":    32,
        "epochs":        10,
    },
}

err = decisionClient.PublishCustom(ctx, "data_science", customDecision)
if err != nil {
    return fmt.Errorf("failed to publish custom decision: %w", err)
}
```

### Decision Streaming

```go
// Stream decisions in real-time
stream, err := decisionClient.StreamDecisions(ctx, decisions.StreamRequest{
    Role:        "backend_developer",
    ContentType: "decision",
})
if err != nil {
    return fmt.Errorf("failed to start stream: %w", err)
}
defer stream.Close()

for {
    select {
    case decision := <-stream.Decisions():
        fmt.Printf("New decision: %s\n", decision.Address)
        processDecision(decision)
        
    case err := <-stream.Errors():
        log.Printf("Stream error: %v", err)
        
    case <-ctx.Done():
        return ctx.Err()
    }
}
```

**Cross-Reference**: Decision implementation in `pkg/ucxl/` and `sdk/decisions/`

## Election SDK

The election SDK provides access to admin election and consensus operations.

### Election Management

```go
import "github.com/anthonyrawlins/bzzz/sdk/elections"

// Create election client
electionClient := elections.NewClient(client)

// Get current election status
status, err := electionClient.GetStatus(ctx)
if err != nil {
    return fmt.Errorf("failed to get election status: %w", err)
}

fmt.Printf("Current admin: %s\n", status.CurrentAdmin)
fmt.Printf("Election active: %t\n", status.IsElectionActive)
fmt.Printf("Last heartbeat: %s\n", status.LastHeartbeat.Format(time.RFC3339))

// Monitor election events
events, err := electionClient.MonitorElections(ctx)
if err != nil {
    return fmt.Errorf("failed to monitor elections: %w", err)
}
defer events.Close()

for {
    select {
    case event := <-events.Events():
        switch event.Type {
        case elections.ElectionStarted:
            fmt.Printf("Election started: %s\n", event.ElectionID)
            
        case elections.CandidateProposed:
            fmt.Printf("New candidate: %s (score: %.1f)\n", 
                event.Candidate.NodeID, event.Candidate.Score)
                
        case elections.ElectionCompleted:
            fmt.Printf("Election completed. Winner: %s\n", event.Winner)
            
        case elections.AdminHeartbeat:
            fmt.Printf("Admin heartbeat from: %s\n", event.AdminID)
        }
        
    case <-ctx.Done():
        return ctx.Err()
    }
}
```

### Admin Operations

```go
// Admin-only operations
if client.IsAdmin() {
    // Trigger manual election
    election, err := electionClient.TriggerElection(ctx, elections.TriggerRequest{
        Reason: "manual_trigger",
        Force:  false,
    })
    if err != nil {
        return fmt.Errorf("failed to trigger election: %w", err)
    }
    
    fmt.Printf("Election %s started with %d candidates\n", 
        election.ElectionID, len(election.Candidates))
    
    // Get admin key shares information
    shares, err := electionClient.GetKeyShares(ctx)
    if err != nil {
        return fmt.Errorf("failed to get key shares: %w", err)
    }
    
    fmt.Printf("Key shares: %d/%d distributed\n", 
        len(shares.DistributedShares), shares.TotalShares)
    fmt.Printf("Reconstruction possible: %t\n", shares.ReconstructionPossible)
}
```

### Consensus Operations

```go
// Participate in consensus (for eligible nodes)
if status.CanParticipate {
    // Propose candidacy
    err = electionClient.ProposeCandidate(ctx, elections.CandidateProposal{
        Capabilities: []string{"high_uptime", "master_authority"},
        Resources: elections.NodeResources{
            CPU:    0.2,  // 20% CPU usage
            Memory: 0.15, // 15% memory usage  
            Disk:   0.45, // 45% disk usage
        },
    })
    if err != nil {
        return fmt.Errorf("failed to propose candidacy: %w", err)
    }
    
    // Vote in election (automatic based on scoring)
    vote, err := electionClient.CastVote(ctx, elections.VoteRequest{
        ElectionID:   status.CurrentElection,
        CandidateID:  "QmBestCandidate",
        VoteValue:    true,
    })
    if err != nil {
        return fmt.Errorf("failed to cast vote: %w", err)
    }
    
    fmt.Printf("Vote cast: %t\n", vote.Recorded)
}
```

**Cross-Reference**: Election implementation in `pkg/election/` and `sdk/elections/`

## Configuration SDK

The configuration SDK provides programmatic access to BZZZ configuration management.

### Configuration Management

```go
import "github.com/anthonyrawlins/bzzz/sdk/config"

// Create config client
configClient := config.NewClient(client)

// Get current configuration
cfg, err := configClient.GetConfig(ctx)
if err != nil {
    return fmt.Errorf("failed to get config: %w", err)
}

fmt.Printf("Node ID: %s\n", cfg.NodeID)
fmt.Printf("Role: %s\n", cfg.Agent.Role)
fmt.Printf("Authority: %s\n", cfg.Agent.AuthorityLevel)

// Update agent configuration
err = configClient.UpdateAgent(ctx, config.AgentUpdate{
    Role:           "senior_software_architect",
    Specialization: "microservices_architecture", 
    Models:         []string{"gpt-4", "claude-3-opus"},
    MaxTasks:       10,
})
if err != nil {
    return fmt.Errorf("failed to update agent config: %w", err)
}

// Update security configuration (admin only)
if client.IsAdmin() {
    err = configClient.UpdateSecurity(ctx, config.SecurityUpdate{
        AdminKeyShares: config.ShamirConfig{
            Threshold:   3,
            TotalShares: 5,
        },
        ElectionTimeout: 30 * time.Second,
        HeartbeatInterval: 5 * time.Second,
    })
    if err != nil {
        return fmt.Errorf("failed to update security config: %w", err)
    }
}
```

### Role Management

```go
// Get available roles
roles, err := configClient.GetRoles(ctx)
if err != nil {
    return fmt.Errorf("failed to get roles: %w", err)
}

for name, role := range roles.Roles {
    fmt.Printf("Role: %s\n", name)
    fmt.Printf("  Authority: %s\n", role.AuthorityLevel)
    fmt.Printf("  Can decrypt: %v\n", role.CanDecrypt)
    fmt.Printf("  Model: %s\n", role.Model)
}

// Create custom role
err = configClient.CreateRole(ctx, config.RoleDefinition{
    Name:           "data_scientist",
    AuthorityLevel: "decision",
    CanDecrypt:     []string{"data_scientist", "backend_developer", "observer"},
    Model:          "ollama/llama3.1",
    DecisionScope:  []string{"data", "analytics", "ml_models"},
    SpecialFunctions: []string{"model_training", "data_analysis"},
})
if err != nil {
    return fmt.Errorf("failed to create role: %w", err)
}

// Generate keys for role
keys, err := configClient.GenerateRoleKeys(ctx, "data_scientist")
if err != nil {
    return fmt.Errorf("failed to generate role keys: %w", err)
}

fmt.Printf("Generated keys for data_scientist role\n")
fmt.Printf("Public key: %s\n", keys.PublicKey)
// Store keys.PrivateKey securely
```

### Configuration Validation

```go
// Validate configuration
validation, err := configClient.ValidateConfig(ctx, cfg)
if err != nil {
    return fmt.Errorf("failed to validate config: %w", err)
}

if !validation.Valid {
    fmt.Printf("Configuration validation failed:\n")
    for _, error := range validation.Errors {
        fmt.Printf("  - %s: %s\n", error.Field, error.Message)
    }
    return fmt.Errorf("invalid configuration")
}

// Get configuration schema
schema, err := configClient.GetSchema(ctx)
if err != nil {
    return fmt.Errorf("failed to get schema: %w", err)
}

// Use schema for validation in external tools
fmt.Printf("Schema version: %s\n", schema.Version)
fmt.Printf("Required fields: %v\n", schema.RequiredFields)
```

**Cross-Reference**: Configuration implementation in `pkg/config/` and `sdk/config/`

## Examples

### Complete Agent Implementation

```go
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "os/signal"
    "syscall"
    "time"
    
    "github.com/anthonyrawlins/bzzz/sdk/bzzz"
    "github.com/anthonyrawlins/bzzz/sdk/decisions"
    "github.com/anthonyrawlins/bzzz/sdk/crypto"
)

type CustomAgent struct {
    client    *bzzz.Client
    decisions *decisions.Client
    crypto    *crypto.Client
    shutdown  chan os.Signal
}

func NewCustomAgent(endpoint, role string) (*CustomAgent, error) {
    // Create BZZZ client
    client, err := bzzz.NewClient(bzzz.Config{
        Endpoint: endpoint,
        Role:     role,
        Timeout:  30 * time.Second,
    })
    if err != nil {
        return nil, fmt.Errorf("failed to create client: %w", err)
    }
    
    // Create specialized clients
    decisionsClient := decisions.NewClient(client)
    cryptoClient := crypto.NewClient(client)
    
    agent := &CustomAgent{
        client:    client,
        decisions: decisionsClient,
        crypto:    cryptoClient,
        shutdown:  make(chan os.Signal, 1),
    }
    
    signal.Notify(agent.shutdown, os.Interrupt, syscall.SIGTERM)
    
    return agent, nil
}

func (a *CustomAgent) Run(ctx context.Context) error {
    log.Printf("Starting custom BZZZ agent...")
    
    // Get initial status
    status, err := a.client.GetStatus(ctx)
    if err != nil {
        return fmt.Errorf("failed to get status: %w", err)
    }
    
    log.Printf("Connected as %s (%s)", status.AgentID, status.Role)
    
    // Start event monitoring
    events, err := a.client.SubscribeEvents(ctx)
    if err != nil {
        return fmt.Errorf("failed to subscribe to events: %w", err)
    }
    defer events.Close()
    
    // Start decision monitoring
    decisions, err := a.decisions.StreamDecisions(ctx, decisions.StreamRequest{
        Role: status.Role,
    })
    if err != nil {
        return fmt.Errorf("failed to stream decisions: %w", err)
    }
    defer decisions.Close()
    
    // Start task processing
    go a.processTask(ctx)
    
    // Main event loop
    for {
        select {
        case event := <-events.Events():
            a.handleEvent(event)
            
        case decision := <-decisions.Decisions():
            a.handleDecision(decision)
            
        case <-a.shutdown:
            log.Printf("Shutting down agent...")
            return nil
            
        case <-ctx.Done():
            return ctx.Err()
        }
    }
}

func (a *CustomAgent) handleEvent(event bzzz.Event) {
    switch event.Type {
    case "admin_changed":
        log.Printf("Admin changed: %s -> %s", 
            event.Data["old_admin"], event.Data["new_admin"])
            
    case "peer_connected":
        log.Printf("Peer connected: %s (%s)", 
            event.Data["agent_id"], event.Data["role"])
            
    default:
        log.Printf("Received event: %s", event.Type)
    }
}

func (a *CustomAgent) handleDecision(decision decisions.TaskDecision) {
    log.Printf("New decision: %s - %s", decision.Task, decision.Decision)
    
    // Process decision based on your logic
    if decision.Success && len(decision.FilesModified) > 0 {
        log.Printf("Successful task with %d files modified", len(decision.FilesModified))
        // Trigger related tasks or analysis
    }
}

func (a *CustomAgent) processTask(ctx context.Context) {
    // Simulate task processing
    ticker := time.NewTicker(60 * time.Second)
    defer ticker.Stop()
    
    taskCounter := 0
    
    for {
        select {
        case <-ticker.C:
            taskCounter++
            
            // Simulate completing a task
            err := a.decisions.PublishCode(ctx, decisions.CodeDecision{
                Task:     fmt.Sprintf("automated_task_%d", taskCounter),
                Decision: "Completed automated code analysis task",
                FilesModified: []string{
                    fmt.Sprintf("analysis/task_%d.go", taskCounter),
                },
                LinesChanged: 50 + taskCounter*10,
                TestResults: &decisions.TestResults{
                    Passed:   5,
                    Failed:   0,
                    Coverage: 85.0 + float64(taskCounter),
                },
            })
            
            if err != nil {
                log.Printf("Failed to publish task completion: %v", err)
            } else {
                log.Printf("Published completion for task %d", taskCounter)
            }
            
        case <-ctx.Done():
            return
        }
    }
}

func main() {
    agent, err := NewCustomAgent("http://localhost:8080", "backend_developer")
    if err != nil {
        log.Fatal(err)
    }
    defer agent.client.Close()
    
    ctx := context.Background()
    if err := agent.Run(ctx); err != nil {
        log.Fatal(err)
    }
}
```

### Data Analysis Tool

```go
package main

import (
    "context"
    "fmt"
    "time"
    
    "github.com/anthonyrawlins/bzzz/sdk/bzzz"
    "github.com/anthonyrawlins/bzzz/sdk/decisions"
)

func analyzeDecisions() error {
    // Connect to BZZZ
    client, err := bzzz.NewClient(bzzz.Config{
        Endpoint: "http://localhost:8080",
        Role:     "observer", // Read-only access
    })
    if err != nil {
        return err
    }
    defer client.Close()
    
    decisionsClient := decisions.NewClient(client)
    
    // Query last 30 days of decisions
    since := time.Now().Add(-30 * 24 * time.Hour)
    recent, err := decisionsClient.QueryRecent(context.Background(), decisions.QueryRequest{
        Since: since,
        Limit: 1000,
    })
    if err != nil {
        return err
    }
    
    // Analyze decision patterns
    roleStats := make(map[string]int)
    projectStats := make(map[string]int)
    successRate := 0
    totalDecisions := len(recent.Decisions)
    
    for _, decision := range recent.Decisions {
        // Get full decision content
        content, err := decisionsClient.GetContent(context.Background(), decision.Address)
        if err != nil {
            continue // Skip if we can't decrypt
        }
        
        roleStats[content.Role]++
        projectStats[content.Project]++
        
        if content.Success {
            successRate++
        }
    }
    
    // Print analysis
    fmt.Printf("Decision Analysis (Last 30 Days)\n")
    fmt.Printf("================================\n")
    fmt.Printf("Total decisions: %d\n", totalDecisions)
    fmt.Printf("Success rate: %.1f%%\n", float64(successRate)/float64(totalDecisions)*100)
    
    fmt.Printf("\nDecisions by Role:\n")
    for role, count := range roleStats {
        fmt.Printf("  %s: %d\n", role, count)
    }
    
    fmt.Printf("\nDecisions by Project:\n")
    for project, count := range projectStats {
        fmt.Printf("  %s: %d\n", project, count)
    }
    
    return nil
}
```

### Monitoring Dashboard

```go
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "html/template"
    "net/http"
    "time"
    
    "github.com/anthonyrawlins/bzzz/sdk/bzzz"
    "github.com/anthonyrawlins/bzzz/sdk/dht"
    "github.com/anthonyrawlins/bzzz/sdk/elections"
)

type Dashboard struct {
    client    *bzzz.Client
    dht       *dht.Client
    elections *elections.Client
}

func NewDashboard(bzzzEndpoint string) (*Dashboard, error) {
    client, err := bzzz.NewClient(bzzz.Config{
        Endpoint: bzzzEndpoint,
        Role:     "observer",
    })
    if err != nil {
        return nil, err
    }
    
    return &Dashboard{
        client:    client,
        dht:       dht.NewClient(client),
        elections: elections.NewClient(client),
    }, nil
}

func (d *Dashboard) GetMetrics(ctx context.Context) (map[string]interface{}, error) {
    // Get node status
    status, err := d.client.GetStatus(ctx)
    if err != nil {
        return nil, err
    }
    
    // Get DHT metrics
    dhtMetrics, err := d.dht.GetMetrics(ctx)
    if err != nil {
        return nil, err
    }
    
    // Get election status
    electionStatus, err := d.elections.GetStatus(ctx)
    if err != nil {
        return nil, err
    }
    
    // Get peers
    peers, err := d.client.GetPeers(ctx)
    if err != nil {
        return nil, err
    }
    
    return map[string]interface{}{
        "node":      status,
        "dht":       dhtMetrics,
        "elections": electionStatus,
        "peers":     peers,
        "timestamp": time.Now(),
    }, nil
}

func (d *Dashboard) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    switch r.URL.Path {
    case "/":
        d.serveDashboard(w, r)
    case "/api/metrics":
        d.serveMetrics(w, r)
    case "/api/events":
        d.serveEventStream(w, r)
    default:
        http.NotFound(w, r)
    }
}

func (d *Dashboard) serveDashboard(w http.ResponseWriter, r *http.Request) {
    tmpl := template.Must(template.New("dashboard").Parse(dashboardHTML))
    tmpl.Execute(w, nil)
}

func (d *Dashboard) serveMetrics(w http.ResponseWriter, r *http.Request) {
    metrics, err := d.GetMetrics(r.Context())
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(metrics)
}

func (d *Dashboard) serveEventStream(w http.ResponseWriter, r *http.Request) {
    // Set up SSE headers
    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")
    
    // Subscribe to events
    events, err := d.client.SubscribeEvents(r.Context())
    if err != nil {
        fmt.Fprintf(w, "data: {\"error\": \"%s\"}\n\n", err.Error())
        return
    }
    defer events.Close()
    
    // Stream events
    for {
        select {
        case event := <-events.Events():
            data, _ := json.Marshal(event)
            fmt.Fprintf(w, "data: %s\n\n", data)
            if f, ok := w.(http.Flusher); ok {
                f.Flush()
            }
            
        case <-r.Context().Done():
            return
        }
    }
}

const dashboardHTML = `
<!DOCTYPE html>
<html>
<head>
    <title>BZZZ Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
    <h1>BZZZ Cluster Dashboard</h1>
    
    <div id="status"></div>
    <div id="metrics"></div>
    <div id="events"></div>
    
    <script>
        // Fetch and display metrics
        async function updateMetrics() {
            const response = await fetch('/api/metrics');
            const metrics = await response.json();
            
            document.getElementById('status').innerHTML = 
                '<h2>Node Status</h2>' +
                '<p>Node ID: ' + metrics.node.node_id + '</p>' +
                '<p>Role: ' + metrics.node.role + '</p>' +
                '<p>Admin: ' + metrics.elections.current_admin + '</p>';
                
            document.getElementById('metrics').innerHTML = 
                '<h2>DHT Metrics</h2>' +
                '<p>Stored Items: ' + metrics.dht.stored_items + '</p>' +
                '<p>Cache Hit Rate: ' + (metrics.dht.cache_hit_rate * 100).toFixed(1) + '%</p>' +
                '<p>Connected Peers: ' + metrics.dht.connected_peers + '</p>';
        }
        
        // Set up event stream
        const eventSource = new EventSource('/api/events');
        eventSource.onmessage = function(event) {
            const data = JSON.parse(event.data);
            const eventsDiv = document.getElementById('events');
            eventsDiv.innerHTML = '<h2>Recent Events</h2>' + 
                '<p>' + data.type + ': ' + JSON.stringify(data.data) + '</p>' +
                eventsDiv.innerHTML;
        };
        
        // Update metrics every 10 seconds
        updateMetrics();
        setInterval(updateMetrics, 10000);
    </script>
</body>
</html>
`

func main() {
    dashboard, err := NewDashboard("http://localhost:8080")
    if err != nil {
        panic(err)
    }
    
    http.Handle("/", dashboard)
    
    fmt.Println("Dashboard available at http://localhost:3000")
    http.ListenAndServe(":3000", nil)
}
```

## Language Bindings

### Python SDK

```python
# Install: pip install bzzz-sdk
import asyncio
from bzzz_sdk import BzzzClient, DecisionType

async def main():
    # Create client
    client = BzzzClient(
        endpoint="http://localhost:8080",
        role="backend_developer"
    )
    
    # Get status
    status = await client.get_status()
    print(f"Connected as {status.agent_id} ({status.role})")
    
    # Publish decision
    await client.decisions.publish_code(
        task="implement_feature",
        decision="Implemented new API endpoint",
        files_modified=["api/handlers.py", "tests/test_api.py"],
        lines_changed=120
    )
    
    # Query decisions
    decisions = await client.decisions.query_recent(
        role="backend_developer",
        limit=10
    )
    
    for decision in decisions:
        print(f"Decision: {decision.task} - {decision.success}")
    
    await client.close()

if __name__ == "__main__":
    asyncio.run(main())
```

### JavaScript/Node.js SDK

```javascript
// Install: npm install bzzz-sdk
const { BzzzClient } = require('bzzz-sdk');

async function main() {
    // Create client
    const client = new BzzzClient({
        endpoint: 'http://localhost:8080',
        role: 'frontend_developer'
    });
    
    // Get status
    const status = await client.getStatus();
    console.log(`Connected as ${status.agentId} (${status.role})`);
    
    // Subscribe to events
    const events = client.subscribeEvents();
    events.on('decision_published', (decision) => {
        console.log(`New decision: ${decision.address}`);
    });
    
    // Publish architectural decision
    await client.decisions.publishArchitectural({
        task: 'redesign_ui',
        decision: 'Migrating to React with TypeScript',
        rationale: 'Better type safety and developer experience',
        alternatives: ['Vue.js', 'Angular', 'Svelte'],
        nextSteps: ['Set up build pipeline', 'Migrate components']
    });
    
    // Query decisions
    const recentDecisions = await client.decisions.queryRecent({
        role: 'frontend_developer',
        project: 'user_interface',
        limit: 5
    });
    
    recentDecisions.forEach(decision => {
        console.log(`Decision: ${decision.task} - ${decision.success}`);
    });
}

main().catch(console.error);
```

### Rust SDK

```rust
// Cargo.toml: bzzz-sdk = "2.0"
use bzzz_sdk::{BzzzClient, decisions::CodeDecision, crypto::AgeKeyPair};
use tokio;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create client
    let client = BzzzClient::new(bzzz_sdk::Config {
        endpoint: "http://localhost:8080".to_string(),
        role: "backend_developer".to_string(),
        timeout: std::time::Duration::from_secs(30),
        ..Default::default()
    }).await?;
    
    // Get status
    let status = client.get_status().await?;
    println!("Connected as {} ({})", status.agent_id, status.role);
    
    // Generate Age keys
    let keys = client.crypto().generate_keys().await?;
    println!("Generated Age key pair");
    
    // Publish code decision
    client.decisions().publish_code(CodeDecision {
        task: "optimize_performance".to_string(),
        decision: "Implemented async processing with Tokio".to_string(),
        files_modified: vec![
            "src/async_handler.rs".to_string(),
            "src/main.rs".to_string(),
        ],
        lines_changed: 180,
        test_results: Some(bzzz_sdk::decisions::TestResults {
            passed: 25,
            failed: 0,
            coverage: 92.5,
            ..Default::default()
        }),
        dependencies: vec![
            "tokio".to_string(),
            "futures".to_string(),
        ],
        ..Default::default()
    }).await?;
    
    println!("Published code decision");
    
    Ok(())
}
```

---

## Cross-References

- **Core Implementation**: `pkg/` packages in main codebase
- **HTTP API**: [API_REFERENCE.md](API_REFERENCE.md) - REST API documentation
- **User Guide**: [USER_MANUAL.md](USER_MANUAL.md) - End-user documentation
- **Developer Guide**: [DEVELOPER.md](DEVELOPER.md) - Development documentation
- **Examples**: `examples/sdk/` directory in repository

**BZZZ SDK v2.0** - Complete Software Development Kit for Phase 2B unified architecture with Age encryption and DHT storage.