How Graphify Modules Communicate: The Dispatch-Based Architecture

Graphify modules communicate through a three-layer dispatch system embedded in the knowledge graph, where modules publish dispatch tables mapping symbols to handlers rather than calling code directly.

Graphify is an open-source knowledge graph generator that enables loose coupling between modules through symbolic dispatch. Unlike traditional direct function calls, Graphify modules communicate by dispatching requests through a centralized graph structure. This architecture allows modules to remain independent while sharing data through symbolic references rather than hard-coded dependencies.

The Three-Layer Dispatch Architecture

The dispatch mechanism operates across three distinct layers that translate symbolic requests into concrete handler execution.

Direct Dispatch with @dispatch Annotations

The first layer uses literal @dispatch annotations embedded in generated markdown blocks. When you run graphify install, the system inserts these blocks into skill documentation, creating explicit pointers to handler files.

According to the Graphify source code in README.md (lines 294-298), these dispatch slots allow platforms to insert their own handler references:

<!-- @@DISPATCH@@ -->
@dispatch: my_handler.md

Indirect Dispatch via AST Inference

The second layer infers dispatch relationships automatically during source code extraction. When the AST parser encounters imports, calls, or assignments that reference dispatchable symbols, it creates inferred edges in the graph.

The test suite in tests/test_indirect_dispatch.py (lines 46-86) validates that any import, call, or assignment generating a "dispatchable" symbol automatically creates an INFERRED edge of type dispatch in the global graph. This allows modules to follow edges to handlers without hard-coded imports.

Runtime Watch Dispatch

The third layer handles dynamic updates through the watch subsystem. Implemented in graphify/watch.py, the Watch class monitors file system events and triggers partial re-extraction by looking up dispatch entries for changed files. When graphify watch <path> detects a change, the system resolves the affected dispatch entry and runs only the relevant extractor, avoiding full rebuilds.

Core Components of the Dispatch System

Dispatch Tables

Each skill file maintains a dispatch table—a dictionary (dispatch: str | None) mapping logical names to markdown fragments containing handler code. This structure acts as the contract between modules, enforced by the graph-builder during extraction.

Indirect Dispatch Edges

During extraction, the graph builder adds edges of type dispatch between symbols. These edges, created in graphify/symbol_resolution.py, allow the assistant to follow connections from request to implementation without hard-coded imports. A module only needs to know the name of the data it wants, not the concrete implementation.

Watch-Based Dispatch

The Watch service enables incremental graph updates. When graphify watch <path> detects a file change, it resolves the file's dispatch entry and triggers a partial extraction so the graph stays up-to-date without a full rebuild.

Code Examples in Practice

Example 1: Registering a Dispatch Entry

Generated by graphify install, these markdown blocks create explicit dispatch registrations:

<!-- @@DISPATCH@@ -->
@dispatch: my_handler.md

Example 2: Indirect Dispatch in Python

When the extractor processes this code, it automatically creates dispatch edges:


# In module A

def do_work():
    return helper.process(data)   # `helper.process` becomes a dispatch edge

# In module B (the handler)

def process(data):
    # Actual implementation

    return data.processed

The extractor adds an edge A.do_work → B.process of type dispatch; any query requesting do_work automatically follows this edge to the implementation.

Example 3: Watching Directories and Dispatching on Change

from graphify.watch import Watch

watcher = Watch(path="src/")
watcher.start()   # On every file change, the watcher looks up its dispatch entry

When src/utils.py changes, the watch service finds the corresponding dispatch fragment (e.g., utils_extractor.md) and runs only that extractor, updating the graph incrementally.

Key Implementation Files

  • graphify/symbol_resolution.py: Contains the logic that resolves symbols to dispatch entries and builds dispatch → handler edges.
  • graphify/watch.py: Implements the Watch class for file system monitoring and runtime dispatch triggering.
  • tests/test_indirect_dispatch.py: Validates that indirect dispatch edges are correctly inferred from Python AST (lines 46-86).
  • README.md: Documents the dispatch slot syntax and platform-specific implementations (lines 294-298).

Summary

  • Graphify modules communicate through dispatch tables rather than direct function calls, enabling loose coupling between components.
  • The system supports three dispatch layers: direct annotation (@dispatch), AST-inferred edges, and runtime file watching.
  • Indirect dispatch edges are created automatically during extraction and validated in tests/test_indirect_dispatch.py.
  • The Watch class in graphify/watch.py enables incremental updates by resolving dispatch entries for changed files.
  • graphify/symbol_resolution.py handles the core symbol-to-handler resolution logic that makes the graph queryable.

Frequently Asked Questions

What is the difference between direct and indirect dispatch in Graphify?

Direct dispatch uses explicit @dispatch annotations in markdown blocks generated by graphify install, while indirect dispatch is automatically inferred from the AST during extraction. Indirect dispatch creates edges in the knowledge graph when code references symbols that have associated handlers, allowing the system to route requests without explicit registration.

How does the watch subsystem trigger module updates?

The watch subsystem, implemented in the Watch class in graphify/watch.py, monitors file system events for directories specified in graphify watch <path>. When a file changes, the system looks up the file's dispatch entry in the graph and triggers only the relevant extractor, enabling incremental graph updates without full rebuilds.

Where are dispatch edges stored in the Graphify knowledge graph?

Dispatch edges are stored as INFERRED edges of type dispatch in the global knowledge graph. These edges map symbols (function names, class names, file paths) to their handlers, and are created during AST extraction as validated in tests/test_indirect_dispatch.py.

How can I register a custom dispatch handler for my Graphify skill?

Register a custom handler by including a dispatch annotation in your skill's markdown documentation. When running graphify install, the system inserts <!-- @@DISPATCH@@ --> blocks containing @dispatch: handler_file.md pointers. These entries populate the dispatch table that other modules query when requesting your skill's data.

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 →