Skip to content

API stability

Starting with v0.1.0, GrayMatter follows a best-effort compatibility policy for the identifiers listed below:

  • No removals or signature changes within the v0.x series without a deprecation notice in the prior minor release.
  • Struct fields listed as stable will not be removed; new fields may be added.
  • Store internals (unexported fields, internal packages) are not covered — do not embed Store or depend on unexported symbols.
  • When v1.0.0 is released, full semver guarantees apply.

github.com/angelnicolasc/graymatter (root package)

Section titled “github.com/angelnicolasc/graymatter (root package)”
Identifier Notes
New(dataDir string) *Memory
NewWithConfig(cfg Config) (*Memory, error)
(*Memory).Remember(ctx context.Context, agentID, text string) error
(*Memory).Recall(ctx context.Context, agentID, query string) ([]string, error)
(*Memory).Consolidate(ctx context.Context, agentID string) error
(*Memory).RememberShared(ctx context.Context, text string) error
(*Memory).RecallShared(ctx context.Context, query string) ([]string, error)
(*Memory).RecallAll(ctx context.Context, agentID, query string) ([]string, error)
(*Memory).Close() error
(*Memory).Advanced() AdvancedStore Narrow handle for CRUD, listing, raw bbolt access
(*Memory).Config() Config
(*Memory).RememberWithOptions, RememberSharedWithOptions Added in v0.20.0. Accept context.Context and memory.WriteOptions, return the exact committed memory.Fact; normal writes retain automatic consolidation policy
(*Memory).RecallWithOptions, RecallExplainWithOptions, RecallSharedWithOptions, RecallAllWithOptions Added in v0.20.0. Accept context.Context and memory.RecallOptions; configured TopK applies
Config struct — all fields present in v0.1.0 New fields may be added
DefaultConfig() Config
EmbeddingMode type and constants

github.com/angelnicolasc/graymatter/pkg/memory

Section titled “github.com/angelnicolasc/graymatter/pkg/memory”
Identifier Notes
Open(cfg StoreConfig) (*Store, error)
(*Store).Put(ctx, agentID, text string) error
(*Store).PutReturningFact(ctx, agentID, text string) (Fact, error) Added after v0.18.0. Concrete Store capability, intentionally not part of AdvancedStore; returns the exact fact committed so callers can persist its identity without a post-write lookup
(*Store).PutWithOptionsReturningFact(ctx, agentID, text, WriteOptions) (Fact, error) Added in v0.20.0. Text, confidence, canonical ID and index maintenance commit in the same fact transaction
(*Store).ReviseWithOptions, ReviseFactsWithOptions Added in v0.20.0. Conservative omitted confidence, exact replacement identity; return a known committed replacement alongside a later retirement error
(*Store).RecallWithOptions, RecallExplainWithOptions, RecallSharedWithOptions, RecallAllWithOptions, BatchRecallWithOptions Added in v0.20.0. Per-call options; nonpositive topK uses 8. Existing raw Store recall signatures keep their legacy zero-count behavior
(*Store).DefaultConfidenceWeight() float64 Optional adapter capability added in v0.20.0; advertises the configured default so request routing and negotiated RPC retain the same effective policy
WriteOptions, RecallOptions, RecallResult, RecallExplainResult, RetrievalMetadata, ConfidenceRanking Added in v0.20.0. Optional pointer fields distinguish omission from explicit labels/zero; additive result metadata is omitted for legacy calls
EligibleVectorStore, ExhaustiveVectorStore Optional capabilities added in v0.20.0; VectorStore and AdvancedStore require no new methods
(*Store).Delete(agentID, factID string) error
(*Store).List(agentID string) ([]Fact, error)
(*Store).ListAgents() ([]string, error)
(*Store).Stats(agentID string) (MemoryStats, error)
(*Store).UpdateFact(agentID string, f Fact) error
(*Store).Recall(ctx, agentID, query string, topK int) ([]string, error) Result ordering is deterministic — see below
(*Store).RecallShared(ctx, query string, topK int) ([]string, error)
(*Store).RecallAll(ctx, agentID, query string, topK int) ([]string, error)
(*Store).RecallExplain(ctx, agentID, query string, topK int) ([]RecallReceipt, error) Added in v0.17.0. The same ranking as Recall — identical order, dedup and access-metadata side effects — with one receipt per returned fact instead of bare text. KG neighbour enrichment is text-only and has no receipts, so it is not part of the explain result
RecallReceipt struct (text, weight, age_days, ranks, provenance, kg_links) Added in v0.17.0. JSON tags are the wire contract for graymatter recall --explain --json and the MCP explained payload
RecallRanks struct (vector_rank, keyword_rank, recency_rank, fused_score, k) Added in v0.17.0. A rank of 0 means the signal did not rank the fact; the fused score reproduces from the ranks and k using the documented RRF arithmetic
RecallProvenance struct (fact_id, written_at, superseded_by, confidence, pinned) Added in v0.17.0
(*Store).PutShared(ctx, text string) error
(*Store).MaybeConsolidate(ctx, agentID string, cfg ConsolidateConfig) error
(*Store).Consolidate(ctx, agentID string, cfg ConsolidateConfig) error
(*Store).Close() error
(*Store).SetKG(graph GraphAccessor, extractor EntityExtractorAccessor)
(*Store).DB() *bolt.DB
Fact struct — all fields present in v0.1.0 New fields may be added; SupersededBy added in v0.10.0; Confidence added in v0.12.0; Pinned/PinnedAt added in v0.14.0 (zero values reproduce pre-v0.14 behaviour; older stores load as unpinned)
(Fact).IsSuperseded() bool Added in v0.10.0
SupersededByAgent constant Added in v0.10.0
MemoryStats struct
StoreConfig struct — all fields present in v0.1.0 New fields may be added; SignalWeights and MinRelevance added in v0.10.0
SignalWeights struct Added in v0.10.0
DefaultSignalWeights() SignalWeights Added in v0.10.0
ErrConsolidateLLMUnsupported Added in v0.10.0. Deprecated in v0.14.0: never returned anymore (Ollama consolidation is implemented); kept so errors.Is callers keep compiling
SharedAgentID constant
ConsolidateConfig interface v0.14.0: gained GetOllamaURL() and GetOllamaConsolidateModel(). This is a signature-level change to a stable identifier, taken with the deviation documented in the 0.14.0 changelog compatibility notes instead of a prior-minor deprecation cycle. Callers using graymatter.Config are unaffected; hand-rolled implementers add two getters
GraphAccessor interface
EntityExtractorAccessor interface
TypedEntityExtractor interface, EntityRef, EntityLink Added in v0.12.0 — optional extractor capability preserving label + type and producing co-mention links; consolidation uses it when implemented, legacy ID-only path otherwise
EdgeWriter interface Added in v0.12.0 — optional graph capability used by consolidation to persist co-mention edges
AdvancedStore.SetKG(...) Exposed in v0.12.0 (mirrors (*Store).SetKG)
(*Store).ConsolidationCounters(), ReadConsolidationCounters(db) Added in v0.14.0 — lifetime consolidation totals from the meta bucket, surfaced by status and doctor

Recall result ordering is deterministic: descending final score, oldest first, then ID.

With zero confidence weight the final score is the existing fused RRF score. An explicit confidence filter first restricts the corpus. Without a filter and with zero weight, scores and selection retain the previous arithmetic.

The same query against the same store returns the same facts in the same order, on every call, on every platform. Facts that score equally are ordered by CreatedAt ascending, and facts created in the same instant by fact ID ascending, which makes the order total.

This is a guarantee callers may rely on within each namespace. It applies to Recall and RecallShared, and every configuration of SignalWeights and MinRelevance. RecallAll combines those input rankings by namespace RRF and breaks ties by agent-list position, shared-list position, then text. Batch merge orders by best input rank, number of query hits, then first appearance.

Exception, v0.12.0: when a knowledge graph is wired via SetKG (directly, via AdvancedStore.SetKG, or by enabling the daemon’s --kg / GRAYMATTER_KG=1), Recall may append at most three neighbour labels after the ranked facts. The first topK entries keep the deterministic order above; appended entries are enrichment hints, capped and deduplicated, and never displace a ranked fact. Without a wired graph the exception does not exist and Recall returns at most topK distinct eligible facts.

An explicit min_confidence, including unverified, suppresses this text-only enrichment because graph labels have no confidence receipts. Retrieval metadata reports kg: "suppressed_min_confidence"; without a filter it describes hints as "hints_without_confidence_receipts". Explain never adds that hint tail.

These APIs and MCP/CLI options are available since v0.20.0 and absent from v0.19.1. Labels are writer declarations, not probabilities or verification by GrayMatter. New writes accept exactly verified, inferred or unverified. Absent/empty historical labels are effectively inferred; unknown historical labels are preserved and treated as unverified. Explicit invalid/null options are rejected before effects.

An omitted add label retains the legacy empty representation. An omitted revise label becomes min(inferred, lowest effective confidence of the validated live targets); an explicit label overrides it. Summaries use the same conservative minimum over valid consumed IDs, and LLM-extracted facts are unverified. The replacement fact’s write is atomic; subsequent retirements remain separate phases and their failures are reported. A revision never inherits a pin. Narrow lifecycle mutations preserve unrelated confidence metadata.

RecallOptions.MinConfidence filters before document frequencies, signal ranks, recency, fusion, MinRelevance, deduplication and top-k. An optional finite ConfidenceWeight in [0, 0.5] multiplies base RRF score B by 1 + weight * c, where verified has c = +1, inferred/legacy c = 0 and unverified/unknown c = -1. ConfidencePolicy is confidence-v1. ranks.fused_score remains B; the additive receipt ranking object identifies the final score that controls selection. Explicit zero weight preserves filters. Query options do not mutate global configuration. Config.ConfidenceWeight and StoreConfig.ConfidenceWeight set the configured request default within the same finite range. Omitted per-call weights use that default; explicit zero overrides it. An omitted RPC weight uses the configured default advertised by the actual server connection, unless the client supplies DialOptions.DefaultConfidenceWeight. A server that does not advertise a default uses the client’s product default. Adapters send the resolved value explicitly; batch resolves it once after connection preflight and before fan-out, keeping one policy if the daemon restarts during the batch. Reconnection renegotiates the default for later requests.

Both product and low-level defaults remain zero in v0.20.0. A future positive product default requires explicit notice in a published minor release and promotion in a subsequent minor release after the frozen quality gates pass. v0.20.0 does not announce a positive default or close issue #126. Explicit zero remains the legacy ranking opt-out and preserves any requested filter.

New RPC methods negotiate confidence-write-v1, confidence-recall-v1, confidence-lifecycle-v1 and confidence-shared-write-v1. The separate shared write capability provides PutSharedWithOptionsReturningFact and preserves RememberShared’s policy of scheduling no automatic consolidation. A generic write with agent_id = "__shared__" retains the ordinary Remember consolidation policy. Existing RPC methods retain zero confidence preference. A new client can use an old daemon for an effectively legacy request, but new options or an active positive default require a supporting capability; otherwise the request returns an update/restart error before effects. Reconnection renegotiates capabilities. Writes with uncertain commit results are not replayed. Pin, unpin and forget remain available against an older daemon: after negotiating the absence of confidence-lifecycle-v1, the client reads each target’s current metadata and uses the historical UpdateFact endpoint once. This compatibility path retains the old daemon’s read-modify-write concurrency limitations; upgraded daemons use transactional field patches. An error after sending a mutation never switches endpoints or replays that mutation. Revision requires confidence-write-v1 even when the label is omitted, because conservative confidence derivation and transactional source validation are new semantics. The REST API retains its legacy endpoints and zero preference; authenticated MCP over HTTP includes the new options.

Filtered vector retrieval requires the native eligible-ID capability or an optional custom capability that proves exhaustion. VectorStore.Query promises only at-most-n results; a short list cannot prove completeness. Progressive queries reuse one embedding and reject incomplete/no-progress prefixes. Keyword-only search remains supported without a vector capability. Concurrent confidence updates cannot mix eligibility with different receipt metadata. Once a query embedding exists, an overlapping alias edit that changes the effective query returns an explicit retry error before another embedding.

Before v0.11.0 the ordering of equal-scoring facts was unspecified in practice: the three signal rankings were sorted with a comparator that read only the score, and sort.Slice is not stable, so tied facts received arbitrary ranks which the fusion then read. Nothing about the scores has changed — only the resolution of ties.

Three additions, all fields or new identifiers, no signature changes — so the compatibility promise above holds and no caller needs to do anything.

Each new field’s zero value reproduces the previous behaviour exactly, which is enforced rather than asserted:

Field Zero value Behaviour at zero
Fact.SupersededBy "" Fact is live. Stores written before v0.10.0 have no superseded_by key and load as live — checked against a literal v0.9.0 JSON fact
StoreConfig.SignalWeights nil DefaultSignalWeights() — vector 1.0, keyword 1.0, recency 0.5, the values that were hardcoded before v0.10.0. It is a pointer precisely so the zero value cannot be confused with “all signals off”
StoreConfig.MinRelevance 0 No relevance floor; Recall returns exactly topK, the pre-v0.10.0 contract

TestRankingDefaults_MatchV09Behaviour is the gate: with the ranking fields unset, results must be identical to the v0.9.0 ranking.

One default did change, and it is a behaviour change rather than an addition: the REST server’s default k moved from 5 to 8, matching DefaultConfig().TopK and every other entry point. GET /recall with no k now returns 8 facts. Pass ?k=5 for the old count.


MCP wire contract (stable within the v0.x series)

Section titled “MCP wire contract (stable within the v0.x series)”

The Go package that implements the MCP server, cmd/graymatter/internal/mcp, is internal and carries no Go-level guarantee (see Internal / unstable packages). The wire contract it serves is different: any MCP client — in any language, often with no Go dependency at all — compiles against the payloads below. Within the v0.x series:

  • Tool names, parameter names, and required parameters will not be removed or renamed.
  • outputSchema objects are authoritative: a success result’s structuredContent conforms to the tool’s declared schema. Each result shape sets additionalProperties: false — on a oneOf union, each branch, since a root-level constraint would apply to every branch. New keys arrive only through a schema revision, never silently.
  • Text content remains functionally equivalent to structuredContent per the MCP compatibility guidance. Exact prose wording is best-effort and may be reworded; clients should read the structured payload.
  • Changes that would break a conforming client follow the same deprecation rule as the Go identifiers above: notice in the prior minor release.
  • Tool calls on one connection may execute concurrently (the stdio server runs a worker pool): a response guarantees only its own effects, and clients must not rely on cross-request ordering within a stream. A client that needs write-then-read visibility must wait for the write’s response first.
  • Enforcement is mechanical, not aspirational: tdqs_contract_test.go (tool set, titles, descriptions, input schemas), structured_contract_test.go (payload ↔ outputSchema agreement), and annotations_test.go (safety hints) fail CI on drift.

The tables below reflect the definitions served by graymatter mcp serve, verified against a live tools/list exchange at the time of writing.

Tool Required parameters Optional parameters
memory_search agent_id, query top_k (default 8), explain (boolean, default false), min_confidence, confidence_weight (since v0.20.0)
memory_search_batch agent_id, queries top_k (default 8), min_confidence, confidence_weight (since v0.20.0)
memory_add agent_id, text confidence (since v0.20.0)
memory_alias agent_id, term, equivalents —
checkpoint_save agent_id state (string containing a JSON object)
checkpoint_resume agent_id on_missing ("error" | "empty", default "error")
memory_reflect action, plus at least one explicit valid agent_id (canonical) or agent (deprecated alias; agent_id wins when both are valid) text, target

memory_reflect.action is an enum: add, update, forget, link, pin, unpin. Its input schema is a flat object with required: ["action"], no root anyOf, oneOf, or allOf, and additionalProperties: false. Both identity spellings remain schema-optional so canonical-only and alias-only callers can pass client validation. At least one explicit identity is required at runtime for both stdio and HTTP; no identity is derived from the working directory. An identity-free object passes the schema but returns a tool error before any backend call.

Every supplied agent_id or agent must be a non-empty string that is not entirely whitespace. Null, wrong types, empty strings, and whitespace-only strings are rejected even when the other field is valid. When both fields are valid, agent_id wins. Valid identities are not trimmed or normalized: " project " and "project" address distinct namespaces; Unicode and __shared__ are accepted. This hardens malformed inputs that previously could fall back to the alias or ignore an invalid alias without changing valid callers. See ADR-014.

Since v0.20.0, confidence is accepted on reflect add/update only. Search options on writes, confidence on other tools/actions, explicit null, wrong types, unknown labels and non-finite/out-of-range weights are errors. The runtime validates these new options explicitly; it does not enable global strict MCP argument validation as a side effect.

Tool Success payload Notes
memory_search {"agent_id", "query", "count", "facts", "feedback"?} facts is nullable in the schema; the empty result is count: 0, facts: [] with a “No memories found” text notice. feedback is optional: it carries the weak-match vocabulary block when the query’s vocabulary barely overlaps the store’s (v0.18.0), omitted otherwise
memory_search with explain: true {"agent_id", "query", "count", "facts", "explained"?} Added in v0.17.0. explained carries one RecallReceipt per fact (same JSON shape as the Go type); facts is present but empty so the payload conforms to the declared schema. The ranking is identical to explain: false — explain only reads it out
memory_search_batch {"agent_id", "count", "merged", "per_query"} count is the number of distinct facts in merged; per_query[] carries {"query", "facts", "error"?} — a per-query failure is reflected in per_query[].error while the other query results still return successfully
memory_add {"agent_id", "stored"} stored is true on success
memory_alias {"agent_id", "term", "equivalents", "stored"} stored is true on success
checkpoint_save {"agent_id", "checkpoint_id", "created_at"} created_at is RFC3339
checkpoint_resume {"id", "created_at", "state"?, "message_count"?} state is the persisted JSON object; keys marked ? may be absent when empty
checkpoint_resume with on_missing: "empty" {"found": false, "agent_id"} Added in v0.20.0. The successful absence result; found is always false and is declared non-optional. The output schema declares this shape and the success shape under oneOf
memory_reflect {"action", "agent", "ok"} ok is true on success

Confidence calls added in v0.20.0 preserve these keys and add declared optional schema fields. Explicit-label add/update results carry fact_id and confidence. Search, explain and batch add optional retrieval with effective min_confidence, confidence_weight, policy and kg, including empty results. Explain receipts add optional ranking with base_score, final_score, factor, effective_confidence, confidence_weight and policy. Text reports the same policy and identifies final scores. Legacy calls omit the new metadata. Batch applies one global policy to all input queries and its merged view.

Errors return text-only isError: true results without structuredContent; their wording may change. checkpoint_resume with no checkpoint returns such an error by default; the optional on_missing parameter ("error" — the default — or "empty") lets a caller opt into the successful {"found": false, "agent_id"} result above instead. This is an additive option in v0.20.0, not a behaviour change for existing callers. Advance notice: a default change to "empty" in v0.21.0 is conditional on a successful real OpenChamber/OpenCode smoke and publication of this prior-minor notice and the matching changelog notice, per the deprecation rule above. If the client rejects the union schema, apply and validate the documented fallback before publishing v0.20.0, keep "error" as the default, and defer the default change. Callers that depend on absence being an error should pass on_missing: "error" explicitly; it remains accepted as the legacy behaviour throughout v0.x. Storage, daemon, and corrupt-record failures stay prose-only in both modes. The former {"error": "not_found", "agent_id"} payload violated the declared success schema and was removed to prevent strict clients from rejecting the entire response (#117; ADR-013 amendment); the machine-readable absence result that amendment deferred is ADR-015.


Identifier Reason
memory.ExtractFacts New in v0.1.0; prompt and output format may be tuned
memory.ExtractConfig Interface may gain methods
(*Memory).Extract New in v0.1.0
(*Memory).RememberExtracted New in v0.1.0
(*Store).LaunchAsyncConsolidate Internal scheduling; may be unexported

The following packages are implementation details and provide no stability guarantee:

  • cmd/graymatter/internal/kg — knowledge graph and entity extraction
  • cmd/graymatter/internal/session — session checkpointing
  • cmd/graymatter/internal/harness — agent runner
  • cmd/graymatter/internal/mcp — MCP server handlers. The Go package is internal and may change freely; the wire contract it serves is stable — see MCP wire contract
  • cmd/graymatter/internal/server — REST API server
  • cmd/graymatter/internal/plugin — plugin protocol
  • cmd/graymatter/internal/export — Obsidian / markdown export
  • pkg/embedding — embedding backend adapters (public; see the stable table for its provider interface)
  • cmd/ — CLI command implementations