> ## Documentation Index
> Fetch the complete documentation index at: https://memproof.kyberon.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Memproof Class

> Full reference for the Memproof entry-point class -- constructor, methods, parameters, and return types.

# Memproof

`memproof.Memproof` is the single entry point for the library. It assembles the internal pipeline (risk engine, policy engine, Trailproof audit trail, quarantine store, approval broker, and memory adapter) and exposes a concise async API.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
from memproof import Memproof

mp = Memproof(policy="./memproof.yaml")
```

***

## Constructor

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
Memproof(
    policy: str | None = None,
    adapter: str = "in_memory",
    config: MemproofConfig | None = None,
    *,
    policy_schema_path: str | None = None,
    langgraph_url: str = "",
    langgraph_api_key: str = "",
    openai_api_key: str = "",
    openai_organization: str = "",
    mcp_server_url: str = "",
    trail_store: str = "memory",
    trail_store_path: str | None = None,
    trail_signing_key: str | None = None,
    attesta_enabled: bool = False,
    attesta_url: str = "",
    attesta_token: str = "",
)
```

You can either pass a fully constructed `MemproofConfig` object via `config`, or use the convenience keyword arguments -- they are forwarded to a new `MemproofConfig` internally. If `config` is provided, the keyword arguments are ignored (except `policy_schema_path`).

### Parameters

<ParamField path="policy" type="str | None" default="None">
  Path to a Memproof policy YAML file. If `None` and no `config` is provided, defaults to `"memproof.yaml"` in the current working directory.
</ParamField>

<ParamField path="adapter" type="str" default="&#x22;in_memory&#x22;">
  Which memory adapter to use. Supported values:

  * `"in_memory"` -- ephemeral, dictionary-backed store (useful for testing).
  * `"langgraph"` -- LangGraph checkpoint-backed store.
  * `"openai_sessions"` -- OpenAI Sessions API-backed store.
  * `"mcp"` -- MCP memory server-backed store.
</ParamField>

<ParamField path="config" type="MemproofConfig | None" default="None">
  A pre-built configuration object. When provided, all other keyword arguments (except `policy_schema_path`) are ignored. See [Configuration](/api-reference/config).
</ParamField>

<ParamField path="policy_schema_path" type="str | None" default="None">
  Path to the JSON Schema file used to validate the policy YAML. If `None`, Memproof looks for `schemas/memproof-policy.schema.json` relative to the package root.
</ParamField>

<ParamField path="langgraph_url" type="str" default="&#x22;&#x22;">
  Base URL for the LangGraph checkpoint API. Only used when `adapter="langgraph"`.
</ParamField>

<ParamField path="langgraph_api_key" type="str" default="&#x22;&#x22;">
  API key for authenticating with the LangGraph checkpoint API.
</ParamField>

<ParamField path="openai_api_key" type="str" default="&#x22;&#x22;">
  OpenAI API key. Only used when `adapter="openai_sessions"`.
</ParamField>

<ParamField path="openai_organization" type="str" default="&#x22;&#x22;">
  OpenAI organization ID. Only used when `adapter="openai_sessions"`.
</ParamField>

<ParamField path="mcp_server_url" type="str" default="&#x22;&#x22;">
  URL of the MCP memory server. Only used when `adapter="mcp"`.
</ParamField>

<ParamField path="trail_store" type="str" default="&#x22;memory&#x22;">
  Trailproof audit trail storage backend. Supported values:

  * `"memory"` -- in-memory store (events are lost on process exit).
  * `"jsonl"` -- JSONL file-backed persistent store.
</ParamField>

<ParamField path="trail_store_path" type="str | None" default="None">
  File path for the JSONL trail store. Required when `trail_store="jsonl"`.
</ParamField>

<ParamField path="trail_signing_key" type="str | None" default="None">
  HMAC-SHA256 secret key for signing trail events. When provided, each event includes a cryptographic signature for tamper detection.
</ParamField>

<ParamField path="attesta_enabled" type="bool" default="False">
  Enable the Attesta external approval service for `require_approval` policy decisions.
</ParamField>

<ParamField path="attesta_url" type="str" default="&#x22;&#x22;">
  Base URL for the Attesta approval service.
</ParamField>

<ParamField path="attesta_token" type="str" default="&#x22;&#x22;">
  Bearer token for authenticating with the Attesta approval service.
</ParamField>

### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
from memproof import Memproof

# Minimal -- uses in-memory adapter and default policy path
mp = Memproof(policy="./memproof.yaml")

# With LangGraph backend and JSONL audit trail
mp = Memproof(
    policy="./memproof.yaml",
    adapter="langgraph",
    langgraph_url="https://langgraph.example.com",
    langgraph_api_key="lg-key-abc",
    trail_store="jsonl",
    trail_store_path="./audit.jsonl",
    trail_signing_key="my-hmac-secret",
)

# With a pre-built config object
from memproof import MemproofConfig

cfg = MemproofConfig(
    policy_path="./memproof.yaml",
    adapter="mcp",
    mcp_server_url="http://localhost:8200",
)
mp = Memproof(config=cfg)
```

***

## Methods

### remember()

Create a new memory through the full control pipeline (risk assessment, policy evaluation, event logging, and adapter persistence).

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
async def remember(
    content: str,
    scope: dict[str, Any] | MemoryScope,
    context: dict[str, Any] | OperationContext,
    *,
    tags: list[str] | None = None,
    metadata: dict[str, Any] | None = None,
    ttl_seconds: int | None = None,
    idempotency_key: str | None = None,
) -> MemoryOperationResponse
```

<ParamField path="content" type="str" required>
  The memory content to store. Must be non-empty.
</ParamField>

<ParamField path="scope" type="dict | MemoryScope" required>
  Identifies where this memory belongs. Accepts either a `MemoryScope` instance or a dictionary with the keys `tenant_id`, `project_id`, `agent_id`, and optionally `session_id` and `subject_id`.
</ParamField>

<ParamField path="context" type="dict | OperationContext" required>
  Describes who is performing the operation and when. Accepts either an `OperationContext` instance or a dictionary with the keys `actor_type`, `actor_id`, `source`, `timestamp`, and optionally `request_id`, `correlation_id`, and `metadata`.
</ParamField>

<ParamField path="tags" type="list[str] | None" default="None">
  Optional list of tags to associate with the memory.
</ParamField>

<ParamField path="metadata" type="dict[str, Any] | None" default="None">
  Arbitrary key-value metadata to attach to the memory record.
</ParamField>

<ParamField path="ttl_seconds" type="int | None" default="None">
  Time-to-live in seconds. If set, the memory will be considered expired after this duration. Must be greater than 0.
</ParamField>

<ParamField path="idempotency_key" type="str | None" default="None">
  Client-supplied idempotency key. If the same key is reused, the original response is returned without re-executing the operation. If `None`, a unique key is generated automatically.
</ParamField>

<ResponseField name="return" type="MemoryOperationResponse">
  Contains `operation_id`, `status`, the created `memory` record (if committed), `risk_assessment`, and the `decision` from the policy engine. See [Models](/api-reference/models#memoryoperationresponse).
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
result = await mp.remember(
    content="user prefers dark mode",
    scope={"tenant_id": "acme", "project_id": "assistant", "agent_id": "a1"},
    context={
        "actor_type": "agent",
        "actor_id": "a1",
        "source": "langgraph",
        "timestamp": "2026-01-15T10:30:00Z",
    },
    tags=["preference", "ui"],
    metadata={"confidence": 0.95},
    ttl_seconds=86400,
)

print(result.status)          # OperationStatus.committed
print(result.memory.memory_id)
print(result.decision.action) # DecisionAction.allow
```

***

### get()

Retrieve a single memory record by its ID.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
async def get(memory_id: str) -> MemoryRecord
```

<ParamField path="memory_id" type="str" required>
  The unique identifier of the memory to retrieve.
</ParamField>

<ResponseField name="return" type="MemoryRecord">
  The full memory record. See [Models](/api-reference/models#memoryrecord).
</ResponseField>

#### Errors

* `NotFoundError` -- raised if no memory with the given ID exists.

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
record = await mp.get("mem-abc123")
print(record.content)
print(record.scope.tenant_id)
```

***

### update()

Update an existing memory through the full control pipeline. Only the fields you provide are changed; omitted fields remain unchanged.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
async def update(
    memory_id: str,
    context: dict[str, Any] | OperationContext,
    *,
    content: str | None = None,
    tags: list[str] | None = None,
    metadata_patch: dict[str, Any] | None = None,
    ttl_seconds: int | None = None,
    idempotency_key: str | None = None,
) -> MemoryOperationResponse
```

<ParamField path="memory_id" type="str" required>
  The ID of the memory to update.
</ParamField>

<ParamField path="context" type="dict | OperationContext" required>
  Operation context. Same format as `remember()`.
</ParamField>

<ParamField path="content" type="str | None" default="None">
  New content for the memory. If `None`, the content is not changed.
</ParamField>

<ParamField path="tags" type="list[str] | None" default="None">
  Replacement tag list. If `None`, tags are not changed.
</ParamField>

<ParamField path="metadata_patch" type="dict[str, Any] | None" default="None">
  Key-value pairs to merge into the existing metadata. Existing keys not present in the patch are preserved.
</ParamField>

<ParamField path="ttl_seconds" type="int | None" default="None">
  New TTL value in seconds. Must be greater than 0 if provided.
</ParamField>

<ParamField path="idempotency_key" type="str | None" default="None">
  Client-supplied idempotency key.
</ParamField>

<ResponseField name="return" type="MemoryOperationResponse">
  Contains the updated memory, risk assessment, and policy decision. See [Models](/api-reference/models#memoryoperationresponse).
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
result = await mp.update(
    memory_id="mem-abc123",
    context={
        "actor_type": "user",
        "actor_id": "user-42",
        "source": "web-ui",
        "timestamp": "2026-01-15T11:00:00Z",
    },
    content="user prefers light mode",
    tags=["preference", "ui", "updated"],
)

print(result.status)  # OperationStatus.committed
```

***

### forget()

Delete a memory through the full control pipeline. The operation still flows through risk assessment and policy evaluation before the adapter removes the record.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
async def forget(
    memory_id: str,
    context: dict[str, Any] | OperationContext,
    *,
    idempotency_key: str | None = None,
) -> OperationStatusResponse
```

<ParamField path="memory_id" type="str" required>
  The ID of the memory to delete.
</ParamField>

<ParamField path="context" type="dict | OperationContext" required>
  Operation context. Same format as `remember()`.
</ParamField>

<ParamField path="idempotency_key" type="str | None" default="None">
  Client-supplied idempotency key.
</ParamField>

<ResponseField name="return" type="OperationStatusResponse">
  Contains the operation ID, status, and decision. See [Models](/api-reference/models#operationstatusresponse).
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
result = await mp.forget(
    memory_id="mem-abc123",
    context={
        "actor_type": "user",
        "actor_id": "user-42",
        "source": "web-ui",
        "timestamp": "2026-01-15T12:00:00Z",
    },
)

print(result.status)  # OperationStatus.committed
```

***

### search()

Search for memories within a given scope. The search query is forwarded to the adapter, which returns ranked results.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
async def search(
    query: str,
    scope: dict[str, Any] | MemoryScope,
    context: dict[str, Any] | OperationContext,
    *,
    limit: int = 20,
    filters: dict[str, Any] | None = None,
) -> MemorySearchResponse
```

<ParamField path="query" type="str" required>
  The search query string. Must be non-empty.
</ParamField>

<ParamField path="scope" type="dict | MemoryScope" required>
  Restricts the search to memories within this scope.
</ParamField>

<ParamField path="context" type="dict | OperationContext" required>
  Operation context for auditing the search request.
</ParamField>

<ParamField path="limit" type="int" default="20">
  Maximum number of results to return. Must be between 1 and 100 (inclusive).
</ParamField>

<ParamField path="filters" type="dict[str, Any] | None" default="None">
  Additional key-value filters passed to the adapter. The available filter keys depend on the adapter implementation.
</ParamField>

<ResponseField name="return" type="MemorySearchResponse">
  Contains a `hits` list of `MemorySearchHit` objects, each with a `memory` and a relevance `score`. See [Models](/api-reference/models#memorysearchresponse).
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
results = await mp.search(
    query="dark mode",
    scope={"tenant_id": "acme", "project_id": "assistant", "agent_id": "a1"},
    context={
        "actor_type": "agent",
        "actor_id": "a1",
        "source": "langgraph",
        "timestamp": "2026-01-15T10:31:00Z",
    },
    limit=5,
)

for hit in results.hits:
    print(f"{hit.memory.content} (score={hit.score})")
```

***

### get\_operation\_status()

Retrieve the current status of a previously submitted operation. This is a **synchronous** method.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
def get_operation_status(operation_id: str) -> OperationStatusResponse
```

<ParamField path="operation_id" type="str" required>
  The operation ID returned by `remember()`, `update()`, or `forget()`.
</ParamField>

<ResponseField name="return" type="OperationStatusResponse">
  Current status of the operation. See [Models](/api-reference/models#operationstatusresponse).
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
status = mp.get_operation_status(result.operation_id)
print(status.status)          # e.g. OperationStatus.pending_approval
print(status.operation_type)  # e.g. OperationType.remember
```

***

### approve()

Approve a pending operation that was held by a `require_approval` policy decision.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
async def approve(
    operation_id: str,
    actor_id: str,
    notes: str | None = None,
) -> OperationStatusResponse
```

<ParamField path="operation_id" type="str" required>
  The ID of the operation to approve.
</ParamField>

<ParamField path="actor_id" type="str" required>
  Identifier of the actor (human reviewer) performing the approval.
</ParamField>

<ParamField path="notes" type="str | None" default="None">
  Optional free-text notes to attach to the approval decision.
</ParamField>

<ResponseField name="return" type="OperationStatusResponse">
  Updated status of the operation after approval. See [Models](/api-reference/models#operationstatusresponse).
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
approved = await mp.approve(
    operation_id="op-xyz789",
    actor_id="reviewer-1",
    notes="Reviewed and approved -- content is safe.",
)

print(approved.status)  # OperationStatus.committed
```

***

### deny()

Deny a pending operation that was held by a `require_approval` policy decision.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
async def deny(
    operation_id: str,
    actor_id: str,
    notes: str | None = None,
) -> OperationStatusResponse
```

<ParamField path="operation_id" type="str" required>
  The ID of the operation to deny.
</ParamField>

<ParamField path="actor_id" type="str" required>
  Identifier of the actor performing the denial.
</ParamField>

<ParamField path="notes" type="str | None" default="None">
  Optional free-text notes explaining the denial.
</ParamField>

<ResponseField name="return" type="OperationStatusResponse">
  Updated status of the operation after denial. See [Models](/api-reference/models#operationstatusresponse).
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
denied = await mp.deny(
    operation_id="op-xyz789",
    actor_id="reviewer-1",
    notes="Content contains PII -- denied per policy.",
)

print(denied.status)  # OperationStatus.blocked
```

***

### verify\_audit\_trail()

Verify the integrity of the Trailproof audit trail by validating the SHA-256 hash chain. If any event has been tampered with, the chain breaks and verification fails.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
def verify_audit_trail() -> TrailVerificationResult
```

<ResponseField name="return" type="TrailVerificationResult">
  Contains `valid` (bool), `event_count` (int), and `error` (str or None if valid). See [Trailproof documentation](https://trailproof.kyberon.dev/docs/introduction) for details.
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
result = mp.verify_audit_trail()

if result.valid:
    print(f"Audit trail intact: {result.event_count} events verified")
else:
    print(f"Tampering detected: {result.error}")
```

***

### query\_audit\_trail()

Query the Trailproof audit trail with optional filters for event type and metadata fields.

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
def query_audit_trail(
    event_type: str | None = None,
    metadata: dict[str, Any] | None = None,
    limit: int | None = None,
) -> list[TrailEvent]
```

<ParamField path="event_type" type="str | None" default="None">
  Filter by event type (e.g. `"memproof.pipeline.committed"`).
</ParamField>

<ParamField path="metadata" type="dict[str, Any] | None" default="None">
  Filter by metadata fields (e.g. `{"operation_id": "op-abc123"}` or `{"tenant_id": "acme"}`).
</ParamField>

<ParamField path="limit" type="int | None" default="None">
  Maximum number of events to return.
</ParamField>

<ResponseField name="return" type="list[TrailEvent]">
  A list of Trailproof `TrailEvent` objects matching the query criteria.
</ResponseField>

#### Example

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
# All committed events for a tenant
events = mp.query_audit_trail(
    event_type="memproof.pipeline.committed",
    metadata={"tenant_id": "acme"},
    limit=50,
)

for event in events:
    print(f"{event.event_type} at {event.timestamp}")

# Full trace for a single operation
trace = mp.query_audit_trail(
    metadata={"operation_id": "op-abc123"},
)
```

***

## Scope and Context Flexibility

Every method that accepts `scope` or `context` parameters can receive either a Pydantic model instance or a plain dictionary. Memproof coerces dictionaries internally:

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
from memproof import MemoryScope, OperationContext

# Using model instances
scope = MemoryScope(tenant_id="acme", project_id="p1", agent_id="a1")
context = OperationContext(
    actor_type="agent",
    actor_id="a1",
    source="langgraph",
    timestamp="2026-01-15T10:30:00Z",
)
result = await mp.remember("hello", scope=scope, context=context)

# Using plain dicts (equivalent)
result = await mp.remember(
    "hello",
    scope={"tenant_id": "acme", "project_id": "p1", "agent_id": "a1"},
    context={
        "actor_type": "agent",
        "actor_id": "a1",
        "source": "langgraph",
        "timestamp": "2026-01-15T10:30:00Z",
    },
)
```

Both forms are fully supported and produce identical results.
