speed

Go SDK

Goroutine-safe Go SDK for building AI agents with persistent memory, local SQLite storage, cloud sync, and idiomatic context-based APIs.

go get github.com/rekall-ai/rekall-goGo 1.21+

Installation

go get github.com/rekall-ai/rekall-go

Requirements

Go 1.21 or higher is required. The SDK uses modernc.org/sqlite for pure-Go SQLite support -- no CGo required.

Client Initialization

Create an agent using functional options. All API methods accept a context.Context for cancellation and timeouts.

main.go
package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"time"
rekall "github.com/rekall-ai/rekall-go"
)
func main() {
agent, err := rekall.NewAgent(
rekall.WithAPIKey(os.Getenv("REKALL_API_KEY")),
rekall.WithAgentID("my-assistant"),
rekall.WithStoragePath("./data/rekall.db"),
rekall.WithSyncEnabled(true),
rekall.WithSyncInterval(30 * time.Second),
rekall.WithSyncStrategy(rekall.LastWriteWins),
rekall.WithBaseURL("https://api.rekall.ai/v1"), // Default
)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
if err := agent.Initialize(ctx); err != nil {
log.Fatal(err)
}
// Graceful shutdown
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
shutdownCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
if err := agent.Shutdown(shutdownCtx); err != nil {
log.Printf("shutdown error: %v", err)
}
}

Environment variables

If WithAPIKey is not called, the SDK reads from the REKALL_API_KEY environment variable automatically.

Creating Memories

Store memories locally and sync to the cloud. Use struct literals or the builder pattern for constructing inputs.

Episodic memory
memory, err := agent.Memories.Create(ctx, &rekall.MemoryCreateInput{
Type: rekall.Episodic,
Content: "User asked about quarterly revenue trends for Q3 2024.",
Context: rekall.AgentContext,
Importance: 0.8,
Metadata: map[string]interface{}{
"conversationId": "conv_abc123",
"userId": "user_456",
"tags": []string{"finance", "revenue", "Q3"},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(memory.ID) // "mem_..."
fmt.Println(memory.CreatedAt) // time.Time
fmt.Println(memory.SyncStatus) // "pending" | "synced" | "conflict"
Semantic memory with entities
memory, err := agent.Memories.Create(ctx, &rekall.MemoryCreateInput{
Type: rekall.Semantic,
Content: "Acme Corp is a Fortune 500 company headquartered in San Francisco.",
Entities: []rekall.EntityInput{
{Name: "Acme Corp", Type: "organization"},
{Name: "San Francisco", Type: "location"},
},
Relationships: []rekall.RelationshipInput{
{
Source: "Acme Corp",
Target: "San Francisco",
Type: "headquartered_in",
},
},
})
Procedural memory
memory, err := agent.Memories.Create(ctx, &rekall.MemoryCreateInput{
Type: rekall.Procedural,
Content: "Deploy to production workflow",
Steps: []rekall.Step{
{Order: 1, Instruction: "Run the test suite", Command: "go test ./..."},
{Order: 2, Instruction: "Build the binary", Command: "go build -o app ."},
{Order: 3, Instruction: "Deploy to staging", Command: "deploy --env staging"},
{Order: 4, Instruction: "Run smoke tests", Command: "go test -tags smoke ./..."},
{Order: 5, Instruction: "Promote to production", Command: "deploy --env prod"},
},
})

Searching Memories

Semantic search with optional filters. Returns scored results from local storage and/or the cloud.

Semantic search
results, err := agent.Memories.Search(ctx, &rekall.MemorySearchInput{
Query: "What do we know about the customer onboarding process?",
Type: rekall.Ptr(rekall.Procedural), // Optional filter
Context: rekall.Ptr(rekall.AgentContext),
Limit: 10,
Threshold: 0.7,
})
if err != nil {
log.Fatal(err)
}
for _, result := range results {
fmt.Printf("Content: %s
", result.Memory.Content)
fmt.Printf("Score: %.2f
", result.Score)
fmt.Printf("Source: %s
", result.Source) // "local" or "cloud"
}
Filtered search
results, err := agent.Memories.Search(ctx, &rekall.MemorySearchInput{
Query: "revenue",
Filters: &rekall.SearchFilters{
Tags: &rekall.ContainsFilter{Contains: "finance"},
CreatedAfter: rekall.Ptr(time.Date(2024, 6, 1, 0, 0, 0, 0, time.UTC)),
Importance: &rekall.RangeFilter{GTE: rekall.Ptr(0.5)},
},
Sort: rekall.SortByRelevance,
})

Entity Management

Create entities, define relationships, and query the knowledge graph.

// Create an entity
entity, err := agent.Entities.Create(ctx, &rekall.EntityCreateInput{
Name: "Acme Corp",
Type: "organization",
Attributes: map[string]interface{}{
"industry": "Technology",
"founded": 2010,
"website": "https://acme.example.com",
},
})
if err != nil {
log.Fatal(err)
}
// Create a relationship
_, err = agent.Entities.Relate(ctx, &rekall.RelateInput{
SourceID: entity.ID,
TargetID: "ent_person_456",
Type: "employs",
Attributes: map[string]interface{}{"role": "CEO", "since": "2018-01-01"},
})
// Query the knowledge graph
graph, err := agent.Entities.Graph(ctx, &rekall.GraphQueryInput{
RootID: entity.ID,
Depth: 2,
Types: []string{"employs", "headquartered_in", "acquired"},
})
for _, node := range graph.Nodes {
fmt.Printf("%s (%s)
", node.Name, node.Type)
}
for _, edge := range graph.Edges {
fmt.Printf("%s --%s--> %s
", edge.Source, edge.Type, edge.Target)
}
// List entities
entities, err := agent.Entities.List(ctx, &rekall.EntityListInput{
Type: rekall.Ptr("organization"),
Limit: 50,
})

Agent Lifecycle

Spawn child agents, send messages, and manage termination.

// Spawn a child agent
child, err := agent.Spawn(ctx, &rekall.SpawnOptions{
AgentID: "research-assistant",
Config: rekall.AgentConfig{
Model: "claude-3-opus",
SystemPrompt: "You are a research assistant...",
},
Memory: rekall.MemoryOptions{
Context: rekall.AgentContext,
InheritParent: true,
},
})
if err != nil {
log.Fatal(err)
}
// Send a message
response, err := agent.Send(ctx, child.AgentID, &rekall.Message{
Type: "task",
Payload: map[string]interface{}{
"query": "Research latest AI safety papers",
},
})
// Terminate a child
err = agent.Terminate(ctx, child.AgentID, &rekall.TerminateOptions{
PreserveMemories: true,
})
// Get agent status
status, err := agent.Status(ctx)
fmt.Printf("State: %s, Uptime: %v
", status.State, status.Uptime)
// List child agents
children, err := agent.ListChildren(ctx)

Goroutine Safety

The SDK is safe for concurrent use from multiple goroutines. All methods use internal synchronization for both local storage access and API calls.

// Safe to use from multiple goroutines
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
memory, err := agent.Memories.Create(ctx, &rekall.MemoryCreateInput{
Type: rekall.Episodic,
Content: fmt.Sprintf("Memory from goroutine %d", idx),
})
if err != nil {
log.Printf("goroutine %d error: %v", idx, err)
return
}
log.Printf("goroutine %d created memory %s", idx, memory.ID)
}(i)
}
wg.Wait()
// Concurrent searches are also safe
type searchResult struct {
results []rekall.SearchResult
err error
}
ch := make(chan searchResult, 2)
go func() {
r, err := agent.Memories.Search(ctx, &rekall.MemorySearchInput{
Query: "revenue trends",
})
ch <- searchResult{r, err}
}()
go func() {
r, err := agent.Memories.Search(ctx, &rekall.MemorySearchInput{
Query: "customer feedback",
})
ch <- searchResult{r, err}
}()
for i := 0; i < 2; i++ {
res := <-ch
if res.err != nil {
log.Printf("search error: %v", res.err)
}
}

Connection pooling

The SDK maintains an internal HTTP connection pool and a SQLite connection pool. You do not need to manage connections manually. The defaults work well for most workloads, but you can tune pool sizes with WithMaxHTTPConns and WithMaxDBConns.

Error Handling

The SDK returns typed errors that can be inspected with errors.As. All API errors include the HTTP status code, error code, and message.

import "errors"
memory, err := agent.Memories.Get(ctx, "mem_nonexistent")
if err != nil {
var notFound *rekall.NotFoundError
var rateLimit *rekall.RateLimitError
var authErr *rekall.AuthError
var apiErr *rekall.APIError
switch {
case errors.As(err, &notFound):
fmt.Printf("Resource not found: %s
", notFound.ResourceID)
case errors.As(err, &rateLimit):
fmt.Printf("Rate limited. Retry after %v
", rateLimit.RetryAfter)
time.Sleep(rateLimit.RetryAfter)
case errors.As(err, &authErr):
fmt.Println("Invalid or expired API key")
case errors.As(err, &apiErr):
fmt.Printf("API error %d: %s - %s
", apiErr.StatusCode, apiErr.Code, apiErr.Message)
default:
fmt.Printf("Unexpected error: %v
", err)
}
}
// Error types:
// *rekall.APIError - Base type for all API errors
// *rekall.AuthError - 401 invalid or expired API key
// *rekall.ForbiddenError - 403 insufficient permissions
// *rekall.NotFoundError - 404 resource not found
// *rekall.ValidationError - 422 invalid input
// *rekall.RateLimitError - 429 rate limit exceeded (includes RetryAfter)
// *rekall.ServerError - 500+ server error (auto-retried)

Struct Types

All request and response types are exported as Go structs with JSON tags.

Key types
// Memory represents a stored memory
type Memory struct {
ID string `json:"id"`
Type MemoryType `json:"type"`
Content string `json:"content"`
Context MemoryContext `json:"context"`
Importance float64 `json:"importance"`
Metadata map[string]interface{} `json:"metadata"`
Entities []Entity `json:"entities"`
Relationships []Relationship `json:"relationships"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
AccessedAt time.Time `json:"accessedAt"`
AccessCount int `json:"accessCount"`
DecayFactor float64 `json:"decayFactor"`
SyncStatus string `json:"syncStatus"`
}
// MemoryType is an enum for memory types
type MemoryType string
const (
Episodic MemoryType = "episodic"
Semantic MemoryType = "semantic"
Procedural MemoryType = "procedural"
LongTerm MemoryType = "long_term"
ShortTerm MemoryType = "short_term"
Execution MemoryType = "execution"
Preferences MemoryType = "preferences"
)
// MemoryContext determines the memory scope
type MemoryContext string
const (
AgentContext MemoryContext = "agent"
UserContext MemoryContext = "user"
HiveContext MemoryContext = "hive"
)
Entity and relationship types
type Entity struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Attributes map[string]interface{} `json:"attributes"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
type Relationship struct {
ID string `json:"id"`
SourceID string `json:"sourceId"`
TargetID string `json:"targetId"`
Type string `json:"type"`
Attributes map[string]interface{} `json:"attributes"`
CreatedAt time.Time `json:"createdAt"`
}
type SearchResult struct {
Memory Memory `json:"memory"`
Score float64 `json:"score"`
Source string `json:"source"` // "local" or "cloud"
}
// SyncStrategy for conflict resolution
type SyncStrategy string
const (
LastWriteWins SyncStrategy = "last-write-wins"
CloudWins SyncStrategy = "cloud-wins"
LocalWins SyncStrategy = "local-wins"
Manual SyncStrategy = "manual"
)

Builder Patterns

For complex queries, use the fluent builder API as an alternative to struct literals.

Search builder
results, err := agent.Memories.
Search(ctx, rekall.NewSearchBuilder().
Query("customer onboarding issues").
Type(rekall.Episodic).
Context(rekall.AgentContext).
Limit(10).
Threshold(0.7).
CreatedAfter(time.Date(2024, 6, 1, 0, 0, 0, 0, time.UTC)).
TagContains("support").
SortBy(rekall.SortByRelevance).
Build(),
)
Memory builder
memory, err := agent.Memories.
Create(ctx, rekall.NewMemoryBuilder().
Type(rekall.Episodic).
Content("User completed onboarding flow.").
Context(rekall.UserContext).
Importance(0.7).
Tag("onboarding").
Tag("success").
Meta("userId", "user_123").
Meta("step", "complete").
Build(),
)
Agent options builder
// Functional options for agent construction
agent, err := rekall.NewAgent(
rekall.WithAPIKey(apiKey),
rekall.WithAgentID("my-assistant"),
rekall.WithStoragePath("./rekall.db"),
rekall.WithSyncEnabled(true),
rekall.WithSyncInterval(30 * time.Second),
rekall.WithSyncStrategy(rekall.LastWriteWins),
rekall.WithMaxHTTPConns(20),
rekall.WithMaxDBConns(5),
rekall.WithRequestTimeout(30 * time.Second),
rekall.WithRetries(3),
rekall.WithLogger(slog.Default()),
)

Ptr helper

Use rekall.Ptr(value) to convert any value to a pointer. This is useful for optional fields in struct literals, such as Type: rekall.Ptr(rekall.Episodic).

Rekall
rekall