How to Implement Causal Decision Chain Analysis and Impact Analysis in Semantica

You implement causal decision chain analysis and impact analysis in Semantica by building a causal knowledge graph in ContextGraph, traversing it via get_causal_chain(), and optionally enriching results with the LLM-driven CausalChainAnalyzer.

Semantica treats every decision as a node inside a persistent knowledge graph called the ContextGraph. Edges between nodes capture causal semantics—such as CAUSED, INFLUENCED, or PRECEDENT_FOR—and the system supports both pure-graph traversal and LLM-augmented reasoning to analyze chains and impacts. According to the semantica-agi/semantica source code, the implementation is split between graph storage, an optional analyzer wrapper, and an MCP tool endpoint.

How Semantica Models Decisions and Causality

In semantica/context/context_graph.py, the ContextGraph class persists decision nodes and their causal edges in a pluggable vector store. When a decision is recorded—typically via semantica.context.decision_recorder.DecisionRecorder—the graph stores metadata such as the decision ID, description, and provenance.

Building the Causal Graph

Adding Decisions and Relationships

To construct a chain, first add decisions to the graph, then link them with causal relationships. The following example shows a simple three-node chain in pure Python:

from semantica.context.context_graph import ContextGraph

g = ContextGraph()

# Create causal edges: d_root -> d_child -> d_grandchild

g.add_causal_relationship("d_root", "d_child", "CAUSED")
g.add_causal_relationship("d_child", "d_grandchild", "CAUSED")

In production, these calls are usually made by DecisionRecorder as decisions are ingested. The underlying storage backend—whether SQLite, PG-Vector, Pinecone, or FAISS—is abstracted behind the graph API, so the causal-chain logic remains identical across environments.

Querying Causal Chains

Semantica provides two ways to retrieve a causal chain: a pure-graph traversal method on ContextGraph and an optional LLM-driven wrapper in CausalChainAnalyzer.

Pure-Graph Traversal with ContextGraph

The core method is ContextGraph.get_causal_chain(), defined in semantica/context/context_graph.py. It accepts a node_id, a direction ("upstream" or "downstream"), and a max_depth parameter.

downstream = g.get_causal_chain(
    node_id="d_root",
    direction="downstream",
    max_depth=5,
)

# downstream -> ["d_child", "d_grandchild"]

If the analyzer layer is unavailable, the MCP endpoint falls back directly to this method. The tests in tests/test_030_context_graph_realworld_extended.py verify upstream and downstream behavior, depth limits, and graceful handling of missing nodes.

LLM-Enhanced Analysis with CausalChainAnalyzer

When an LLM integration is configured, semantica/context/causal_analyzer.py exposes CausalChainAnalyzer.get_causal_chain(). This wrapper can augment the returned chain with narrative explanations, confidence scores, and suggested mitigation actions before returning the final result.

The analyzer follows the same signature—node_id, direction, max_depth—so it acts as a drop-in replacement for the pure-graph implementation. If the LLM path fails or is not configured, the system falls back to ContextGraph.get_causal_chain().

Performing Impact Analysis

Impact analysis is a direct application of causal chain traversal. Downstream nodes represent decisions impacted by the starting node, while upstream nodes represent prerequisites. End-to-end examples in tests/test_030_realworld_comprehensive.py demonstrate how a supply-disruption decision propagates through inventory draw-down and price-increase decisions.

After retrieving a chain, you can enumerate the affected decisions and inspect their payloads:

chain = g.get_causal_chain("supply_disruption", direction="downstream", max_depth=5)
impacted = [g.get_decision(dec_id) for dec_id in chain]

for d in impacted:
    print(f"Impacted: {d.decision_id} – {d.description}")

For richer reporting, ContextGraph.trace_decision_causality() returns a list of causal paths rather than a flat list of IDs. Use this when you need to visualize branch points, measure blast radius, or identify bottleneck decisions in the graph.

MCP Endpoint for Decision Chains

The public interface for causal chain queries is handle_get_causal_chain in semantica/mcp/tools/decisions.py. The orchestration flow is:

  1. Extract decision_id, direction, and max_depth from the request payload.
  2. Instantiate CausalChainAnalyzer if the LLM integration is present.
  3. Call analyzer.get_causal_chain(node_id, direction, max_depth).
  4. On failure, fall back to graph.get_causal_chain(...).
  5. Wrap the resulting ID list or decision objects in a consistent JSON response.

A typical call through the MCP tool looks like this:

from semantica.mcp.tools.decisions import handle_get_causal_chain

payload = {"decision_id": "dec_101", "direction": "upstream", "max_depth": 3}
response = handle_get_causal_chain(payload)

# response -> {"causal_chain": ["dec_099", "dec_100"], "status": "ok"}

This endpoint is exercised in tests/test_mcp_decisions_causal_chain.py, which covers both the LLM-enabled path and the pure-graph fallback.

Summary

  • Store causality in ContextGraph using add_causal_relationship() and add_decision() inside semantica/context/context_graph.py.
  • Traverse chains with ContextGraph.get_causal_chain(), specifying direction and max_depth to control scope.
  • Enable LLM reasoning by instantiating CausalChainAnalyzer from semantica/context/causal_analyzer.py without changing the traversal API.
  • Analyze impact by inspecting downstream chains, or use trace_decision_causality() for full path reporting.
  • Expose the logic through handle_get_causal_chain in semantica/mcp/tools/decisions.py for MCP-compatible requests.

Frequently Asked Questions

What storage backends does Semantica support for causal graphs?

Semantica abstracts the vector store behind ContextGraph, so you can use SQLite, PG-Vector, Pinecone, FAISS, or other compatible backends. The causal-chain query logic in get_causal_chain() remains identical regardless of which storage layer you choose, letting you swap backends without touching analysis code.

How does Semantica handle missing decisions during chain traversal?

The pure-graph traversal in ContextGraph.get_causal_chain() gracefully handles absent nodes. The integration tests in tests/test_030_context_graph_realworld_extended.py explicitly verify traversal behavior when nodes in the requested path do not exist.

Can I use causal decision chain analysis without an LLM?

Yes. The CausalChainAnalyzer is optional. If it is not configured or its call fails, the MCP endpoint and other consumers automatically fall back to ContextGraph.get_causal_chain(), which performs fast, deterministic graph traversal without LLM calls.

What is the difference between get_causal_chain() and trace_decision_causality()?

ContextGraph.get_causal_chain() returns a flat list of decision IDs reachable from a starting node, while trace_decision_causality() returns a list of full causal paths. Use the former for simple enumeration and the latter for detailed impact visualization or branch-point analysis.

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 →