memgraph

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: May 23, 2026 License: MIT Imports: 8 Imported by: 0

README

memgraph

A versioned, multi-graph knowledge substrate for agents and teams. Exposed as a Model Context Protocol (MCP) server. Runs locally or in the cloud.

Status: Alpha (v0.1.0). The data model and MCP surface are stable enough to build against, but expect breaking changes before v1.0. See PRD.md for the full design and roadmap.

memgraph is an open-source agentic persistence layer. It generalizes the single-table KB pattern of camggould/kb into a real graph: first-class typed edges, versioned lineages, freshness, cross-graph symlinks, and a pluggable storage layer.

It is a persistence layer, not an application. memgraph is opinionated about the data model and agnostic about who uses it — authentication, authorization, UI, and ingestion all live in clients above this layer.

Why

LLM agents need memory that survives sessions, scales beyond a context window, and is shareable across teammates and tools. Existing options force a choice between toy local stores (no concurrency, no audit) and heavyweight graph databases (no MCP, no agent-native API, no versioning model for evolving facts). memgraph aims to be the small, sharp tool in between.

Features (v0.1.0)

  • Graphs as units of isolation — a deployment hosts N graphs; cross-graph references are first-class symlinks.
  • Versioned lineages — every node has a stable lineage_id; edits append immutable versions. Default reads always return the current version; history is preserved for audit.
  • Configurable conflict policylww (default) or manual (concurrent writes produce sibling heads that require explicit resolution). Per-graph.
  • Freshness flags — nodes carry an optional freshness_at date; reads surface is_stale so clients can warn users about decay.
  • FTS5 (SQLite) and pg_trgm (Postgres) search — graph-scoped, ranked, with snippet output.
  • MCP server with 10 tools and memgraph:// resources; live resources/list_changed notifications when graphs are created.
  • memgraph migrate kb — idempotent migration from a camggould/kb SQLite database.
  • Two reference storage backendsSQLiteStore (cgo-free, single-binary, local) and PostgresStore (cloud, multi-process). Pluggable: implement memgraph.Store against any backend.

Install

One-line install (macOS, Linux)
curl -fsSL https://raw.githubusercontent.com/camggould/memgraph/main/install.sh | sh

Downloads the latest release from GitHub, verifies the SHA-256 checksum, and installs memgraph to /usr/local/bin (falling back to $HOME/.local/bin if /usr/local/bin isn't writable and sudo isn't available).

Override defaults via env vars:

# Pin to a specific version
curl -fsSL https://raw.githubusercontent.com/camggould/memgraph/main/install.sh | MEMGRAPH_VERSION=v0.1.0 sh

# Install somewhere else
curl -fsSL https://raw.githubusercontent.com/camggould/memgraph/main/install.sh | MEMGRAPH_INSTALL_DIR=$HOME/bin sh
Pre-built binaries (manual)

Tarballs and a checksums.txt are on the Releases page for darwin/linux on amd64+arm64 and windows/amd64.

go install
go install github.com/camggould/memgraph/cmd/memgraph@latest

Requires Go 1.25+. Binary lands in $(go env GOBIN) (or $GOPATH/bin); add that to your PATH.

Build from source
git clone https://github.com/camggould/memgraph.git
cd memgraph
go build -o memgraph ./cmd/memgraph

The default build is fully pure-Go (no cgo). Cross-compile for any supported target:

GOOS=linux GOARCH=amd64 go build -o memgraph-linux-amd64 ./cmd/memgraph
GOOS=darwin GOARCH=arm64 go build -o memgraph-darwin-arm64 ./cmd/memgraph
GOOS=windows GOARCH=amd64 go build -o memgraph-windows-amd64.exe ./cmd/memgraph
Cutting a new release (maintainers)

The repo ships a .goreleaser.yaml. After tagging a new version on main:

git tag -a vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z
GITHUB_TOKEN=$(gh auth token) goreleaser release --clean

This produces archives + checksums for all supported targets and publishes them to GitHub Releases. The install.sh script picks up the new version automatically.

Quickstart

memgraph runs as an MCP server over stdio. The most common pattern: wire it into a Claude Code (or any MCP-compatible) client and let an agent read and write memory.

1. Initialize a store and run the server

The SQLite file is created on first run; no separate init step needed.

memgraph serve --sqlite ~/.memgraph/store.db

Press Ctrl-C to stop. The store persists across runs.

2. Wire it into an MCP client

Add memgraph to your MCP client config. The exact format depends on the client; the generic block looks like:

{
  "mcpServers": {
    "memgraph": {
      "command": "memgraph",
      "args": ["serve", "--sqlite", "/Users/you/.memgraph/store.db"]
    }
  }
}

For Claude Code specifically:

claude mcp add memgraph -- memgraph serve --sqlite ~/.memgraph/store.db
3. Have your agent use it

Once connected, the agent can call any of the MCP tools. A typical first interaction:

> Remember that I prefer tabs over spaces in Go projects.

[agent calls memgraph_create_graph(name="prefs") then memgraph_put_node(...)]

> What do I prefer for Go formatting?

[agent calls memgraph_search(graph_id="...", text="go formatting") and recalls the fact]

CLI reference

memgraph --help

Commands:
  serve         Run the memgraph MCP server
  graph         Manage graphs in a memgraph deployment
    create      Create a new graph
    list        List graphs
  migrate       Migrate data from other systems
    kb          Import a camggould/kb SQLite database
  completion    Generate shell autocompletion
  help          Help about any command
memgraph serve

Runs the MCP server on stdio.

--sqlite string   Path to SQLite store file (default "memgraph.db")
memgraph migrate kb <kb-db-path>

Imports a camggould/kb SQLite database into a memgraph SQLite store. Idempotent: re-running only migrates net-new content.

--sqlite string   Path to target memgraph SQLite store (default "memgraph.db")
--dry-run         Validate source and report what would be migrated without writing

Mapping (see PRD §11):

  • Each kb note → memgraph node with kind=fact (content=body, summary=title).
  • kb tags → memgraph Tags.
  • kb source, context, workspace, file_path, created, modified → preserved in metadata under kb_* keys.
  • kb workspaces → memgraph graphs (one per distinct value; NULL/empty → default).
  • kb links → first-class cites edges; cross-workspace links become cross-graph symlinks.

Data model in one screen

  • Node — atomic, immutable, versioned. Fields: id, lineage_id, version, kind, content, summary, tags, metadata, freshness_at, created_at, created_by, superseded_by, conflicts. Clients pick their own kind ontology.
  • Edge — directed, typed, ordered. Targets lineage_id (not version), so references survive edits. If to_graph != graph_id, the edge is a symlink across graph boundaries.
  • Graph — unit of isolation. A deployment hosts N graphs; cross-graph symlinks are explicit edges.
  • Lineage — the conceptual "thing". Multiple versions share one lineage_id. Default reads resolve to the current (non-superseded) version.

See PRD §4 for the full data model.

MCP tools

Read:

Tool Purpose
memgraph_list_graphs List all graphs with symlink-manifest counts
memgraph_get_node Fetch by node_id or lineage_id; flags is_current, is_stale
memgraph_history All versions of a lineage, newest first
memgraph_traverse BFS from a lineage, with depth/kind filters and optional symlink-follow
memgraph_search FTS over a graph; filters by kind / tag / freshness
memgraph_symlink_manifest Cross-graph reference inventory

Write:

Tool Purpose
memgraph_create_graph Create a graph with optional conflict policy / kind whitelist
memgraph_put_node Create a new lineage or append a version (optimistic via based_on_version)
memgraph_put_edge Create an intra-graph edge or cross-graph symlink
memgraph_delete_edge Remove an edge

Resources:

  • memgraph://<graph_id> — graph summary
  • memgraph://<graph_id>/<lineage_id> — current node payload

Storage backends

SQLite (default, local)

Single file, pure-Go (modernc.org/sqlite), cgo-free. Ideal for single-process / single-user deployments.

memgraph serve --sqlite ~/.memgraph/store.db
Postgres (cloud, multi-process)

For team deployments and concurrent writers. memgraph uses pgx/v5 with pg_trgm (with tsvector fallback) for full-text. Cross-process serialization is provided by SELECT ... FOR UPDATE on lineage heads inside PutNode.

The CLI doesn't yet expose Postgres directly; for now, embed memgraph as a Go library:

import (
    "github.com/camggould/memgraph/mcp"
    "github.com/camggould/memgraph/store/postgres"
)

store, err := postgres.OpenContext(ctx, "postgres://user:pw@host:5432/db")
if err != nil { /* ... */ }
defer store.Close()

if err := mcp.New(store).Serve(ctx); err != nil { /* ... */ }

A --postgres flag on memgraph serve is planned for the next release.

Custom backends

Implement memgraph.Store and you have a backend. The compile-time interface assertion (var _ memgraph.Store = (*MyStore)(nil)) catches drift. The reference SQLite and Postgres implementations are good models — both are ~1000 LoC.

Development

git clone https://github.com/camggould/memgraph.git
cd memgraph
go test -race ./...
Running Postgres tests

The Postgres tests require a reachable Postgres instance. Set MEMGRAPH_POSTGRES_DSN:

MEMGRAPH_POSTGRES_DSN='postgres://you@localhost:5432/postgres' go test ./store/postgres/

If unset, the tests fall back to libpq defaults (PGHOST, PGUSER, socket search). If neither resolves a connection, the tests t.Skip.

Quick local setup:

brew services start postgresql@16
createdb postgres
go test ./store/postgres/  # uses defaults
Layout
memgraph/
├── PRD.md                  # full product spec
├── doc.go, types.go, store.go, ids.go, errors.go   # public package
├── cmd/memgraph/           # CLI entrypoint (cobra)
├── mcp/                    # MCP server (modelcontextprotocol/go-sdk)
├── store/
│   ├── sqlite/             # local backend (modernc.org/sqlite)
│   └── postgres/           # cloud backend (pgx/v5)
└── internal/kbmigrate/     # kb -> memgraph migration

License

MIT. See LICENSE.

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

View Source
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.

View Source
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

View Source
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 EdgeID

type EdgeID string

func NewEdgeID

func NewEdgeID() EdgeID

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 GraphID

type GraphID string

func NewGraphID

func NewGraphID() GraphID

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 GraphRef

type GraphRef struct {
	GraphID   GraphID
	EdgeCount int
}

GraphRef is a reference to a graph, with a denormalized edge count.

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 LineageID

type LineageID string

func NewLineageID

func NewLineageID() LineageID

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 NodeID

type NodeID string

func NewNodeID

func NewNodeID() NodeID

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 ReadOpts

type ReadOpts struct {
	AtTime    *time.Time
	AtVersion *int
}

ReadOpts controls version selection when reading by lineage.

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

type SearchBatchHit struct {
	Node           Node
	RRFScore       float64
	QueriesMatched []int
}

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 SearchHit

type SearchHit struct {
	Node    Node
	Snippet string
	Score   float64
}

SearchHit is one ranked result of a search.

type SearchQuery

type SearchQuery struct {
	Text      string
	Kinds     []string
	Tags      []string
	FreshOnly bool
	Limit     int
}

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

type SymlinkManifest struct {
	Outbound []GraphRef
	Inbound  []GraphRef
}

SymlinkManifest summarizes a graph's cross-graph references.

type TagFreq added in v0.3.0

type TagFreq struct {
	Tag   string `json:"tag"`
	Count int    `json:"count"`
}

TagFreq is a single tag and its node-use count.

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

type TraversalResult struct {
	Nodes []Node
	Edges []Edge
}

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.

Jump to

Keyboard shortcuts

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