Skip to content

API Reference

mempill’s canonical Rust API reference is auto-generated from source and hosted on docs.rs. The guides in this documentation are the authoritative human-readable reference with full examples and decision rationale.

The Rust API is documented inline via rustdoc and served on docs.rs. The table below links to each crate’s reference page.

Crate docs.rs link Description
mempill-core docs.rs/mempill-core EngineHandle, port traits (PersistencePort, OraclePort, VectorPort), use-cases, DTOs (IngestClaimRequest, QueryMemoryRequest, ReconcileRequest, AuditQueryRequest)
mempill-types docs.rs/mempill-types Domain types: ProvenanceLabel, Disposition, Cardinality, Confidence, Criticality, ValidTime, BeliefProjection, LedgerEntry, ClaimRef, AgentId
mempill-sqlite docs.rs/mempill-sqlite DefaultEngine alias, open_default_for_agent, open_default_in_memory, open_with_oracle_for_agent, open_with_oracle_in_memory, SqlitePersistenceStore
mempill-postgres docs.rs/mempill-postgres PostgresEngine alias, open_postgres, open_postgres_with_oracle, PostgresPersistenceStore, PoolConfig

To browse docs locally:

Terminal window
cd mempill
cargo doc --workspace --open

The Python API is documented via PyO3 docstrings in mempill-python/python/mempill/_mempill.pyi and types.py. A pdoc-generated reference is planned at https://api.mempill.dev/python/. Until then, generate it locally:

Terminal window
cd mempill-python
pip install pdoc
pdoc mempill --output-dir docs/python
open docs/python/mempill.html

The type stubs (_mempill.pyi, types.py) are the authoritative type source and are readable directly in any editor.

Language No-oracle With oracle
Python (SQLite) mempill.open_for_agent(base_dir, agent_id), mempill.open_in_memory() mempill.open_oracle_for_agent(base_dir, agent_id, oracle), mempill.open_oracle_in_memory(oracle)
Rust (SQLite) open_default_for_agent(base_dir, agent_id), open_default_in_memory() open_with_oracle_for_agent(base_dir, agent_id, arc_oracle), open_with_oracle_in_memory(arc_oracle)
Rust (Postgres) open_postgres(conn_str, None, None, config) open_postgres_with_oracle(conn_str, arc_oracle, None, config)

SQLite constructors are per-agent as of 0.4.0 — the database file is derived automatically as base_dir/agent_{agent_id}.db. See Changelog.

Method Request type Response type Description
ingest_claim IngestClaimRequest IngestClaimResponse Write a belief claim
query_memory QueryMemoryRequest QueryMemoryResponse Read canonical belief
query_subject QuerySubjectRequest QuerySubjectResponse Read the resolved belief for every predicate known about a subject (available as of 0.3.0)
query_history / history() subject-line identifiers History (Rust) / HistoryResult (Python) Full ordered claim timeline for a (subject, predicate) line — status per entry (Current / Superseded / Contested / Ended), each with honest per-endpoint date granularity (0.4.0; see below)
assert_validity AssertValidityRequest AssertValidityResponse Bound or reopen a claim’s valid-time window — explicit host-initiated end-of-fact (0.4.0)
reconcile ReconcileRequest ReconcileResponse Re-run conflict resolution
query_audit AuditQueryRequest AuditQueryResponse Read immutable ledger

Both the Rust facade (mempill) and the Python wheel expose a simplified additive API on top of the full DTO surface above — remember(engine, ..., RememberOptions) and recall(engine, ...) — for callers who don’t need explicit provenance/confidence/cardinality control. See the Quickstart (Rust) and Quickstart (Python) for full usage; the full DTO API (ingest_claim / query_memory) remains available for advanced provenance control.

QuerySubjectRequest / QuerySubjectResponse fields

Section titled “QuerySubjectRequest / QuerySubjectResponse fields”
Field Python key Rust field Type Required
Agent identity "agent_id" agent_id str / AgentId Yes
Subject "subject" subject str Yes
Valid-time as-of "valid_at" valid_at ISO-8601 string / Option<DateTime<Utc>> No
Tx-time as-of "as_of_tx_time" as_of_tx_time ISO-8601 string / Option<DateTime<Utc>> No

Response is a list of per-predicate entries (Python) / QuerySubjectResponse { entries } (Rust), sorted by predicate. Each entry: predicate, value, status, valid_from_display, valid_until_display, provenance, claim_ref, conf.

Each entry in query_history / history()’s timeline: claim_ref, value, valid_from, valid_until, status (Current | Superseded | Contested | Ended), provenance, value_confidence, plus (0.4.0) valid_from_granularity and valid_until_granularity (raw DateGranularity tags). The Python wheel additionally pre-renders valid_from_display / valid_until_display (same rendering rules as query_memory / query_subject).

Status vocabulary:

  • Current — live (in fold.live_claims), unconflicted (not fold.has_conflict), and its effective window contains the query instant.
  • Superseded — not live; closed by a non-overlapping successor claim.
  • Contested — live and part of an unresolved conflict: either the fold-wide conflict flag, or a pairwise valid-time overlap detected against an adjacent live entry in the timeline (never silently narrowed or picked).
  • Ended — still live per the ledger (never explicitly bounded), but its own valid-time window has naturally expired with no live successor covering the query instant. Distinguishable from Superseded because the ledger contains no explicit successor.

The HistoryEntryStatus enum is #[non_exhaustive] — consumers should handle unknown values gracefully.

valid_until semantics: A claim’s valid_until is its own explicit valid_time.end when present. This window is narrowed by a successor only when the two form a genuine non-overlapping succession. Overlapping claims keep their own windows and are reported Contested. Endpoint precision follows whichever claim supplied that endpoint. A succession starting exactly at an ended window’s end stays a clean (cheap) succession.

valid_until_granularity derivation: When narrowed by a successor, valid_until_granularity is the successor’s start_granularity (or None when the successor’s ordering key falls back to transaction_time). When using the claim’s own end, it is the claim’s own end_granularity. When ended by a bound (affirmed adjudication or assert_validity / end_fact), it carries the granularity of the bounding instant: the winning challenger’s start_granularity for adjudication (or None for a Deny bound), and the date precision as given for end_fact. See Changelog: Date granularity on history() for the full rule and rationale.

Method Description
list_pending_adjudications(agent_id) Return pending conflict queue for an agent
submit_adjudication({handle_id, verdict, evidence_provenance}) Resolve a pending conflict
sweep_expired_adjudications() Return TTL-expired adjudications to Contested
Field Python key Rust field Type Required
Agent identity "agent_id" agent_id str / AgentId Yes
Subject "subject" subject str Yes
Predicate "predicate" predicate str Yes
Value "value" value any JSON / serde_json::Value Yes
Provenance "provenance" provenance dict or ProvenanceLabel Yes
Cardinality "cardinality" cardinality "Functional" / "SetValued" / "Unknown" Yes
Valid time "valid_time" valid_time dict with start, end, valid_time_confidence / Option<ValidTime> No
Confidence "confidence" confidence {value_confidence, valid_time_confidence} / Confidence Yes
Criticality "criticality" criticality "Low" / "Medium" / "High" / "Critical" Yes
Derived from "derived_from" derived_from list[str] / Vec<ClaimRef> Yes (empty ok)
Field Python key Rust field Description
Claim reference "claim_ref" claim_ref UUID of the written claim
Disposition "disposition" disposition One of the 12-state model values
Contested with "contested_with" contested_with UUIDs of conflicting claims (empty unless Contested/PendingConflict)
Field Python key Rust field Type Required
Agent identity "agent_id" agent_id str / AgentId Yes
Target claim "target" target str (UUID) / ClaimRef Yes
Assertion "assertion" assertion {"type": "Bound", "value": {"at": "<RFC3339>", "at_granularity": "year"|"month"|"day"|"instant" | None}} or {"type": "Reopen"} (Python wire dict) / mempill_core::ValidityAssertionInput::Bound { at: DateTime<Utc> } or ::Reopen (Rust) Yes
Provenance "provenance" provenance dict or ProvenanceLabel; must be External(*) Yes
Confidence "confidence" confidence {value_confidence, valid_time_confidence} / Confidence Yes

Reopen reverses the most recent active Bound on target; it carries no timestamp — the engine stamps now. at_granularity (Python only) is optional — the engine derives it from the original date string’s precision when using the end_fact ergonomic helper (see below). When calling engine.assert_validity directly, you can supply it explicitly to record the original precision: date_granularity_of() is the recommended way.

Error conditions (raised as MemError subvariants in Rust, exception subclasses in Python/MCP):

  • ClaimNotFound (Rust) / NotFoundError (Python, MCP) — target claim UUID does not exist, or belongs to another agent
  • AlreadyBound (Rust) / ConflictError (Python, MCP) — a different bound is already active on target; reopen first if the boundary needs to move. Only reachable via assert_validity called directly with a known target — not reachable through end_fact (see below)
  • IncoherentTemporalWindow (Rust) / ValidationError (Python, MCP) — at precedes the target claim’s own valid_time.start
  • InsufficientProvenanceForOverturn (Rust) / ValidationError (Python, MCP) — provenance is not External(*)
  • TargetUnderAdjudication (Rust) / ValidationError (Python, MCP) — Bound was requested on a claim that is QueuedForAdjudication or was rejected by an oracle Deny verdict; call Reopen first to reverse a denial, or wait for adjudication to complete
Field Python key Rust field Type Description
Claim reference "claim_ref" claim_ref str (UUID) / ClaimRef Echo of target
Assertion reference "assertion_ref" assertion_ref str | None / Option<Uuid> UUID of the appended (or, for a no-op, pre-existing) validity assertion. None only for a Reopen no-op with nothing to reverse
Kind "kind" kind AssertionKind The engine-stamped assertion actually in effect after this call
Effective at "effective_at" effective_at ISO-8601 string | None / Option<DateTime<Utc>> Instant the assertion takes effect (at for Bound, the reopen instant for Reopen); None for a Reopen no-op
Disposition "disposition" disposition "Superseded" (Bound) / "Reinstated" (Reopen) Ledger disposition for this write
No-op "no_op" no_op bool true when no new write was made: an idempotent repeat of an identical Bound, a Reopen with no active Bound to reverse, or a Bound whose at is at/after the claim’s own valid_time.end (has zero effect on the derived window — effective_at then honestly reports the effective end time, not the raw requested at)

Ergonomic end_fact (Python, Rust facade) (0.4.0)

Section titled “Ergonomic end_fact (Python, Rust facade) (0.4.0)”

A module-level convenience wrapper around assert_validity that resolves the claim by (subject, predicate) instead of requiring a ClaimRef — never guesses when the line is ambiguous. Only supports Bound; call assert_validity directly (with a known target) to Reopen.

Rust signature:

pub async fn end_fact(
engine: &impl CanAssertValidity,
agent_id: impl Into<String>,
subject: impl Into<String>,
predicate: impl Into<String>,
at: impl Into<String>, // lenient date string: YYYY / YYYY-MM / YYYY-MM-DD / RFC3339
opts: EndFactOptions, // { provenance: Option<ProvenanceLabel>, confidence: Option<f32> }
) -> Result<EndFactReceipt, MempillDxError>

Python signature (module-level function, not an engine method):

from mempill import end_fact
end_fact(
engine,
agent_id: str,
subject: str,
predicate: str,
at: str, # lenient date string
provenance: dict | None = None, # defaults to External/UserAsserted
confidence: float = 1.0,
) -> EndFactReceipt # .claim_ref .disposition .effective_at .no_op

Behavior — resolution runs against the same canonical fold recall / history use (never a heuristic re-derivation):

  • 0 live claims on the line → MempillDxError::NoLiveClaimForClose (Rust) / NotFoundError (Python, MCP) — including a repeat end_fact call on an already-fully-closed line (the bounded claim is no longer live, so this is not a no-op)
  • 1 live claim → bounds it at at; returns EndFactReceipt. In Python/MCP, the at string’s precision is captured via date_granularity_of(at) and recorded as at_granularity in the assertion (so end_fact(engine, agent, s, p, "2024-09") yields valid_until_granularity == "month" in history).
  • 1 live claims (Contested, or co-existing SetValued members) → MemError::AmbiguousLineForClose (Rust) / ValidationError (Python, MCP) — resolve via assert_validity with an explicit target

MemError::AlreadyBound is not reachable through end_fact — resolution only ever targets a currently-live claim, and a claim with an active bound is by definition not live. It is only reachable via assert_validity called directly with an already-known target.

Backs end_fact — resolves a (subject, predicate) line to the single live claim, using the same canonical fold as query_memory / query_history (I8 single source of truth).

  • Python: engine.resolve_live_claim_for_line(agent_id, subject, predicate) -> dict — {"status": "empty" | "single" | "ambiguous", "claim_ref": str | None, "live_count": int | None} (live_count populated only for "ambiguous").
  • Rust facade (CanAssertValidity): resolve_live_claim_for_line_ergo(...) -> LiveClaimResolution — Empty / Single(ClaimRef) / Ambiguous(usize).

Helper date_granularity_of (Python) (0.4.0)

Section titled “Helper date_granularity_of (Python) (0.4.0)”

mempill.date_granularity_of(value: str) -> str | None — returns the display precision of a lenient date string, as the engine’s own parser sees it. "2024" → "year", "2024-09" → "month", "2024-09-15" → "day", an RFC3339 string → "instant"; None when the string cannot be parsed. Used to populate the at_granularity field of an assert_validity Bound assertion — the ergonomic end_fact wrapper calls it automatically.

mempill::assert_validity(engine, req: mempill_core::AssertValidityRequest) -> Result<mempill_core::AssertValidityResponse, MempillDxError> — a typed passthrough to the engine op for callers who already hold the target ClaimRef (e.g. from a RememberReceipt or a history entry) or need Reopen. Most callers should prefer end_fact.

Python (wire dict via engine.assert_validity):

resp = engine.assert_validity({
"agent_id": "agent-1",
"target": claim_ref,
"assertion": {"type": "Reopen"},
"provenance": {"type": "External", "kind": "UserAsserted"},
"confidence": {"value_confidence": 1.0, "valid_time_confidence": 1.0},
})
# resp["disposition"] == "Reinstated"

Rust (facade passthrough):

use mempill::assert_validity;
use mempill_core::{AssertValidityRequest, ValidityAssertionInput};
use mempill_types::{AgentId, ProvenanceLabel, Confidence, ExternalKind, Disposition};
let resp = assert_validity(&engine, AssertValidityRequest {
agent_id: AgentId("agent-1".into()),
target: claim_ref,
assertion: ValidityAssertionInput::Reopen,
provenance: ProvenanceLabel::External(ExternalKind::UserAsserted),
confidence: Confidence { value_confidence: 1.0, valid_time_confidence: 1.0 },
}).await?;
assert_eq!(resp.disposition, Disposition::Reinstated);
Value Meaning
CommittedCheap Fast-path commit — external provenance, no conflict
CommittedInferred Non-conflicting ModelDerived claim — committed down-weighted, ineligible to overturn an existing belief until anchored
Contested Conflict; both values preserved; no winner
QueuedForAdjudication Oracle wired; conflict queued for resolution
PendingConflict Conflict detected; challenger parked (oracle said Deny)
PendingReview Flagged for review before commit
PendingLowConfidence Held pending due to low confidence
Superseded Belief-overturning accepted; the prior claim is bounded and retained in history
Invalidated A validity assertion marks the claim as no-longer-true; retained in history
Reinstated Valid-time window reopened by a new external/first-hand assertion (non-terminal)
Quarantined Blocked by Amplification Guard (RecallReEntry echo)
Rejected Rejected by validation or gate rules
Exception Inherits from Meaning
MempillError Exception Base — catch-all
ValidationError MempillError Bad request shape or domain invariant violation
NotFoundError MempillError Agent, claim, or adjudication handle not found
ConflictError MempillError Write-lock contention — safe to retry
StorageError MempillError Persistence layer failure
ConfigError MempillError Invalid calibration parameter
InternalError MempillError Engine invariant violated — indicates a bug

The API reference above captures the stable surface. For full usage with examples, edge cases, and decision rationale, consult the guides: