How to Use ContextGraph for Decision Recording and Tracing in Semantica
The ContextGraph class provides built-in record_decision() and trace_decision_causality() methods to capture structured decision metadata and traverse causal relationships through breadth-first search.
The ContextGraph is the core knowledge structure in semantica-agi/semantica that enables agentic systems to maintain an auditable history of choices. This guide demonstrates how to use ContextGraph for decision recording and tracing, with direct references to the implementation in [semantica/context/context_graph.py](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py).
Creating a ContextGraph with Decision Support
Before recording decisions, initialize a ContextGraph with optional analytics enabled. The constructor accepts flags for centrality analysis, community detection, and node embeddings—all useful for later exploration of decision clusters.
from semantica.context import ContextGraph
graph = ContextGraph(
advanced_analytics=True,
centrality_analysis=True,
community_detection=True,
node_embeddings=True,
)
These settings activate knowledge graph algorithms that power similarity searches and precedent discovery discussed later.
Recording Decisions with record_decision()
The record_decision() method (lines 4334–4369 in [context_graph.py](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py)) creates a persistent decision node with comprehensive metadata.
Method Signature and Validation
def record_decision(
self,
category: str,
scenario: str,
reasoning: str,
outcome: str,
confidence: float,
entities: Optional[List[str]] = None,
decision_maker: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
valid_from: Optional[Union[str, datetime]] = None,
valid_until: Optional[Union[str, datetime]] = None,
**kwargs
) -> str:
The implementation performs strict input validation (lines 4334–4348):
- Required fields:
category,scenario,reasoning,outcome, andconfidenceare checked for type, length constraints, and valid value ranges - Temporal normalization:
valid_fromandvalid_untilpass through_normalize_temporal_input()(lines 4327–4332), converting to tz-naive UTC ISO strings - UUID generation: Each decision receives a unique identifier with attached timestamp (lines 4349–4350)
Internal Graph Insertion
The private helper _add_decision_to_graph() (lines 4448–4664) handles three critical indexing operations:
- Node creation: Stores the decision with type
"decision"containing all validated fields - Index updates: Maintains
_decision_index,_entity_index, and_temporal_indexfor fast lookups - Entity linking: Creates edges between the decision node and any referenced entities
Complete Recording Example
decision_id = graph.record_decision(
category="fraud_detection",
scenario="Multiple failed login attempts from new device",
reasoning="IP address flagged in threat intelligence blacklist",
outcome="account_blocked",
confidence=0.98,
entities=["user_42", "ip_203.0.113.5", "device_mobile_android"],
decision_maker="security_automation_engine",
metadata={"alert_severity": "critical", " threat_intel_source": "MISP"},
valid_from="2024-09-01T00:00:00",
valid_until="2025-09-01T00:00:00",
)
print(f"Decision recorded with ID: {decision_id}")
# Output: 550e8400-e29b-41d4-a716-446655440000
The returned UUID serves as the stable anchor for all subsequent tracing and linking operations.
Building Causal Chains Between Decisions
Decisions gain explanatory power through relationships. The ContextGraph supports canonical causal edge types defined in _CAUSAL_EDGE_TYPES and _CAUSAL_EDGE_ALIASES.
Adding Causal Relationships
Use add_edge() with causal edge types to express influence:
# Link a precedent decision as direct cause
graph.add_edge(
source_id=previous_decision_id,
target_id=decision_id,
edge_type="CAUSED",
weight=1.0,
metadata={"causal_strength": "definitive"}
)
# Or express partial influence
graph.add_edge(
source_id="risk_model_v3_assessment_001",
target_id=decision_id,
edge_type="INFLUENCED",
weight=0.75,
)
Supported causal edge types include CAUSED, INFLUENCED, ENABLED, PREVENTED, and their aliases—enabling nuanced provenance modeling.
Tracing Decision Causality with trace_decision_causality()
The trace_decision_causality() method (lines 4696–4738) reconstructs the full causal history of any decision through breadth-first search.
Method Signature
def trace_decision_causality(
self,
decision_id: str,
limit: Optional[int] = None,
depth: int = 5,
include_entities: bool = True
) -> List[Dict[str, Any]]:
Tracing Behavior
- Search scope: Follows only edges whose type appears in
_CAUSAL_EDGE_TYPESor_CAUSAL_EDGE_ALIASES - Traversal direction: Backward from target to sources (provenance), with configurable
depth(default 5 hops) - Result enrichment: Each returned dictionary contains
source,target,type,weight,hop, and timestamp fields - Entity integration: When
include_entities=True, adjacent entity nodes enrich the trace with contextual information
Practical Tracing Example
# Retrieve full causality chain
trace = graph.trace_decision_causality(
decision_id=decision_id,
depth=4,
limit=50,
include_entities=True
)
print("Causality trace:")
for hop in trace:
print(f" [{hop['hop']}] {hop['source']} → {hop['target']}")
print(f" Edge: {hop['type']} (weight: {hop.get('weight', 1.0)})")
if 'timestamp' in hop:
print(f" Time: {hop['timestamp']}")
This produces a traversable audit trail showing every decision and entity that contributed to the final outcome.
Finding Decision Precedents
Beyond explicit causal tracing, the ContextGraph supports semantic precedent discovery through find_precedents() and find_precedents_by_scenario(). These methods leverage:
- Vector similarity: Embedding-based matching of scenario descriptions
- Entity overlap: Shared entities between past and current decisions
- Category clustering: Decisions from the same functional domain
Locate these utilities in the same [context_graph.py](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py) file, typically after the core traversal methods.
End-to-End Decision Workflow
from semantica.context import ContextGraph
# Initialize
graph = ContextGraph(advanced_analytics=True, node_embeddings=True)
# Stage 1: Record initial risk assessment
risk_decision = graph.record_decision(
category="risk_assessment",
scenario="Failed security challenge",
reasoning="Behavioral biometrics anomaly detected",
outcome="elevated_risk_score",
confidence=0.87,
entities=["session_abc123", "user_42"],
decision_maker="risk_engine_v2",
)
# Stage 2: Record follow-up action, causally linked
block_decision = graph.record_decision(
category="access_control",
scenario="Elevated risk score triggered step-up auth",
reasoning="Risk score exceeded dynamic threshold",
outcome="session_terminated",
confidence=0.95,
entities=["session_abc123", "user_42"],
decision_maker="access_policy_engine",
)
# Establish causality
graph.add_edge(
source_id=risk_decision,
target_id=block_decision,
edge_type="CAUSED",
weight=1.0
)
# Stage 3: Trace complete provenance
audit_trail = graph.trace_decision_causality(block_decision, depth=3)
print(f"\nFull audit for {block_decision[:8]}...")
for entry in audit_trail:
print(f" Hop {entry['hop']}: {entry['type']} from {entry['source'][:8]}")
MCP Tool Integration
The repository provides higher-level wrappers in [semantica/mcp/tools/decisions.py](https://github.com/semantica-agi/semantica/blob/main/semantica_mcp/mcp/tools/decisions.py) that expose record_decision as an MCP tool for multi-context processor environments. Similarly, [semantica/mcp/tools/graph.py](https://github.com/semantica-agi/semantica/blob/main/semantica_mcp/mcp/tools/graph.py) wraps causal edge operations for remote graph manipulation.
Source Reference Summary
| Component | Location | Purpose |
|---|---|---|
| Core decision recording | [semantica/context/context_graph.py](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py) lines 4334–4664 |
record_decision() and _add_decision_to_graph() |
| Causality tracing | [semantica/context/context_graph.py](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py) lines 4696–4738 |
trace_decision_causality() BFS implementation |
| MCP decision tools | [semantica/mcp/tools/decisions.py](https://github.com/semantica-agi/semantica/blob/main/semantica_mcp/mcp/tools/decisions.py) |
Exposed tool interface |
| MCP graph tools | [semantica/mcp/tools/graph.py](https://github.com/semantica-agi/semantica/blob/main/semantica_mcp/mcp/tools/graph.py) |
Edge manipulation helpers |
| Integration tests | [tests/vector_store/test_end_to_end_decision_tracking.py](https://github.com/semantica-agi/semantica/blob/main/tests/vector_store/test_end_to_end_decision_tracking.py) |
Workflow validation |
Summary
record_decision()creates validated, indexed decision nodes with UUIDs, temporal bounds, and entity referencestrace_decision_causality()performs controlled BFS across causal edges to reconstruct decision provenance- Causal edge types (
CAUSED,INFLUENCED, etc.) enable fine-grained modeling of decision relationships - Dual indexing (
_decision_index,_temporal_index) ensures efficient retrieval at scale - MCP tooling exposes these capabilities to external agent orchestration systems
Frequently Asked Questions
What makes a recorded decision retrievable for tracing?
The record_decision() method automatically indexes decisions in _decision_index by UUID, _entity_index by referenced entities, and _temporal_index by validity period. Without these indexes, trace_decision_causality() could not efficiently locate starting nodes or traverse relationships. The implementation guarantees O(1) UUID lookups and O(n) traversal bounded by depth and limit parameters.
How does temporal validation work for decisions?
The _normalize_temporal_input() helper (lines 4327–4332) converts valid_from and valid_until to standardized tz-naive UTC ISO strings. This normalization ensures consistent comparisons during temporal range queries and prevents timezone-related provenance errors. Invalid or malformed temporal inputs raise ValueError before any graph mutation occurs.
Can I trace forward from a decision to its effects?
The current trace_decision_causality() implementation traverses backward (provenance direction) following incoming causal edges. To trace forward effects, you would either reverse the edge direction in the search or construct an inverse index of outgoing edges. The underlying graph structure in NetworkX supports both directions—adapt the BFS logic in a subclass or wrapper for downstream impact analysis.
What confidence threshold should I set for decision recording?
The confidence parameter accepts any float in [0.0, 1.0] with no enforced minimum threshold in the core implementation. However, downstream analytics in find_precedents() and similarity scoring may weight decisions by confidence. The integration tests in [test_end_to_end_decision_tracking.py](https://github.com/semantica-agi/semantica/blob/main/tests/vector_store/test_end_to_end_decision_tracking.py) demonstrate filtering precedent searches by confidence ≥ 0.7 for high-reliability historical matching.
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 →