Go API Reference
The SochDB Go SDK is remote-first: a plain go build / go get compiles only the
remote (gRPC) and IPC clients plus the pure-Go helpers. The in-process embedded FFI engine
(and everything that depends on it) is gated behind the sochdb_embedded build tag.
- Module:
github.com/sochdb/sochdb-go - Version:
0.4.5(exported assochdb.Version) - Go version:
1.24.0 - License: Apache-2.0 (the language SDK; the core Rust engine is AGPL-3.0-or-later)
import "github.com/sochdb/sochdb-go"
func main() {
println(sochdb.Version) // "0.4.5"
}
Installation
go get github.com/sochdb/sochdb-go
The embedded engine, embedded semantic cache, and the embedded Memory System are only
compiled in when you build with the embedded tag (which additionally requires the native
libsochdb_storage library, CGO, and pkg-config):
go build -tags sochdb_embedded ./...
There is no unified Client type or Config struct that auto-selects remote vs embedded.
"Remote-first" means the non-tagged build only includes the remote/IPC clients and the pure-Go
helpers; the FFI engine is excluded unless you pass -tags sochdb_embedded. The three
connection entrypoints are distinct, explicitly named functions (below).
Connecting
There are three clients, each with its own constructor.
- gRPC (remote)
- IPC (Unix socket)
- Embedded (FFI)
The default-build path. Talks to a SochDB gRPC server.
import "github.com/sochdb/sochdb-go"
// Convenience: connect with default options to an address.
client, err := sochdb.GrpcConnect("localhost:50051")
if err != nil {
panic(err)
}
defer client.Close()
// Full options form.
client, err = sochdb.NewGrpcClient(sochdb.GrpcClientOptions{
Address: "localhost:50051",
Timeout: 30 * time.Second,
Secure: false, // see caution below
})
GrpcClientOptions defaults: Address falls back to "localhost:50051" when empty,
Timeout defaults to 30 * time.Second, and the max receive message size is 100 MiB.
Setting Secure: true returns the error "secure connections not yet implemented". Only
insecure (plaintext) credentials are available today. Do not expose a gRPC endpoint over an
untrusted network until TLS lands.
Connects to a local SochDB server process over a Unix domain socket.
import "github.com/sochdb/sochdb-go"
// Dial a socket path directly.
client, err := sochdb.Connect("/tmp/sochdb.sock")
if err != nil {
panic(err)
}
defer client.Close()
// Or point at a database directory; the SDK appends "sochdb.sock".
client, err = sochdb.ConnectToDatabase("./data")
Both return *IPCClient.
In-process, requires -tags sochdb_embedded.
import "github.com/sochdb/sochdb-go/embedded"
// Single-process, durable, WAL-backed.
db, err := embedded.Open("./data")
if err != nil {
panic(err)
}
defer db.Close()
// Multi-reader / single-writer, lock-free reads (~100ns).
db, err = embedded.OpenConcurrent("./data")
// db.IsConcurrent() reports which mode you opened.
Key-value operations
IPC client
err := client.Put([]byte("greeting"), []byte("Hello, SochDB!"))
value, err := client.Get([]byte("greeting")) // ([]byte, error)
err = client.Delete([]byte("greeting"))
// Path-based hierarchical keys.
err = client.PutPath("users/alice/name", []byte("Alice"))
name, err := client.GetPath("users/alice/name")
For prefix iteration prefer Scan, which returns all matches at once:
results, err := client.Scan("users/") // []KeyValue
for _, kv := range results {
fmt.Printf("%s = %s\n", kv.Key, kv.Value)
}
// Paged variant.
page, err := client.Query("users/", 100 /*limit*/, 0 /*offset*/)
type KeyValue struct {
Key []byte
Value []byte
}
gRPC client
// Convenience helpers (namespace-scoped, string keys).
err := client.PutKv(ctx, "default", "greeting", []byte("Hello"))
value, err := client.GetKv(ctx, "default", "greeting")
// Low-level forms.
err = client.GrpcPut([]byte("k"), []byte("v"), "default", 0 /*ttlSeconds*/)
value, found, err := client.GrpcGet([]byte("k"), "default")
err = client.GrpcDelete([]byte("k"), "default")
Embedded engine
err := db.Put([]byte("k"), []byte("v")) // auto-transaction
value, err := db.Get([]byte("k"))
err = db.Delete([]byte("k"))
Prefix scans (embedded)
ScanPrefix returns a *ScanIterator. You must call Close() — the iterator holds an
open transaction until you do.
it := db.ScanPrefix([]byte("users/"))
defer it.Close()
for {
key, val, ok := it.Next()
if !ok {
break
}
fmt.Printf("%s = %s\n", key, val)
}
if err := it.Err(); err != nil {
panic(err)
}
/Queue keys contain binary big-endian fields that may include the / byte (0x2F). Splitting a
queue key on / is unsafe; use the SDK's DecodeQueueKey (positional parsing) instead.
Transactions
Commit returns error only in the Go SDK — it does not return a commit timestamp. (A
uint64 is returned by BeginTransaction as the transaction ID, and by the embedded
Checkpoint, but not by Commit.)
IPC client
txnID, err := client.BeginTransaction() // (uint64, error)
// ... perform writes within the transaction ...
err = client.CommitTransaction(txnID) // error only
// or, on failure:
err = client.AbortTransaction(txnID)
Embedded engine
// Closure form (recommended): auto-commit on success, auto-abort on error.
err := db.WithTransaction(func(txn *embedded.Transaction) error {
// ... use txn ...
return nil
})
// Explicit form.
txn := db.Begin()
// txn.ID() uint64, txn.SnapshotTS() uint64
if err := txn.Commit(); err != nil { // error only
// A serialization failure surfaces as:
// "SSI conflict: transaction aborted due to serialization failure"
_ = txn.Abort()
}
SQL
The Go SDK has no exported SQL execution method. The OpExecuteSQL opcode is defined
internally but is not wired to any method, and IPCClient.Query() is a prefix query
(path + limit + offset), not SQL. The only Execute() in the SDK belongs to the context
builder (below) and is unrelated to SQL. For SQL, use the gRPC server with another SDK or the
SQL API.
Namespaces and collections
gRPC client
err := client.CreateCollection("docs", 384 /*dimension*/, "default" /*namespace*/)
ids, err := client.AddDocuments("docs", []sochdb.GrpcDocument{
{ID: "1", Content: "hello", Embedding: emb, Metadata: map[string]string{"k": "v"}},
}, "default")
hits, err := client.SearchCollection("docs", queryVec, 10 /*k*/, "default")
Embedded / pure-Go handles
// Namespace handle.
coll, err := ns.CreateCollection(sochdb.CollectionConfig{
Name: "docs",
Dimension: 384,
Metric: sochdb.DistanceMetricCosine, // "cosine" | "euclidean" | "dot"
Indexed: true,
})
// Other namespace ops: Collection(name), GetOrCreateCollection,
// DeleteCollection(name), ListCollections().
// Collection ops.
id, err := coll.Insert(vector, map[string]interface{}{"title": "Intro"}, "doc-1")
results, err := coll.Search(sochdb.SearchRequest{
QueryVector: queryVec,
K: 10,
IncludeMetadata: true,
})
count, err := coll.Count()
The HNSW knobs in CollectionConfig (HNSWM, HNSWEfConstruction) are stored as JSON
metadata only. The embedded Collection.Search performs a brute-force cosine similarity over a
prefix scan, sorted descending and truncated to K. Use the gRPC server for real HNSW indexing
(its CreateIndex builds an HNSW index, though the HNSW parameters are not configurable from
the Go client).
Vector indexes (gRPC)
err := client.CreateIndex("vectors", 384 /*dimension*/, "cosine")
n, err := client.InsertVectors("vectors", ids, vectors) // (int, error)
hits, err := client.GrpcSearch("vectors", queryVec, 10 /*k*/)
for _, h := range hits {
fmt.Printf("id=%d distance=%f\n", h.ID, h.Distance) // GrpcSearchResult
}
The accepted metric strings are "l2", "dot" / "dot_product", and anything else falls back
to cosine. There is no DropIndex / DeleteIndex in the Go SDK.
Memory System
The Memory System requires -tags sochdb_embedded. The shared types in memory_types.go
(Entity, Relation, Assertion, RawAssertion, CanonicalFact, etc.) always compile, but
the pipelines below do not link in without the tag.
// Extraction: compile LLM output into typed Entity / Relation / Assertion.
pipeline := sochdb.NewExtractionPipeline(db, "default", schema)
result, err := pipeline.Extract(text)
err = pipeline.ExtractAndCommit(text)
// Consolidation: merge multi-source RawAssertions into CanonicalFacts.
c := sochdb.NewConsolidator(db, "default", config)
c.Add(rawAssertion)
n, err := c.Consolidate() // (int, error)
// Retrieval: BM25 + semantic hybrid.
r := sochdb.NewHybridRetriever(db, "default", config)
err = r.IndexDocuments(docs)
resp, err := r.Retrieve("query", allowedSet)
ExtractorFunction is func(text string) (map[string]interface{}, error). A standalone
scorer is available via NewBM25Scorer(k1, b float64).
Policy and access pre-filtering
These are pure-Go types (always compiled) for tenant isolation and result pre-filtering:
// Namespace policies: Strict | Explicit | Permissive.
var p sochdb.NamespacePolicy = sochdb.NamespacePolicyStrict
// AllowedSet implementations for pre-filtering retrieval.
allowed := sochdb.NewNamespaceAllowedSet("tenant-a")
// Also: NewIdsAllowedSet, NewFilterAllowedSet, NewAllAllowedSet.
Cross-namespace access is expressed with NamespaceGrant.
Queue
The priority queue is always compiled (pure-Go over a backing store).
q := sochdb.NewPriorityQueue(db, "jobs", &sochdb.QueueConfig{
Name: "jobs",
VisibilityTimeout: 30000, // ms (default)
MaxRetries: 3, // default
DeadLetterQueue: "jobs-dlq",
})
taskID, err := q.Enqueue(10 /*priority*/, payload, metadata)
task, err := q.Dequeue("worker-1")
err = q.Ack(taskID)
err = q.Nack(taskID)
stats, err := q.Stats()
purged, err := q.Purge()
Task states: pending, claimed, completed, dead_lettered. NewPriorityQueue is also
aliased as CreateQueue.
Semantic cache
There are three implementations.
- gRPC
- IPC
- Embedded
err := client.CachePut("answers", "key", "value", keyEmbedding, 3600 /*ttlSeconds*/)
value, found, err := client.CacheGet("answers", queryEmbedding, 0.9 /*threshold*/)
err := client.CachePut(/* ... */)
value, found, err := client.CacheGet(/* ... */)
Requires -tags sochdb_embedded.
cache := sochdb.NewSemanticCache(db, "answers")
// Put / Get / Delete / Clear / Stats / PurgeExpired
Context builder
A pure-Go fluent builder for assembling token-budgeted context windows.
result, err := sochdb.NewContextQueryBuilder().
ForSession("session-123").
WithBudget(4096). // default 4096 tokens
SetFormat(sochdb.FormatTOON). // default; also FormatJSON, FormatMarkdown
SetTruncation(sochdb.TailDrop). // default; also HeadDrop, Proportional
Literal("system", 100, "You are a helpful assistant.").
Execute() // (*ContextResult, error)
TOON is the default wire/context format (documented as 40-66% fewer tokens than JSON).
Graph
- IPC
- gRPC
err := client.AddNode("default", "node-1", "person", props)
err = client.AddEdge("default", "node-1", "node-2", "knows", props)
res, err := client.Traverse("default", "node-1", 3 /*maxDepth*/, "bfs" /*order*/)
err := client.AddGraphNode(/* ... */)
err = client.AddGraphEdge(/* ... */)
nodes, edges, err := client.TraverseGraph("node-1", 3 /*maxDepth*/, "bfs", "default")
// Convenience helpers.
err = client.AddEdge(ctx, "default", edge)
results, err := client.QueryGraph(ctx, "default", "node-1", "knows", 50 /*limit*/)
Tracing
Both clients expose observability spans.
// IPC
trace, err := client.StartTrace(/* ... */)
span, err := client.StartSpan(/* ... */)
err = client.EndSpan(/* ... */)
// gRPC has the equivalent StartTrace / StartSpan / EndSpan.
The Go SDK has no "routing" / "router" subsystem. The only *Policy types are IndexPolicy
(storage layout) and NamespacePolicy (tenant isolation); neither is a query router.
Errors
The SDK exposes sentinel errors for errors.Is matching plus typed error structs.
import "errors"
if errors.Is(err, sochdb.ErrNotFound) {
// key/value not present
}
Sentinel errors
| Sentinel | Meaning |
|---|---|
ErrClosed | Operation on a closed client/database. |
ErrNotFound | Key, collection, or record not found. |
ErrInvalidResponse | Malformed response from the server. |
ErrDatabaseLocked | Database is locked by another process. |
ErrLockTimeout | Timed out acquiring a lock. |
ErrEpochMismatch | Epoch fencing mismatch. |
ErrSplitBrain | Split-brain condition detected. |
Error structs
ConnectionError (wraps the underlying error via Unwrap), ProtocolError, ServerError,
TransactionError, and SochDBError{Op, Message}.
Lock/concurrency error structs implement Is() so they match the sentinels above:
LockError, DatabaseLockedError (→ ErrDatabaseLocked), LockTimeoutError
(→ ErrLockTimeout), EpochMismatchError (→ ErrEpochMismatch), and SplitBrainError
(→ ErrSplitBrain).
Namespace/collection errors: NamespaceNotFoundError, NamespaceExistsError,
CollectionNotFoundError, CollectionExistsError. Format errors:
FormatConversionError{FromFormat, ToFormat, Reason}.