Python client library for the Membrane memory substrate.
Communicates with the Membrane daemon over gRPC using the protobuf-defined
membrane.v1.MembraneService contract.
Arbitrary content fields use google.protobuf.Value; memory records, graph
nodes, graph edges, capture responses, graph retrieval responses, and metrics
envelopes are typed protobuf messages.
pip install -e clients/pythonOr install from the project root:
pip install -e clients/python[dev] # includes pytestfrom membrane import MembraneClient, Sensitivity, SourceKind, TrustContext
# Connect to the running Membrane daemon
client = MembraneClient("localhost:9090")
# Capture a rich memory candidate
capture = client.capture_memory(
{"ref": "src/main.py", "text": "Refactored authentication module"},
source_kind=SourceKind.EVENT,
reason_to_remember="Keep the auth refactor available for future debugging",
summary="Refactored authentication module",
sensitivity=Sensitivity.LOW,
scope="default",
)
print(f"Created record: {capture.primary_record.id}")
# Retrieve memories relevant to a task
trust = TrustContext(
max_sensitivity=Sensitivity.LOW,
scopes=["default"],
)
graph = client.retrieve_graph("fix the login bug", trust=trust, root_limit=5)
for node in graph.nodes:
print(f" [{node.record.type.value}] {node.record.id} hop={node.hop}")
# Reinforce a useful memory
client.reinforce(capture.primary_record.id, actor="agent-1", rationale="Used successfully")
# Clean up
client.close()with MembraneClient("localhost:9090") as client:
capture = client.capture_memory(
{"subject": "user", "predicate": "prefers", "object": {"language": "Python"}},
source_kind=SourceKind.OBSERVATION,
sensitivity=Sensitivity.LOW,
)| Method | Description |
|---|---|
capture_memory(content, ...) |
Capture a rich memory candidate for interpretation and graph linking |
| Method | Description |
|---|---|
retrieve_graph(task_descriptor, ...) |
Retrieve a rooted graph neighborhood relevant to a task |
retrieve_by_id(record_id, ...) |
Retrieve a single record by ID |
retrieve_graph(..., query_embedding=[...]) accepts a precomputed query vector and validates it before the RPC. Non-empty vectors must be numeric, finite, and include at least one non-zero value; strings, booleans, NaN, and infinities are rejected. Graph budgets, metadata shapes, and enum fields are also validated client-side: min_salience must be finite and between 0 and 1, root_limit/node_limit/edge_limit must be integers from 0 to 10000, max_hops must be an integer no lower than -1, root_only must be boolean, memory_types must use public API memory type values, trust.max_sensitivity must use a public API sensitivity value, trust.authenticated must be boolean, trust.actor_id must be a string, and trust.scopes must be a sequence of strings. retrieve_by_id(), revision methods, reinforce(), and penalize() reject empty required record IDs before transport, while contest() still permits an empty contesting_ref for external evidence. Revision replacement records also validate semantic, entity, and relation invariants before transport; outbound semantic and entity records may use either SDK snake_case fields or Go-style JSON fields such as Subject, Predicate, Object, Validity, CanonicalName, and Identifiers. capture_memory() validates source, source_kind, proposed_type, sensitivity, reason_to_remember, summary, timestamp, scope, and tags before sending the RPC; plain strings are rejected for tags and trust.scopes to avoid accidental per-character lists.
| Method | Description |
|---|---|
supersede(old_id, new_record, actor, rationale) |
Replace a record with a new version |
fork(source_id, forked_record, actor, rationale) |
Create a conditional variant |
retract(record_id, actor, rationale) |
Soft-delete a record |
merge(record_ids, merged_record, actor, rationale) |
Merge multiple records |
contest(record_id, contesting_ref, actor, rationale) |
Mark a record as contested |
| Method | Description |
|---|---|
reinforce(record_id, actor, rationale) |
Boost a record's salience |
penalize(record_id, amount, actor, rationale) |
Reduce a record's salience |
| Method | Description |
|---|---|
get_metrics() |
Get a typed MetricsSnapshot, including pgvector coverage fields such as embedded_records, missing_embeddings, and embedding_coverage |
client = MembraneClient(
"membrane.example.com:443",
tls=True, # use TLS transport
tls_ca_cert="/path/to/ca.pem", # optional custom CA
api_key="your-api-key", # Bearer token auth
timeout=10.0, # default timeout in seconds
)The SDK refuses to attach api_key metadata to plaintext gRPC connections
unless the address is loopback. For trusted local-network development without
TLS, set allow_insecure_credentials=True explicitly on both the client and
the Membrane server configuration. When the loopback plaintext exception is
used, the SDK disables gRPC HTTP proxying so proxy environment variables cannot
move the credential-bearing connection off-host. TLS and the explicit insecure
development override retain normal proxy behavior.
- Python >= 3.10
grpcio >= 1.80.0protobuf >= 6.31.1- A running Membrane daemon (default:
localhost:9090) - Inline type metadata via
py.typedfor type checkers
pip install -e clients/python[dev]
python clients/python/scripts/check_proto_sync.py
python clients/python/scripts/check_package.py
python -m pytest clients/python/tests