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.
Rust crates (docs.rs)
Section titled “Rust crates (docs.rs)”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:
cd mempillcargo doc --workspace --openPython API
Section titled “Python API”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:
cd mempill-pythonpip install pdocpdoc mempill --output-dir docs/pythonopen docs/python/mempill.htmlThe type stubs (_mempill.pyi, types.py) are the authoritative type source and are
readable directly in any editor.
Key operations at a glance
Section titled “Key operations at a glance”Constructors
Section titled “Constructors”| 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.
Core methods (all engines)
Section titled “Core methods (all engines)”| 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 |
Ergonomic tier (remember / recall)
Section titled “Ergonomic tier (remember / recall)”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.
HistoryEntry fields (0.4.0)
Section titled “HistoryEntry fields (0.4.0)”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 (infold.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 fromSupersededbecause 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.
Oracle methods (OracleEngine only)
Section titled “Oracle methods (OracleEngine only)”| 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 |
IngestClaimRequest fields
Section titled “IngestClaimRequest fields”| 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) |
IngestClaimResponse fields
Section titled “IngestClaimResponse fields”| 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) |
AssertValidityRequest fields (0.4.0)
Section titled “AssertValidityRequest fields (0.4.0)”| 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 agentAlreadyBound(Rust) /ConflictError(Python, MCP) — a different bound is already active ontarget; reopen first if the boundary needs to move. Only reachable viaassert_validitycalled directly with a knowntarget— not reachable throughend_fact(see below)IncoherentTemporalWindow(Rust) /ValidationError(Python, MCP) —atprecedes the target claim’s ownvalid_time.startInsufficientProvenanceForOverturn(Rust) /ValidationError(Python, MCP) — provenance is notExternal(*)TargetUnderAdjudication(Rust) /ValidationError(Python, MCP) —Boundwas requested on a claim that isQueuedForAdjudicationor was rejected by an oracleDenyverdict; callReopenfirst to reverse a denial, or wait for adjudication to complete
AssertValidityResponse fields (0.4.0)
Section titled “AssertValidityResponse fields (0.4.0)”| 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_opBehavior — 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 repeatend_factcall 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; returnsEndFactReceipt. In Python/MCP, theatstring’s precision is captured viadate_granularity_of(at)and recorded asat_granularityin the assertion (soend_fact(engine, agent, s, p, "2024-09")yieldsvalid_until_granularity == "month"in history). -
1 live claims (Contested, or co-existing SetValued members) →
MemError::AmbiguousLineForClose(Rust) /ValidationError(Python, MCP) — resolve viaassert_validitywith an explicittarget
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.
resolve_live_claim_for_line
Section titled “resolve_live_claim_for_line”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_countpopulated 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.
Facade assert_validity passthrough (Rust)
Section titled “Facade assert_validity passthrough (Rust)”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.
Reopen example
Section titled “Reopen example”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);Disposition values (12-state model)
Section titled “Disposition values (12-state model)”| 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 |
Python exceptions
Section titled “Python exceptions”| 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 |
Guides as the primary reference
Section titled “Guides as the primary reference”The API reference above captures the stable surface. For full usage with examples, edge cases, and decision rationale, consult the guides:
- Rust (Advanced) — all field semantics, valid_time, reconcile, audit, oracle constructors
- Python (Advanced) — dict shapes, TypedDicts, async, error handling
- Writing an Oracle —
request_adjudicationprotocol,submit_adjudication, HumanOracle pattern - Query Patterns — belief shape, Contested handling, AuditQueryRequest
- MCP Integration — tool signatures, environment contract, config files
- PostgreSQL Backend —
open_postgres, connection string, topology-b