temporal-belief-graph
A lightweight Python package for modeling uncertain event orderings in narrative timelines, lore databases, historical reconstructions, and worldbuilding systems.
Instead of assuming every temporal relation is fixed, temporal-belief-graph represents event ordering as probabilistic belief edges and updates them as new evidence accumulates — using log-odds Bayesian updates that never reverse direction due to weak sources.
Why this exists
Most graph libraries treat edges as binary: A comes before B, or it does not.
Real-world narrative and lore data is messier. Multiple sources disagree. Evidence is partial. Some orderings are guesses.
temporal-belief-graph was built to handle exactly this:
- A story timeline where fan sources and official sources conflict
- A historical reconstruction where some events have uncertain sequencing
- A worldbuilding database where causality and temporal order must be separated
- Any system where "we think A happened before B, but we are not sure" needs to be expressed and updated over time
Installation
pip install temporal-belief-graph
Requires Python 3.10 or later. No external dependencies.
Quick start
from tbg import BeliefGraph, EventNode, PriorConfig
from tbg import BayesianUpdater, Evidence, Validator
from tbg import graph_to_json, graph_from_json
from tbg.report import graph_to_markdown, graph_to_mermaid
# 1. Configure the graph
config = PriorConfig(
default_p=0.5,
source_weights={"official_lore": 1.5, "fan_wiki": 0.7},
)
graph = BeliefGraph(prior_config=config)
# 2. Add events
graph.add_node(EventNode(id="kain_incident", label="Kain Incident", era="First Rift War"))
graph.add_node(EventNode(id="rift_opening", label="Rift Opening", era="First Rift War"))
# 3. Add an uncertain edge (p=0.5 means order is unknown)
graph.init_uniform("kain_incident", "rift_opening")
# 4. Update belief with evidence
updater = BayesianUpdater(graph)
updater.update_edge(
"kain_incident", "rift_opening",
Evidence(key="official_001", supports_forward=True, strength=0.9, source="official_lore"),
)
updater.update_edge(
"kain_incident", "rift_opening",
Evidence(key="fan_002", supports_forward=False, strength=0.6, source="fan_wiki"),
)
edge = graph.get_edge("kain_incident", "rift_opening")
print(edge.p_forward) # updated belief: P(kain_incident → rift_opening)
# 5. Explain the current belief state
print(updater.explain_edge("kain_incident", "rift_opening"))
# 6. Validate the graph
result = Validator().validate(graph)
print(result.is_valid)
print(result.warnings)
# 7. Export
graph_to_json(graph, "graph.json")
print(graph_to_mermaid(graph))
A full working example is available in examples/basic_usage.py.
Core concepts
EventNode
A single event in the graph. Every node carries an era — a concrete arc, chapter, or period name. Vague era labels like "present" or "past" are flagged by the validator.
EventNode(id="my_event", label="The Great Collapse", era="Third Age")
BeliefEdge
A directed edge from source_id to target_id carrying p_forward: the probability that the source event occurs before the target event.
p_forward |
Meaning |
|---|---|
0.5 |
No information — uniform prior |
0.9 |
Strong belief that source comes first |
0.1 |
Strong belief that target comes first |
BayesianUpdater
Updates edge probabilities using log-odds steps:
new_logit = old_logit + direction × strength × source_weight × learning_rate
p_new = sigmoid(new_logit)
Key property: a source with source_weight < 1.0 produces a smaller update in the same direction — it never flips the direction of evidence.
Ensemble update
When multiple sources each propose a p_forward value, ensemble_update combines them via weighted average before applying a single Bayesian step:
updater.ensemble_update(
"event_a", "event_b",
claims=[
(0.9, 1.5), # official source claims 0.9, weight 1.5
(0.6, 0.8), # secondary source claims 0.6, weight 0.8
(0.3, 0.5), # weak source claims 0.3, weight 0.5
],
)
Validator
Runs seven checks and returns a ValidationResult with errors and warnings:
| Check | Level |
|---|---|
pseudo_era — vague era label used |
error |
cycle — confirmed edges form a directed cycle |
error |
contradiction — two opposing edges both highly confident |
error |
missing_era — node has no era value |
warning |
missing_evidence — edge probability changed without evidence |
warning |
overconfident_edge — high probability with very few updates |
warning |
isolated_node — node has no incident edges |
warning |
result = Validator().validate(graph)
result.raise_if_errors() # raises ValueError if any errors exist
JSON export / import
from tbg import graph_to_json, graph_from_json
graph_to_json(graph, "graph.json")
restored = graph_from_json("graph.json")
Markdown and Mermaid report
from tbg.report import graph_to_markdown, graph_to_mermaid, save_markdown, save_mermaid
print(graph_to_markdown(graph)) # full Markdown report
print(graph_to_mermaid(graph)) # Mermaid flowchart diagram
save_markdown(graph, "report.md")
save_mermaid(graph, "diagram.mmd")
Package structure
tbg/
├── schema.py EventNode, BeliefEdge, EvidenceRecord, PriorConfig
├── graph.py BeliefGraph
├── bayesian.py BayesianUpdater, Evidence
├── validator.py Validator, ValidationResult
├── io.py graph_to_json, graph_from_json
└── report.py graph_to_markdown, graph_to_mermaid
examples/
└── basic_usage.py End-to-end example
docs/
└── model.md Mathematical model documentation
Design principles
Probabilistic by default. Every edge starts uncertain. Certainty is earned through accumulated evidence, not assumed.
Direction-safe updates. A weak source supporting forward always moves p_forward up — never down. Source weight controls magnitude, not direction.
Explainable history. Every probability update is recorded as an EvidenceRecord on the edge. You can always reconstruct why the current value is what it is.
No hard deletes. The graph is append-friendly. Contradictions are surfaced by the validator, not silently overwritten.
No external dependencies. Pure Python standard library only.
Development
Install the package in editable mode with development dependencies:
pip install -e ".[dev]"
Run the test suite:
pytest
Run tests across all supported Python versions:
tox
Build the package:
python -m build
This package is currently in alpha. APIs may change before version 1.0.0.
Contributing
Contributions, issues, and feature requests are welcome.
Please open an issue before submitting a pull request.
Contributors
| Handle | GitHub | Role |
|---|---|---|
| lajjadred | @lajjadred | Project lead |
| 이채문 | @CHML-real | Mathematical algorithm development |
| CUBE | @90cube | Idea proposal and data collection |
License
MIT License. See LICENSE for details.
Release files for temporal-belief-graph 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| temporal_belief_graph-0.1.3.tar.gz | 23.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| temporal_belief_graph-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.2 kB
Release files / temporal_belief_graph-0.1.3.tar.gz
| Download URL | temporal_belief_graph-0.1.3.tar.gz |
|---|---|
| Size | 23.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b400c6a9d10f35587e74a650a1dae18709127942e384e5d4305ddd1236fda40e
|
|
BLAKE2b-256 checksum How to use checksums |
82e9467e32ea1602447d1a45855e5931204ee3ef4b47892a2fb10107338d5936
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / temporal_belief_graph-0.1.3-py3-none-any.whl
| Download URL | temporal_belief_graph-0.1.3-py3-none-any.whl |
|---|---|
| Size | 17.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8abd1a9d4290041debb3b379281102ce5601905ee69f786fa80a7cff79d7499d
|
|
BLAKE2b-256 checksum How to use checksums |
4b958340a15ba68cefb11902bca6029846b88af7b061838500f92f9209146f5f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|