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 theKnowledgeGraphclass, schema management, and_temporal_filter_sqllogic for interval queries.mempalace/config.py: Providessanitize_iso_temporalfor validating and normalizing all temporal strings used by the knowledge graph.mempalace/ids.py: Generates deterministic IDs viamake_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_totimestamps managed byKnowledgeGraphinknowledge_graph.py. - Date-only strings automatically expand to midnight UTC boundaries, while full UTC datetimes pass through unchanged via
sanitize_iso_temporal. add_triplecreates facts with temporal windows;invalidatecloses them by settingvalid_to.query_entityandquery_relationshipsupport point-in-time retrieval using theas_ofparameter, internally filtering via_temporal_filter_sql.- Omitting
valid_tocreates indefinitely valid facts; omittingas_ofqueries 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →