Documentation
¶
Overview ¶
Package memgraph defines the core data model and storage contract for the memgraph knowledge substrate: nodes, edges, graphs, lineages, versions, freshness, and symlinks. See PRD.md for the design rationale.
memgraph itself is the persistence layer. Authentication, authorization, UI, and ingestion live in clients above this package.
Index ¶
- Constants
- Variables
- type ConflictPolicy
- type Edge
- type EdgeID
- type EdgeInput
- type EdgeResult
- type EdgeSpec
- type Graph
- type GraphConfigPatch
- type GraphID
- type GraphInput
- type GraphRef
- type KindFreq
- type LineageID
- type Node
- type NodeFilter
- type NodeID
- type NodeInput
- type NodeResult
- type NodeSpec
- type NoopWriteHandler
- type PutSubgraphInput
- type PutSubgraphOutput
- type ReadOpts
- type SchemaDescription
- type SearchBatchHit
- type SearchBatchResult
- type SearchHit
- type SearchQuery
- type Store
- type SymlinkManifest
- type TagFreq
- type TagPrefixFreq
- type TraversalResult
- type TraverseDirection
- type TraverseOpts
- type Unsubscribe
- type WriteHandler
Constants ¶
const ( // PutSubgraphMaxNodes caps the number of nodes that may be written in a // single PutSubgraph call. PutSubgraphMaxNodes = 50 // PutSubgraphMaxEdges caps the number of edges that may be written in a // single PutSubgraph call. PutSubgraphMaxEdges = 100 )
PutSubgraph bulk-write limits. Exported so adapter packages (the MCP server, downstream tenant-scoped wrappers like memorysvc) share one source of truth.
const ( // SearchBatchRRFK is the standard RRF k constant; 60 is the canonical // value from Cormack et al. (2009). SearchBatchRRFK = 60.0 // SearchBatchMaxQueries caps the number of variant queries an agent may // submit in one batch. SearchBatchMaxQueries = 8 // SearchBatchDefaultPerQueryLimit is the default per-variant Limit when // the caller does not specify one. SearchBatchDefaultPerQueryLimit = 20 // SearchBatchMaxPerQueryLimit caps each variant's Limit regardless of // what the caller asks for. SearchBatchMaxPerQueryLimit = 50 // SearchBatchDefaultTotalLimit is the default total-result cap applied // after merging across variants. SearchBatchDefaultTotalLimit = 20 // SearchBatchMaxTotalLimit caps the total returned hits regardless of // what the caller asks for. SearchBatchMaxTotalLimit = 100 )
Batch-search tuning constants. Exported so adapter packages (the MCP server, REST server, and downstream tenant-scoped wrappers like memorysvc) can share a single source of truth for limits and the Reciprocal Rank Fusion k value.
Variables ¶
var ( ErrNotFound = errors.New("memgraph: not found") ErrConflict = errors.New("memgraph: lineage has unresolved conflicts") // ErrConflictManual is returned by PutNode when a concurrent write is // detected under ConflictPolicyManual. The node was written (and is // returned alongside the error) as a sibling head; resolution requires // a follow-up PutNode that explicitly supersedes both siblings. ErrConflictManual = errors.New("memgraph: concurrent write under manual conflict policy; conflict recorded") ErrKindNotAllowed = errors.New("memgraph: kind not in graph whitelist") ErrInvalidInput = errors.New("memgraph: invalid input") ErrNotImplemented = errors.New("memgraph: not implemented") )
Functions ¶
This section is empty.
Types ¶
type ConflictPolicy ¶
type ConflictPolicy string
ConflictPolicy controls how concurrent writes to the same lineage are resolved within a graph.
const ( ConflictPolicyLWW ConflictPolicy = "lww" ConflictPolicyManual ConflictPolicy = "manual" )
type Edge ¶
type Edge struct {
ID EdgeID
GraphID GraphID
FromLineage LineageID
ToGraph GraphID
ToLineage LineageID
Kind string
Metadata map[string]any
Ordinal *int
CreatedAt time.Time
CreatedBy string
}
Edge is a directed, typed relationship between two lineages. If ToGraph differs from GraphID, the edge is a symlink across graph boundaries.
type EdgeInput ¶
type EdgeInput struct {
GraphID GraphID
FromLineage LineageID
ToGraph GraphID
ToLineage LineageID
Kind string
Metadata map[string]any
Ordinal *int
CreatedBy string
}
EdgeInput is the create payload for an edge. If ToGraph is empty it defaults to GraphID (intra-graph edge).
type EdgeResult ¶ added in v0.5.0
type EdgeResult struct {
EdgeID string `json:"edge_id,omitempty"`
Error string `json:"error,omitempty"`
}
EdgeResult is the per-item outcome for one EdgeSpec.
type EdgeSpec ¶ added in v0.5.0
type EdgeSpec struct {
// FromRef refers to a node earlier in this batch by Ref.
FromRef string `json:"from_ref,omitempty"`
// FromLineage refers to an existing lineage by id.
FromLineage string `json:"from_lineage,omitempty"`
// ToRef refers to a node earlier in this batch by Ref.
ToRef string `json:"to_ref,omitempty"`
// ToLineage refers to an existing lineage by id.
ToLineage string `json:"to_lineage,omitempty"`
// ToGraph optionally pins a cross-graph symlink target; defaults to the
// batch's GraphID.
ToGraph string `json:"to_graph,omitempty"`
// Standard edge fields (mirror EdgeInput).
Kind string `json:"kind"`
Metadata map[string]any `json:"metadata,omitempty"`
Ordinal *int `json:"ordinal,omitempty"`
CreatedBy string `json:"created_by,omitempty"`
}
EdgeSpec is one edge in a PutSubgraph batch. Each endpoint is identified by EITHER a per-call ref (resolved against nodes earlier in this batch) OR an existing lineage_id. Providing both on the same side is an error and that edge will fail with a per-item error message.
type Graph ¶
type Graph struct {
ID GraphID
Name string
ConflictPolicy ConflictPolicy
KindWhitelist []string
Metadata map[string]any
CreatedAt time.Time
}
Graph is the unit of isolation. A deployment hosts N graphs.
type GraphConfigPatch ¶
type GraphConfigPatch struct {
Name *string
ConflictPolicy *ConflictPolicy
KindWhitelist []string
Metadata map[string]any
}
GraphConfigPatch updates mutable graph configuration. Nil pointers leave the field unchanged; explicit empty slices/maps clear the value.
type GraphInput ¶
type GraphInput struct {
Name string
ConflictPolicy ConflictPolicy
KindWhitelist []string
Metadata map[string]any
}
GraphInput is the create payload for a new Graph. Empty ConflictPolicy defaults to ConflictPolicyLWW.
type KindFreq ¶ added in v0.3.0
type KindFreq struct {
Kind string `json:"kind"`
Count int `json:"count"`
Examples []string `json:"examples,omitempty"` // up to 3 short summaries
}
KindFreq is a kind label with the number of current-version nodes using it and up to three example summaries to hint at the kind's semantic role.
type Node ¶
type Node struct {
ID NodeID
GraphID GraphID
LineageID LineageID
Version int
Kind string
Content string
Summary string // optional; clients fall back to Content if empty
Tags []string
Metadata map[string]any
FreshnessAt *time.Time
CreatedAt time.Time
CreatedBy string // opaque provenance; memgraph never interprets
SupersededBy *NodeID
// Conflicts lists sibling versions of this node that are not superseded
// by anyone. Empty in the normal case. Populated when a lineage has
// multiple concurrent heads under ConflictPolicyManual; the head with
// the highest version is returned with the other heads listed here.
Conflicts []NodeID
}
Node is an atomic, immutable, versioned unit of information. Nodes are minimal containers — clients define their own ontology via Kind, Tags, and Metadata.
type NodeFilter ¶
type NodeFilter struct {
Kinds []string
Tags []string
Limit int
Offset int
// Compact requests a sparse projection: callers that only need to render
// a graph view (canvas labels, colors, shape, filters) can skip the heavy
// fields. When true, the Store returns Nodes with Content, Metadata,
// FreshnessAt, CreatedBy, SupersededBy, and Conflicts cleared. The
// remaining fields (ID, GraphID, LineageID, Version, Kind, Summary, Tags,
// CreatedAt) plus the computed is_current / is_stale flags downstream
// adapters expose are enough to draw the graph. Default false preserves
// the v0.5 behavior.
Compact bool
}
NodeFilter narrows a ListNodes query.
type NodeInput ¶
type NodeInput struct {
GraphID GraphID
LineageID LineageID
Kind string
Content string
Summary string
Tags []string
Metadata map[string]any
FreshnessAt *time.Time
CreatedBy string
// BasedOnVersion is an optional optimistic-concurrency hint. If nil,
// the put follows last-writer-wins semantics: the new version supersedes
// whatever the current head is. If non-nil and the current head version
// matches *BasedOnVersion, the put is non-conflicting. If non-nil and
// the current head is ahead of *BasedOnVersion, the put is a concurrent
// write — behavior then depends on the graph's ConflictPolicy.
BasedOnVersion *int
}
NodeInput is the put payload. Omit LineageID to create a new lineage; supply an existing LineageID to append a new version.
type NodeResult ¶ added in v0.5.0
type NodeResult struct {
Ref string `json:"ref,omitempty"`
LineageID string `json:"lineage_id,omitempty"`
Version int `json:"version,omitempty"`
Created bool `json:"created"`
Error string `json:"error,omitempty"`
}
NodeResult is the per-item outcome for one NodeSpec. Ref echoes the input ref (if any). LineageID and Version are populated on success. Created is true when a new lineage was started; false when an existing lineage gained a new version. Error, when non-empty, describes why this specific item failed; subsequent edges referencing this Ref will also fail.
type NodeSpec ¶ added in v0.5.0
type NodeSpec struct {
// Ref is an opaque, per-call identifier. Edges in the same batch can
// target this node via from_ref / to_ref before its lineage_id has been
// assigned. Optional; only meaningful inside a single PutSubgraph call.
Ref string `json:"ref,omitempty"`
// LineageID, if set, makes this an UPDATE on an existing lineage.
// If empty, a new lineage is created.
LineageID string `json:"lineage_id,omitempty"`
// BasedOnVersion is the optimistic-concurrency hint passed to PutNode
// when LineageID is set. Ignored on creates.
BasedOnVersion *int `json:"based_on_version,omitempty"`
// Standard node fields (mirror NodeInput).
Kind string `json:"kind"`
Content string `json:"content"`
Summary string `json:"summary,omitempty"`
Tags []string `json:"tags,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
FreshnessAt *time.Time `json:"freshness_at,omitempty"`
CreatedBy string `json:"created_by,omitempty"`
}
NodeSpec is one node in a PutSubgraph batch. A node is an UPDATE (new version on an existing lineage) when LineageID is non-empty; otherwise it is a CREATE (new lineage). The optional Ref is a per-call symbol other nodes' edges can target before any lineage_id is known.
type NoopWriteHandler ¶
type NoopWriteHandler struct{}
NoopWriteHandler embeds zero-value methods for WriteHandler so types that only care about a subset of write events can compose it instead of having to implement every method.
func (NoopWriteHandler) OnEdgeWritten ¶
func (NoopWriteHandler) OnEdgeWritten(context.Context, Edge)
func (NoopWriteHandler) OnGraphCreated ¶
func (NoopWriteHandler) OnGraphCreated(context.Context, Graph)
func (NoopWriteHandler) OnNodeWritten ¶
func (NoopWriteHandler) OnNodeWritten(context.Context, Node)
type PutSubgraphInput ¶ added in v0.5.0
type PutSubgraphInput struct {
GraphID GraphID `json:"graph_id"`
Nodes []NodeSpec `json:"nodes,omitempty"`
Edges []EdgeSpec `json:"edges,omitempty"`
}
PutSubgraphInput is the payload accepted by PutSubgraph. At least one of Nodes or Edges must be non-empty. Limits: PutSubgraphMaxNodes nodes and PutSubgraphMaxEdges edges per call.
type PutSubgraphOutput ¶ added in v0.5.0
type PutSubgraphOutput struct {
Nodes []NodeResult `json:"nodes"`
Edges []EdgeResult `json:"edges"`
}
PutSubgraphOutput is the best-effort response: one NodeResult per input node (in input order) and one EdgeResult per input edge (in input order).
func PutSubgraph ¶ added in v0.5.0
func PutSubgraph(ctx context.Context, store Store, graphID GraphID, in PutSubgraphInput) (PutSubgraphOutput, error)
PutSubgraph writes a batch of nodes and edges in two passes against an existing Store, exposing per-item results so callers can retry only the failures. Semantics:
Pass 1 walks Nodes in order. Each NodeSpec is dispatched to Store.PutNode. Successful results with a Ref are recorded so edges in pass 2 can resolve from_ref/to_ref. Failures populate NodeResult.Error and the ref (if any) is NOT recorded.
Pass 2 walks Edges in order. Each EdgeSpec is validated locally — exactly one of from_ref / from_lineage and exactly one of to_ref / to_lineage must be set; refs must resolve against pass-1 results. Valid edges are dispatched to Store.PutEdge; failures populate EdgeResult.Error.
The batch is best-effort: no transaction wraps the underlying primitives, so partial success is the norm. Validation of the overall shape (graph_id present, nodes ≤ PutSubgraphMaxNodes, edges ≤ PutSubgraphMaxEdges, at least one of either) is performed up front and returned as a single error before any writes occur.
PutSubgraph returns (PutSubgraphOutput, nil) once any writes are attempted; per-item errors are inside the result, never the outer error. The only returned error case is shape validation.
type SchemaDescription ¶ added in v0.3.0
type SchemaDescription struct {
GraphID GraphID `json:"graph_id"`
NodeCount int `json:"node_count"`
Kinds []KindFreq `json:"kinds"`
TagPrefixes []TagPrefixFreq `json:"tag_prefixes"`
Tags []TagFreq `json:"tags"`
}
SchemaDescription summarizes the kind and tag vocabulary currently in use within a graph. It is intended as a one-shot snapshot an agent can fetch at session start to learn the user's existing conventions and avoid inventing parallel ones.
type SearchBatchHit ¶ added in v0.4.0
SearchBatchHit is one element of an RRF-fused, deduped batch-search result. Score is the summed Reciprocal Rank Fusion score across the queries that surfaced this lineage; QueriesMatched lists the input-query indexes that contributed.
type SearchBatchResult ¶ added in v0.4.0
type SearchBatchResult struct {
// Hits is the merged, deduped, top-limit slice ranked by RRFScore.
Hits []SearchBatchHit
// QueryCount is len(input queries).
QueryCount int
// UniqueHits is the count of distinct lineages observed across all
// queries, before the total-limit truncation is applied.
UniqueHits int
// PerQueryHits[i] is the number of hits returned by input query i.
PerQueryHits []int
}
SearchBatchResult is the full output of a batch-search fan-out.
func BatchSearch ¶ added in v0.4.0
func BatchSearch(ctx context.Context, store Store, graphID GraphID, queries []SearchQuery, totalLimit int) (SearchBatchResult, error)
BatchSearch fans the given queries out against store in parallel, merges results via Reciprocal Rank Fusion (k = SearchBatchRRFK), dedupes by LineageID, and truncates to totalLimit. The caller (typically an MCP or REST handler) supplies the variants — BatchSearch never invokes an LLM.
Semantics:
- queries must have between 1 and SearchBatchMaxQueries entries.
- Each query's Limit is clamped to [1, SearchBatchMaxPerQueryLimit] with a default of SearchBatchDefaultPerQueryLimit when ≤ 0.
- totalLimit is clamped to [1, SearchBatchMaxTotalLimit] with a default of SearchBatchDefaultTotalLimit when ≤ 0.
- Score(d) = sum over each query i where d appears at 1-based rank r: 1 / (SearchBatchRRFK + r).
- Ties broken by first-appearance order (deterministic across runs).
Errors from any underlying Search call abort the batch and propagate.
type SearchQuery ¶
SearchQuery is the search request payload. Search is graph-scoped; cross-graph search is a client orchestration concern.
type Store ¶
type Store interface {
CreateGraph(ctx context.Context, in GraphInput) (Graph, error)
GetGraph(ctx context.Context, id GraphID) (Graph, error)
ListGraphs(ctx context.Context) ([]Graph, error)
UpdateGraphConfig(ctx context.Context, id GraphID, patch GraphConfigPatch) (Graph, error)
// PutNode writes a new version. If in.LineageID is empty, a new lineage
// is started at version 1. Otherwise, the lineage gains a new version.
PutNode(ctx context.Context, in NodeInput) (Node, error)
// GetNodeByLineage returns the current version of a lineage by default.
// ReadOpts may pin to a specific version or point-in-time.
GetNodeByLineage(ctx context.Context, id LineageID, opts ReadOpts) (Node, error)
// GetNodeByID returns a specific node version exactly as written.
GetNodeByID(ctx context.Context, id NodeID) (Node, error)
// History returns all versions of a lineage, newest first.
History(ctx context.Context, id LineageID) ([]Node, error)
// ListNodes is a low-cardinality enumeration; for ranked/scored queries
// use Search.
ListNodes(ctx context.Context, graphID GraphID, f NodeFilter) ([]Node, error)
PutEdge(ctx context.Context, in EdgeInput) (Edge, error)
DeleteEdge(ctx context.Context, id EdgeID) error
Outgoing(ctx context.Context, from LineageID, opts TraverseOpts) ([]Edge, error)
Incoming(ctx context.Context, to LineageID, opts TraverseOpts) ([]Edge, error)
Traverse(ctx context.Context, from LineageID, opts TraverseOpts) (TraversalResult, error)
Search(ctx context.Context, graphID GraphID, q SearchQuery) ([]SearchHit, error)
SymlinkManifest(ctx context.Context, graphID GraphID) (SymlinkManifest, error)
// DescribeSchema returns the kind/tag distribution for a graph,
// useful for an agent to learn what vocabulary exists before writing.
DescribeSchema(ctx context.Context, graphID GraphID) (SchemaDescription, error)
// ListTags returns tags matching prefix (or all tags if prefix is empty),
// sorted by usage frequency descending. limit caps the result at 100 max.
ListTags(ctx context.Context, graphID GraphID, prefix string, limit int) ([]TagFreq, error)
Subscribe(h WriteHandler) (Unsubscribe, error)
// Close releases any resources held by the store.
Close() error
}
Store is the contract every storage backend must satisfy. memgraph's reference implementations (SQLite, Postgres) live in subpackages of store/. Third parties may implement Store against any backend.
All methods are expected to be safe for concurrent use.
type SymlinkManifest ¶
SymlinkManifest summarizes a graph's cross-graph references.
type TagPrefixFreq ¶ added in v0.3.0
type TagPrefixFreq struct {
Prefix string `json:"prefix"` // e.g. "protein"
Count int `json:"count"` // total node-tag uses with this prefix
Values []string `json:"values"` // up to 10 distinct values
}
TagPrefixFreq groups together tags sharing a "prefix:value" namespace. Count is the total number of node-tag uses with this prefix; Values is up to ten distinct trailing values seen.
type TraversalResult ¶
TraversalResult is the materialized output of a traversal.
type TraverseDirection ¶ added in v0.2.0
type TraverseDirection string
TraverseDirection controls which way edges are followed during a traversal. "" defaults to outgoing for backward compatibility.
const ( TraverseOutgoing TraverseDirection = "outgoing" TraverseIncoming TraverseDirection = "incoming" TraverseBoth TraverseDirection = "both" )
type TraverseOpts ¶
type TraverseOpts struct {
MaxDepth int
EdgeKinds []string
FollowSymlinks bool
MaxNodes int
// Direction controls which edges are followed. Default ("" or
// TraverseOutgoing) is outgoing-only — backward-compatible with v0.1.
Direction TraverseDirection
}
TraverseOpts controls edge walks. FollowSymlinks is opt-in — by default traversal stops at graph boundaries.
type Unsubscribe ¶
type Unsubscribe func()
Unsubscribe removes a previously registered WriteHandler.
type WriteHandler ¶
type WriteHandler interface {
OnNodeWritten(ctx context.Context, n Node)
OnEdgeWritten(ctx context.Context, e Edge)
// OnGraphCreated fires after a graph is created OR has its configuration
// updated. Implementations that only care about the existence of a graph
// can treat both cases the same way; implementations that care about the
// distinction can compare g.CreatedAt against time.Now().
OnGraphCreated(ctx context.Context, g Graph)
}
WriteHandler is notified when nodes or edges are written, or when graphs are created or have their configuration updated. Used by derived indexes (e.g. the v1.1 vector index) and by transport adapters that need to keep live state in sync with the store (e.g. the MCP server's resource list).
Handlers fire AFTER the underlying write has been committed.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
memgraph
command
Command memgraph is the CLI entrypoint for the memgraph persistence layer.
|
Command memgraph is the CLI entrypoint for the memgraph persistence layer. |
|
internal
|
|
|
kbmigrate
Package kbmigrate imports a camggould/kb SQLite database into a memgraph deployment.
|
Package kbmigrate imports a camggould/kb SQLite database into a memgraph deployment. |
|
Package mcp exposes a memgraph.Store as a Model Context Protocol server.
|
Package mcp exposes a memgraph.Store as a Model Context Protocol server. |
|
store
|
|
|
postgres
Package postgres provides the Postgres reference implementation of memgraph.Store, using pgx and pg_trgm for full-text search.
|
Package postgres provides the Postgres reference implementation of memgraph.Store, using pgx and pg_trgm for full-text search. |
|
sqlite
Package sqlite provides the embedded SQLite reference implementation of memgraph.Store.
|
Package sqlite provides the embedded SQLite reference implementation of memgraph.Store. |