How to Use the Knowledge Graph with Temporal Validity Windows in MemPalace

MemPalace implements a temporal entity-relationship graph on top of SQLite where each fact (triple) stores optional valid_from and valid_to timestamps, enabling you to query the exact state of knowledge at any specific point in time using the as_of parameter.

The MemPalace repository provides a sophisticated temporal knowledge graph that moves beyond static fact storage to capture when information is true. By defining validity windows for every triple in mempalace/knowledge_graph.py, the system supports historical queries, temporal reasoning, and fact invalidation while maintaining backward compatibility with legacy data.

Understanding Temporal Validity Windows

MemPalace models knowledge as time-bound facts. Each triple (subject → predicate → object) exists within a temporal window defined by:

  • valid_from: The timestamp when the fact becomes true (required)
  • valid_to: The timestamp when the fact ceases to be true (optional; NULL indicates currently valid)

The graph automatically normalizes temporal inputs using sanitize_iso_temporal from mempalace/config.py. Date-only strings like 2025-01-01 expand to 2025-01-01T00:00:00Z for comparisons, while full UTC datetime strings pass through verbatim.

Initializing the Knowledge Graph

Create a KnowledgeGraph instance to establish the SQLite backend. The constructor accepts an optional custom database path; otherwise, it defaults to ~/.mempalace/knowledge_graph.sqlite3.

from mempalace.knowledge_graph import KnowledgeGraph

# Initialize with default location

kg = KnowledgeGraph()

# Or specify a custom database path

# kg = KnowledgeGraph(db_path="/tmp/my_kg.sqlite3")

Adding Facts with Temporal Boundaries

Use add_triple to insert facts with explicit validity periods. The method validates and normalizes all temporal strings before storage.

Adding Open-Ended Facts

For facts with no defined end date, omit the valid_to parameter:


# A person's birth date (valid from a specific date, ongoing)

kg.add_triple(
    subject="Alice",
    predicate="born_on",
    obj="1990-05-12",
    valid_from="1990-05-12"  # Internally stored as 1990-05-12T00:00:00Z

)

# An ongoing hobby with no expiration

kg.add_triple(
    subject="Bob",
    predicate="loves",
    obj="chess",
    valid_from="2025-01-01"
)

Adding Time-Bounded Facts

Specify both valid_from and valid_to for temporary relationships:


# A project active between specific dates

kg.add_triple(
    subject="ProjectX",
    predicate="active",
    obj="true",
    valid_from="2023-07-01",
    valid_to="2024-03-15"
)

Querying Facts at Specific Points in Time

The query_entity method supports temporal filtering through the as_of parameter, which triggers the internal _temporal_filter_sql mechanism.

Point-in-Time Queries

Retrieve only the facts that were valid at a specific moment:


# What was true about Alice on 1995-01-01?

facts_1995 = kg.query_entity("Alice", as_of="1995-01-01")
print(facts_1995)

# Returns the 'born_on' triple because the interval covers that date

# Check ProjectX status during its active period

facts_jan2024 = kg.query_entity("ProjectX", as_of="2024-01-01")
print(facts_jan2024)

# Includes the 'active' fact (still within valid window)

Current State Queries

Omit as_of to retrieve only currently valid facts (where valid_to is NULL):


# Current facts only (no temporal filter applied)

current_facts = kg.query_entity("Bob")
print(current_facts)

# Shows 'loves' relationship because valid_to is NULL

Internally, the query layer converts stored date-only values to comparable UTC strings using _temporal_start_key and _temporal_end_key to ensure accurate interval containment checks.

Invalidating Facts to Close Validity Windows

Use invalidate to mark a fact as no longer true. This method sets the valid_to timestamp while validating that the end date never predates the existing valid_from.


# Bob stopped loving chess on 2026-02-01

kg.invalidate(
    subject="Bob",
    predicate="loves",
    obj="chess",
    ended="2026-02-01"
)

# Verify the fact no longer appears after that date

expired_check = kg.query_entity("Bob", as_of="2027-01-01")
print(expired_check)  # Empty; the triple is expired

Querying Relationships Temporally

The query_relationship method applies the same temporal filtering to specific predicates:


# Find all projects active as of a specific date

active_facts = kg.query_relationship("active", as_of="2023-12-31")
print(active_facts)  # Returns projects valid at that moment

Key Implementation Files

The temporal functionality spans several core files in the MemPalace repository:

  • mempalace/knowledge_graph.py: Core implementation containing the KnowledgeGraph class, schema management, and _temporal_filter_sql logic for interval queries.
  • mempalace/config.py: Provides sanitize_iso_temporal for validating and normalizing all temporal strings used by the knowledge graph.
  • mempalace/ids.py: Generates deterministic IDs via make_triple_id, ensuring uniqueness across temporal inserts and updates.
  • tests/test_knowledge_graph.py: Comprehensive test suite validating temporal window behaviors including addition, querying, and invalidation operations.

Summary

  • MemPalace stores facts in SQLite with explicit valid_from/valid_to timestamps managed by KnowledgeGraph in knowledge_graph.py.
  • Date-only strings automatically expand to midnight UTC boundaries, while full UTC datetimes pass through unchanged via sanitize_iso_temporal.
  • add_triple creates facts with temporal windows; invalidate closes them by setting valid_to.
  • query_entity and query_relationship support point-in-time retrieval using the as_of parameter, internally filtering via _temporal_filter_sql.
  • Omitting valid_to creates indefinitely valid facts; omitting as_of queries only currently valid facts.

Frequently Asked Questions

What happens if I omit the valid_to parameter when adding a fact?

The fact receives a NULL valid_to value in the database, indicating it remains valid indefinitely. When querying without an as_of timestamp, the system returns only these open-ended facts, while temporal queries include them if the as_of date falls after their valid_from timestamp.

How does MemPalace handle timezone-aware timestamps in validity windows?

According to config.py, the sanitize_iso_temporal function processes date-only strings by appending T00:00:00Z (midnight UTC), while full UTC datetime strings are preserved verbatim. The system standardizes on UTC for all internal comparisons to ensure consistent temporal filtering across different input formats.

Can I query for facts that were valid during an entire date range rather than a single point?

The current implementation in knowledge_graph.py supports only point-in-time queries via the as_of parameter. To find facts valid across a range, you would need to execute multiple point-in-time queries or retrieve all facts for the entities involved and perform interval intersection logic in your application code.

What validation prevents creating facts that end before they begin?

The invalidate method explicitly checks that the supplied ended timestamp (which becomes valid_to) does not predate the existing valid_from timestamp stored for that triple. This temporal consistency check ensures the validity window always represents a logical forward-moving time interval.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →