Skip to main content

py-context-graph

Extract, enrich, cluster, and query decisions from unstructured conversations using LLMs.

Tests PyPI Python License: MIT

Quick Start

pip install py-context-graph[all]
import asyncio
from decision_graph import LiteLLMAdapter
from decision_graph.backends.memory import InMemoryBackend
from decision_graph.backends.memory.stores import InMemoryGraphStore, InMemoryVectorIndex
from decision_graph.decision_trace_pipeline import DecisionTracePipeline

backend = InMemoryBackend()
pipeline = DecisionTracePipeline(
    backend=backend,
    executor=LiteLLMAdapter(),
    vector_index=InMemoryVectorIndex(),
    graph_store=InMemoryGraphStore(),
)

async def main():
    decisions = await pipeline.run_from_text(
        conv_text="Alice: We decided to switch from REST to GraphQL for the new API...",
        conv_id="standup-2024-01-15",
        gid="engineering-team",
        updated_at=1705334400.0,
        summary_pid="summary_standup-2024-01-15",
        query_gids=["engineering-team"],
    )
    print(f"Extracted {len(decisions)} decisions")

asyncio.run(main())

See it in Action

The examples/ directory includes sample conversations and an interactive viewer with dashboards, a cluster board, timeline, and force-directed graph.

cd examples
export OPENAI_API_KEY=sk-...   # or any LiteLLM-supported provider
python run.py                  # opens browser with live pipeline progress

Options: --port 9000, --no-browser, --model anthropic/claude-3.5-sonnet, or pass your own files (python run.py my_notes.txt).

What is this?

py-context-graph turns messy conversation text (meeting notes, Slack threads, standups) into a structured decision graph. It uses LLMs to:

  1. Extract decision items from text (what was decided, by whom, about what)
  2. Deduplicate near-identical decisions across conversations
  3. Enrich each decision with structured metadata (topics, entities, constraints, key facts)
  4. Cluster related decisions across conversations into coherent themes
  5. Materialize the result into a queryable graph
Text → Extract (LLM) → Persist → Deduplicate → Enrich (LLM) → Cluster → Graph

Install

pip install py-context-graph

With optional backends:

pip install py-context-graph[all]       # LiteLLM + Firestore + in-memory vector index
pip install py-context-graph[llm]       # LiteLLM adapter only
pip install py-context-graph[firestore] # Google Cloud Firestore backend
pip install py-context-graph[memory]    # In-memory TF-IDF vector index (pandas)

Usage

import asyncio
from decision_graph import DecisionGraph, LiteLLMAdapter
from decision_graph.backends.memory import InMemoryBackend
from decision_graph.backends.memory.stores import InMemoryGraphStore, InMemoryVectorIndex
from decision_graph.decision_trace_pipeline import DecisionTracePipeline

backend = InMemoryBackend()
pipeline = DecisionTracePipeline(
    backend=backend,
    executor=LiteLLMAdapter(),
    vector_index=InMemoryVectorIndex(),
    graph_store=InMemoryGraphStore(),
)

async def main():
    # Process a conversation
    decisions = await pipeline.run_from_text(
        conv_text="Alice: We decided to switch from REST to GraphQL for the new API...",
        conv_id="standup-2024-01-15",
        gid="engineering-team",
        updated_at=1705334400.0,
        summary_pid="summary_standup-2024-01-15",
        query_gids=["engineering-team"],
    )

    # Query the results
    dg = DecisionGraph(backend=backend, executor=LiteLLMAdapter())
    service = dg.graph_service()
    result = await service.get_enrichments_and_projections_joined(
        group_ids=["engineering-team"]
    )
    print(f"Found {result['total_joined']} enriched decisions")

asyncio.run(main())

Key concepts

The four protocols

py-context-graph is built around pluggable interfaces. You only implement what you need:

Protocol Purpose Bundled implementations
StorageBackend Groups 4 document stores (enrichments, projections, clusters, links) InMemoryBackend, FirestoreBackend
LLMAdapter Executes LLM calls for extraction and enrichment LiteLLMAdapter (supports OpenAI, Anthropic, and any LiteLLM provider)
VectorIndex Similarity search for cross-conversation clustering InMemoryVectorIndex (TF-IDF + cosine)
GraphStore Write-only sync of hydrated clusters to a graph DB InMemoryGraphStore, NullGraphStore

DecisionGraph facade

The main entry point. Wire a backend and LLM adapter, then access services:

from decision_graph import DecisionGraph

dg = DecisionGraph(backend=my_backend, executor=my_llm)
service = dg.graph_service()        # query enrichments, projections, clusters
retrieval = dg.retrieval()          # filtered queries over enrichments
clusterer = dg.cluster_service()    # cluster management

DecisionTracePipeline

The end-to-end processing pipeline. Feed it text, get structured decisions:

from decision_graph.decision_trace_pipeline import DecisionTracePipeline

pipeline = DecisionTracePipeline(
    backend=backend,
    executor=llm_adapter,
    vector_index=vector_index,    # optional, enables cross-conversation clustering
    graph_store=graph_store,      # use NullGraphStore() to skip graph materialization
)

# From raw text
decisions = await pipeline.run_from_text(conv_text=text, conv_id="c1", gid="g1", ...)

# From pre-extracted decision items
decisions = await pipeline.run(decision_items=[...], conv_id="c1", gid="g1", ...)

Context Graph (query layer)

For querying the materialized graph (requires a GraphReader implementation, e.g. Neo4j):

from decision_graph.context_graph.service import ContextGraphService

ctx = ContextGraphService(reader=my_graph_reader)
result = await ctx.query(text="What decisions were made about the API?", mode="chat")

Bring your own backend

Implement StorageBackend to use any database:

from decision_graph.core.registry import StorageBackend
from decision_graph.core.interfaces import EnrichmentStore, ProjectionStore, ClusterStore, LinkStore

class PostgresBackend(StorageBackend):
    def enrichment_store(self) -> EnrichmentStore: ...
    def projection_store(self) -> ProjectionStore: ...
    def cluster_store(self) -> ClusterStore: ...
    def link_store(self) -> LinkStore: ...

Each store protocol is defined in decision_graph.core.interfaces with clear method signatures.

Bring your own LLM

Implement the LLMAdapter protocol:

from decision_graph.core.interfaces import LLMAdapter

class MyLLMAdapter(LLMAdapter):
    async def execute_async(self, model_config, data, additional_data=None):
        # Call your LLM, return parsed result
        ...

Project structure

src/decision_graph/
├── __init__.py                  # Public API: DecisionGraph, LLMAdapter, LLMConfig, LiteLLMAdapter
├── graph.py                     # DecisionGraph facade
├── decision_trace_pipeline.py   # End-to-end pipeline
├── extraction_service.py        # LLM-based decision extraction
├── enrichment_service.py        # LLM-based decision enrichment
├── clustering_service.py        # Decision clustering
├── retrieval.py                 # Query/filter over enrichments
├── context_retrieval.py         # Vector-based context retrieval
├── services.py                  # DecisionGraphService (joins, hydration)
├── ingestion.py                 # Graph materialization helpers
├── visualization.py             # vis.js graph builder
├── markdown_chunker.py          # Split markdown by headings
├── core/
│   ├── interfaces.py            # Protocol definitions
│   ├── registry.py              # StorageBackend ABC
│   ├── domain.py                # Pydantic models
│   ├── config.py                # LLMConfig
│   └── matching.py              # Dedup, scoring, similarity
├── llm/
│   └── litellm_adapter.py       # LiteLLM-based LLMAdapter
├── backends/
│   ├── memory/                  # In-memory stores + TF-IDF vector index
│   └── firestore/               # Google Cloud Firestore stores
├── context_graph/               # Graph query layer (planner, templates, post-processing)
└── prompts/                     # LLM prompt templates

Development

A Makefile is included for common tasks. Run make to see all available targets:

make                # show all targets
make install-dev    # create venv + install with dev dependencies
make test           # run tests
make test-verbose   # run tests with verbose output
make test-cov       # run tests with coverage (opens HTML report)
make build          # build distribution packages
make clean          # remove build artifacts and caches
make clean-all      # remove build artifacts, caches, and venv

Contributing

Contributions are welcome. Please open an issue first to discuss what you'd like to change.

git clone https://github.com/ResearchifyLabs/py-context-graph.git
cd py-context-graph
make install-dev
make test

License

MIT

Metadata

Release files for py-context-graph 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for py-context-graph 0.1.2
File Size Uploaded Provenance
py_context_graph-0.1.2.tar.gz 92.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for py-context-graph 0.1.2
File Interpreter ABI Platform
py_context_graph-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 149.8 kB

Release files / py_context_graph-0.1.2.tar.gz

Download URL py_context_graph-0.1.2.tar.gz
Size 92.8 kB
Tags Source
SHA-256 checksum
How to use checksums
dac693f530a6c4a78c00bb32d966f4338556a8ca747169d6b7df08b07670a7c8
BLAKE2b-256 checksum
How to use checksums
2a347aea0082d4a6c32555d921422b37e6702dcdb26568efe0505fa2b80e283a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.

Transparency log

Release files / py_context_graph-0.1.2-py3-none-any.whl

Download URL py_context_graph-0.1.2-py3-none-any.whl
Size 57.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
76ed60c766a4eeba913471b81ad7ed74cbf23d1f773c78ffb81b02a1688023aa
BLAKE2b-256 checksum
How to use checksums
5325885e97b780f1c493ae37d98fab1276546406b6982b260d0ee3ad5f07a5f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.

Transparency log

Security for py-context-graph 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for py_context_graph-0.1.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page