membrane

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 16, 2026 License: MIT

README

Membrane

CI Go Report Card Go Reference Go Version Release

GitHub Stars GitHub Forks GitHub Issues GitHub Pull Requests Last Commit Contributors

A general-purpose selective learning and memory substrate for agentic systems.

Membrane gives long-lived agents structured, revisable memory with built-in decay, trust-gated retrieval, and audit trails. Instead of an append-only context window or flat text log, agents get typed memory records that can be consolidated, revised, contested, and pruned over time.


Table of Contents


Why Membrane

Most agent "memory" is either ephemeral (context windows that reset each turn) or an append-only text log stuffed into a RAG pipeline. That gives you retrieval, but not learning: facts get stale, procedures drift, and the system cannot revise itself safely.

Membrane makes memory selective and revisable. It captures raw experience, promotes it into structured knowledge, and lets you supersede, fork, contest, or retract that knowledge with evidence. The result is an agent that can improve over time while remaining predictable, auditable, and safe.

60-Second Mental Model

  1. Ingest events, tool outputs, observations, and working state.
  2. Consolidate episodic traces into semantic facts, competence records, and plan graphs.
  3. Retrieve in layers with trust gating and salience ranking.
  4. Revise knowledge with explicit operations and audit trails.
  5. Decay salience over time unless reinforced by success.

Key Features

  • Typed Memory -- Explicit schemas and lifecycles for each memory type, not a flat text store.
  • Revisable Knowledge -- Supersede, fork, retract, merge, and contest records with full provenance tracking.
  • Competence Learning -- Agents learn how to solve problems (procedures, success rates), not just what happened.
  • Decay and Consolidation -- Time-based salience decay keeps memory useful; background consolidation extracts durable knowledge from episodic traces.
  • Trust-Aware Retrieval -- Sensitivity levels (public, low, medium, high, hyper) with graduated access control and redacted responses for records above the caller's trust level.
  • Security and Operations -- SQLCipher encryption at rest, optional TLS and API key authentication, configurable rate limiting, full audit logs.
  • Observability -- Built-in metrics for retrieval usefulness, competence success rate, plan reuse frequency, memory growth, and revision rate.
  • gRPC API -- 15-method gRPC service with TypeScript and Python client SDKs, or use Membrane as an embedded Go library.

Memory Types

Type Purpose Example
Episodic Raw experience capture (immutable) Tool calls, errors, observations from a debugging session
Working Current task state "Backend initialized, frontend pending, docs TODO"
Semantic Stable facts and preferences "User prefers Go for backend services"
Competence Learned procedures with success tracking "To fix linker cache error: clear cache, rebuild with flags"
Plan Graph Reusable solution structures as directed graphs Multi-step project setup workflow with dependencies and checkpoints

Each memory type has its own schema, lifecycle rules, and consolidation behavior. Episodic records are immutable once ingested. Working memory tracks in-flight task state. Semantic, competence, and plan graph records are the durable output of consolidation and can be revised through explicit operations.

Quick Start

Prerequisites
  • Go 1.22 or later
  • Make
  • Protocol Buffers compiler (protoc >= 3.20) for gRPC development
  • Node.js 20+ for the TypeScript client SDK
  • Python 3.10+ for the Python client SDK
Build and Run
git clone https://github.com/GustyCube/membrane.git
cd membrane

# Build the daemon
make build

# Run tests
make test

# Start with default SQLite storage
./bin/membraned

# With custom configuration
./bin/membraned --config /path/to/config.yaml

# Override database path or listen address
./bin/membraned --db /path/to/membrane.db --addr :8080
Using the Go Library

Membrane can be used as an embedded library without running the daemon:

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/GustyCube/membrane/pkg/ingestion"
    "github.com/GustyCube/membrane/pkg/membrane"
    "github.com/GustyCube/membrane/pkg/retrieval"
    "github.com/GustyCube/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()
    m.Start(ctx)

    // Ingest an episodic event (tool call observation)
    rec, _ := m.IngestEvent(ctx, ingestion.IngestEventRequest{
        Source:    "build-agent",
        EventKind: "tool_call",
        Ref:       "build#42",
        Summary:   "Executed go build, failed with linker error",
        Tags:      []string{"build", "error"},
    })
    fmt.Printf("Ingested episodic record: %s\n", rec.ID)

    // Ingest a semantic observation
    m.IngestObservation(ctx, ingestion.IngestObservationRequest{
        Source:    "build-agent",
        Subject:   "user",
        Predicate: "prefers_language",
        Object:    "go",
        Tags:      []string{"preferences"},
    })

    // Ingest working memory state
    m.IngestWorkingState(ctx, ingestion.IngestWorkingStateRequest{
        Source:     "build-agent",
        ThreadID:   "session-001",
        State:      schema.TaskStateExecuting,
        NextActions: []string{"run tests", "deploy"},
    })

    // Retrieve with trust context
    resp, _ := m.Retrieve(ctx, &retrieval.RetrieveRequest{
        TaskDescriptor: "fix build error",
        Trust: &retrieval.TrustContext{
            MaxSensitivity: schema.SensitivityMedium,
            Authenticated:  true,
        },
        MemoryTypes: []schema.MemoryType{
            schema.MemoryTypeCompetence,
            schema.MemoryTypeSemantic,
        },
    })

    for _, r := range resp.Records {
        fmt.Printf("Found: %s (type=%s, confidence=%.2f)\n", r.ID, r.Type, r.Confidence)
    }
}

Architecture

Membrane runs as a long-lived daemon or embedded library. The architecture is organized into three logical planes:

+------------------+     +------------------+     +----------------------+
|  Ingestion Plane |---->|   Policy Plane   |---->| Storage & Retrieval  |
+------------------+     +------------------+     +----------------------+
        |                        |                         |
   Events, tool            Classification,            SQLCipher (encrypted),
   outputs, obs.,          sensitivity,               audit trails,
   working state           decay profiles             trust-gated access
Storage Model
  • Authoritative Store -- SQLCipher-encrypted SQLite database for metadata, lifecycle state, revision chains, relations, and audit history.
  • Structured Payloads -- Type-specific schemas stored as JSON within the authoritative store.
  • Relationship Graph -- Relations between records (supersedes, derived_from, contested_by, supports, contradicts) stored alongside the records they describe.
Background Jobs
Job Default Interval Purpose
Decay 1 hour Applies time-based salience decay using exponential or linear curves
Pruning With decay Deletes records with auto_prune policy whose salience has reached 0
Consolidation 6 hours Extracts semantic facts, competence records, and plan graphs from episodic memory
Security Model
  • Encryption at Rest -- SQLCipher with PRAGMA key applied at database open.
  • TLS Transport -- Optional TLS for gRPC connections.
  • Authentication -- Bearer token API key via authorization metadata.
  • Rate Limiting -- Token bucket limiter with configurable requests per second.
  • Trust-Aware Retrieval -- Records filtered by sensitivity level. Records one level above the caller's threshold are returned in redacted form (metadata only, no payload).
  • Input Validation -- Payload size limits, string length checks, tag count limits, NaN/Inf rejection.

Configuration

Membrane is configured via a YAML file or command-line flags. Secrets should come from environment variables.

db_path: "membrane.db"
listen_addr: ":9090"
decay_interval: "1h"
consolidation_interval: "6h"
default_sensitivity: "low"
selection_confidence_threshold: 0.7

# Security (prefer environment variables for keys)
# encryption_key: ""       # or set MEMBRANE_ENCRYPTION_KEY
# api_key: ""              # or set MEMBRANE_API_KEY
# tls_cert_file: ""
# tls_key_file: ""
rate_limit_per_second: 100
Variable Purpose
MEMBRANE_ENCRYPTION_KEY SQLCipher encryption key for the database
MEMBRANE_API_KEY Bearer token for gRPC authentication

gRPC API

The gRPC API uses protoc-generated service stubs with JSON-encoded payloads over protobuf bytes fields.

Method Description
IngestEvent Create episodic record from an event
IngestToolOutput Create episodic record from a tool invocation
IngestObservation Create semantic record from an observation
IngestOutcome Update episodic record with outcome data
IngestWorkingState Create working memory record
Retrieve Layered retrieval with trust context
RetrieveByID Fetch single record by ID
Supersede Replace a record with a new version
Fork Create conditional variant of a record
Retract Mark a record as retracted
Merge Combine multiple records into one
Contest Mark a record as contested by conflicting evidence
Reinforce Boost a record's salience
Penalize Reduce a record's salience
GetMetrics Retrieve observability metrics snapshot

Revision Operations

Membrane provides five revision operations, each producing an audit trail and updating the record's revision status:

// Supersede a semantic record with a new version
superseded, _ := m.Supersede(ctx, oldRecordID, newRec, "agent", "Go version updated")

// Fork a record for conditional validity
forked, _ := m.Fork(ctx, sourceID, conditionalRec, "agent", "different for dev environment")

// Contest a record when conflicting evidence appears
m.Contest(ctx, recordID, conflictingRecordID, "agent", "new evidence contradicts this")

// Retract a record that is no longer valid
m.Retract(ctx, recordID, "agent", "no longer accurate")

// Merge multiple records into one consolidated record
merged, _ := m.Merge(ctx, []string{id1, id2, id3}, mergedRec, "agent", "consolidating duplicates")

Evaluation and Metrics

Membrane exposes behavioral metrics (retrieval usefulness, competence success rate, plan reuse frequency) via GetMetrics, and the test suite covers ingestion, revision, selection, and retrieval ordering.

Recall Regression Checks
go test ./tests -run TestRetrievalRecallAtK
Vector-Aware End-to-End Metrics

Optional; requires Python dependencies:

python3 -m pip install -r tools/eval/requirements.txt
make eval

Thresholds are enforced by default (override via environment variables):

MEMBRANE_EVAL_MIN_RECALL=0.90
MEMBRANE_EVAL_MIN_PRECISION=0.20
MEMBRANE_EVAL_MIN_MRR=0.90
MEMBRANE_EVAL_MIN_NDCG=0.90
Targeted Capability Evals
make eval-typed          # Memory type handling
make eval-revision       # Revision semantics
make eval-decay          # Decay curves and pruning
make eval-trust          # Trust-gated retrieval
make eval-competence     # Competence learning
make eval-plan           # Plan graph operations
make eval-consolidation  # Episodic consolidation
make eval-metrics        # Observability metrics
make eval-invariants     # System invariants
make eval-grpc           # gRPC endpoint coverage

make eval-all            # Run everything
Latest Results

Local run (Feb 5, 2026):

  • Unit/Integration: 22 top-level eval tests + 7 subtests = 29 test cases, 0 failures (~0.40s)
  • Vector E2E: 35 records, 18 queries -- recall@k 1.000, precision@k 0.267, MRR@k 0.956, NDCG@k 0.955

Note: Membrane itself does not implement vector similarity search. End-to-end recall depends on the retrieval backend and the agent policy driving ingestion and reinforcement. Treat recall tests as scenario-level regression guards rather than universal benchmarks.

Observability

The GetMetrics endpoint returns a point-in-time snapshot:

{
  "total_records": 142,
  "records_by_type": {
    "episodic": 80,
    "semantic": 35,
    "competence": 15,
    "plan_graph": 7,
    "working": 5
  },
  "avg_salience": 0.62,
  "avg_confidence": 0.78,
  "salience_distribution": {
    "0.0-0.2": 12,
    "0.2-0.4": 18,
    "0.4-0.6": 30,
    "0.6-0.8": 45,
    "0.8-1.0": 37
  },
  "active_records": 130,
  "pinned_records": 3,
  "total_audit_entries": 890,
  "memory_growth_rate": 0.15,
  "retrieval_usefulness": 0.42,
  "competence_success_rate": 0.85,
  "plan_reuse_frequency": 2.3,
  "revision_rate": 0.08
}
Metric Description
memory_growth_rate Fraction of records created in the last 24 hours
retrieval_usefulness Ratio of reinforce actions to total audit entries
competence_success_rate Average success rate across competence records
plan_reuse_frequency Average execution count across plan graph records
revision_rate Fraction of audit entries that are revisions (supersede, fork, merge)

TypeScript Client

Install the TypeScript client SDK:

npm install @gustycube/membrane
import { MembraneClient, Sensitivity } from "@gustycube/membrane";

const client = new MembraneClient("localhost:9090", { apiKey: "your-key" });

// Ingest an event
const record = await client.ingestEvent("tool_call", "task#1", {
  summary: "Ran database migration successfully",
  tags: ["db", "migration"]
});

// Retrieve with trust context
const results = await client.retrieve("database operations", {
  trust: {
    max_sensitivity: Sensitivity.MEDIUM,
    authenticated: true,
    actor_id: "ts-agent",
    scopes: []
  },
  memoryTypes: ["semantic", "competence"]
});

client.close();

See clients/typescript/README.md for the full API reference.

Python Client

Install the Python client SDK:

pip install -e clients/python
from membrane import MembraneClient, Sensitivity, TrustContext

client = MembraneClient("localhost:9090", api_key="your-key")

# Ingest an event
record = client.ingest_event(
    source="my-agent",
    event_kind="tool_call",
    ref="task#1",
    summary="Ran database migration successfully",
    tags=["db", "migration"],
)

# Retrieve with trust context
results = client.retrieve(
    task_descriptor="database operations",
    trust=TrustContext(max_sensitivity=Sensitivity.MEDIUM, authenticated=True),
    memory_types=["semantic", "competence"],
)

See clients/python/README.md for the full API reference.

Documentation

Full documentation is available in the docs/ directory, built with VitePress:

cd docs
npm install
npm run dev

Topics covered:

  • Memory type schemas and lifecycle rules
  • Revision semantics and conflict resolution
  • Trust and sensitivity model
  • API reference
  • Deployment guide

Contributing

Contributions are welcome. See CONTRIBUTING.md for guidelines on code style, testing requirements, the pull request process, and SDK sync procedures.

Star History

Star History Chart

License

Membrane is released under the MIT License.


Author: Bennett Schwartz | Repository: github.com/GustyCube/membrane

Directories

Path Synopsis
api
grpc
Package grpc provides the gRPC transport layer for the Membrane service.
Package grpc provides the gRPC transport layer for the Membrane service.
cmd
membrane-eval command
membraned command
pkg
consolidation
Package consolidation analyzes episodic and working memory to extract durable knowledge.
Package consolidation analyzes episodic and working memory to extract durable knowledge.
decay
Package decay implements salience decay, reinforcement, and scheduling as specified in RFC 15A.7.
Package decay implements salience decay, reinforcement, and scheduling as specified in RFC 15A.7.
ingestion
Package ingestion provides the ingestion layer for the Membrane memory substrate.
Package ingestion provides the ingestion layer for the Membrane memory substrate.
membrane
Package membrane provides the top-level API surface that wires together all subsystems of the memory substrate: ingestion, retrieval, decay, revision, consolidation, and metrics.
Package membrane provides the top-level API surface that wires together all subsystems of the memory substrate: ingestion, retrieval, decay, revision, consolidation, and metrics.
metrics
Package metrics collects observability metrics from the memory substrate.
Package metrics collects observability metrics from the memory substrate.
retrieval
Package retrieval implements the layered memory retrieval service as specified in RFC 15.8 and RFC 15A.11.
Package retrieval implements the layered memory retrieval service as specified in RFC 15.8 and RFC 15A.11.
revision
Package revision implements the revision layer for the Membrane memory substrate.
Package revision implements the revision layer for the Membrane memory substrate.
schema
Package schema defines the core data structures for the memory substrate as specified in RFC 15A (Schema Appendix).
Package schema defines the core data structures for the memory substrate as specified in RFC 15A (Schema Appendix).
storage
Package storage defines the Store interface that all storage backends must implement.
Package storage defines the Store interface that all storage backends must implement.
storage/sqlite
Package sqlite implements the storage.Store interface using SQLite via github.com/mattn/go-sqlite3.
Package sqlite implements the storage.Store interface using SQLite via github.com/mattn/go-sqlite3.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL