Skip to main content

Go Library

Membrane can run inside your Go process. The embedded facade exposes the same core model as the daemon: graph-aware capture, trust-gated graph retrieval, revision, reinforcement, and metrics.

Installation

go get github.com/BennettSchwartz/membrane

Create An Instance

cfg := membrane.DefaultConfig()
cfg.DBPath = "my-agent.db"

m, err := membrane.New(cfg)
if err != nil {
log.Fatal(err)
}

ctx := context.Background()
if err := m.Start(ctx); err != nil {
log.Fatal(err)
}
defer m.Stop()
Note

Always call m.Stop() to shut down schedulers and close the database.


Capture Memory

Use CaptureMemory for events, tool output, observations, working state, and agent turns. The response contains the primary record plus any linked records or graph edges.

capture, err := m.CaptureMemory(ctx, ingestion.CaptureMemoryRequest{
Source: "auth-agent",
SourceKind: "tool_output",
Content: map[string]any{
"tool_name": "go test",
"args": map[string]any{"packages": []string{"./pkg/auth"}},
"result": map[string]any{"exit_code": 0, "stdout": "ok ./pkg/auth"},
},
Context: map[string]any{"thread_id": "session-001"},
ReasonToRemember: "Successful auth package verification",
Summary: "Auth package tests passed",
Tags: []string{"auth", "tests"},
Scope: "project-auth",
Sensitivity: schema.SensitivityLow,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(capture.PrimaryRecord.ID)

Common Source Kinds

Source kindUse for
eventUser messages, agent replies, errors, status changes
tool_outputTool calls and structured results
observationSubject-predicate-object facts
working_stateIn-flight task state
agent_turnGeneric agent turn capture

Observation Example

_, err := m.CaptureMemory(ctx, ingestion.CaptureMemoryRequest{
Source: "auth-agent",
SourceKind: "observation",
Content: map[string]any{
"subject": "user",
"predicate": "prefers_language",
"object": "Go",
},
ReasonToRemember: "Remember user language preference",
Summary: "User prefers Go",
Tags: []string{"preference"},
Sensitivity: schema.SensitivityLow,
})

Working State Example

_, err := m.CaptureMemory(ctx, ingestion.CaptureMemoryRequest{
Source: "auth-agent",
SourceKind: "working_state",
Content: map[string]any{
"thread_id": "session-001",
"state": "executing",
"next_actions": []string{"run tests", "review output"},
"context_summary": "Refactoring auth middleware",
},
Summary: "Auth refactor in progress",
Tags: []string{"auth", "working"},
Sensitivity: schema.SensitivityLow,
})

Record Outcome

RecordOutcome updates an existing episodic record with success, failure, or partial outcome state.

updated, err := m.RecordOutcome(ctx, ingestion.IngestOutcomeRequest{
Source: "auth-agent",
TargetRecordID: capture.PrimaryRecord.ID,
OutcomeStatus: schema.OutcomeStatusSuccess,
})

Retrieve Graph Context

RetrieveGraph returns ranked root records and a bounded graph neighborhood. Every retrieval request needs a TrustContext.

graph, err := m.RetrieveGraph(ctx, &retrieval.RetrieveGraphRequest{
TaskDescriptor: "debug auth retry failures",
Trust: retrieval.NewTrustContext(
schema.SensitivityMedium,
true,
"auth-agent",
[]string{"project-auth"},
),
MemoryTypes: []schema.MemoryType{
schema.MemoryTypeEntity,
schema.MemoryTypeSemantic,
schema.MemoryTypeCompetence,
schema.MemoryTypeEpisodic,
},
RootLimit: 8,
NodeLimit: 20,
EdgeLimit: 80,
MaxHops: 1,
MinSalience: 0.2,
})
if err != nil {
log.Fatal(err)
}

for _, node := range graph.Nodes {
fmt.Printf("Found: %s (type=%s, root=%t, hop=%d)\n",
node.Record.ID,
node.Record.Type,
node.Root,
node.Hop,
)
}

Fetch a single record by ID:

record, err := m.RetrieveByID(ctx, capture.PrimaryRecord.ID, retrieval.NewTrustContext(
schema.SensitivityHigh,
true,
"auth-agent",
[]string{"project-auth"},
))

Revision Operations

Revision operations update durable knowledge with audit entries.

newRec := &schema.MemoryRecord{ /* ... */ }
superseded, err := m.Supersede(ctx, oldRecordID, newRec, "agent", "updated fact")

forkedRec := &schema.MemoryRecord{ /* ... */ }
forked, err := m.Fork(ctx, sourceID, forkedRec, "agent", "different in staging")

err = m.Retract(ctx, recordID, "agent", "no longer accurate")

mergedRec := &schema.MemoryRecord{ /* ... */ }
merged, err := m.Merge(ctx, []string{id1, id2}, mergedRec, "agent", "deduplicated")

err = m.Contest(ctx, recordID, conflictingRecordID, "agent", "conflicting evidence")

Reinforce And Penalize

err := m.Reinforce(ctx, recordID, "agent", "used successfully")
err = m.Penalize(ctx, recordID, 0.2, "agent", "not useful for this task")

Metrics

snap, err := m.GetMetrics(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Total records: %d\n", snap.TotalRecords)
fmt.Printf("Retrieval usefulness: %.2f\n", snap.RetrievalUsefulness)

Complete Example

package main

import (
"context"
"fmt"
"log"

"github.com/BennettSchwartz/membrane/pkg/ingestion"
"github.com/BennettSchwartz/membrane/pkg/membrane"
"github.com/BennettSchwartz/membrane/pkg/retrieval"
"github.com/BennettSchwartz/membrane/pkg/schema"
)

func main() {
cfg := membrane.DefaultConfig()
cfg.DBPath = "my-agent.db"

m, err := membrane.New(cfg)
if err != nil {
log.Fatal(err)
}
defer m.Stop()

ctx := context.Background()
if err := m.Start(ctx); err != nil {
log.Fatal(err)
}

capture, err := m.CaptureMemory(ctx, ingestion.CaptureMemoryRequest{
Source: "auth-agent",
SourceKind: "event",
Content: map[string]any{
"ref": "thread-1:turn-7",
"text": "Refactored auth middleware and verified package tests",
},
ReasonToRemember: "Keep auth refactor context",
Summary: "Refactored auth middleware",
Tags: []string{"auth"},
Sensitivity: schema.SensitivityLow,
})
if err != nil {
log.Fatal(err)
}

graph, err := m.RetrieveGraph(ctx, &retrieval.RetrieveGraphRequest{
TaskDescriptor: "debug auth",
Trust: retrieval.NewTrustContext(
schema.SensitivityMedium,
true,
"auth-agent",
nil,
),
MemoryTypes: []schema.MemoryType{
schema.MemoryTypeEntity,
schema.MemoryTypeSemantic,
schema.MemoryTypeEpisodic,
},
RootLimit: 5,
NodeLimit: 20,
MaxHops: 1,
})
if err != nil {
log.Fatal(err)
}

fmt.Printf("Captured %s and retrieved %d graph nodes\n",
capture.PrimaryRecord.ID,
len(graph.Nodes),
)
}