Graphite Deep Dive — Event Driven Workflow
Graphite is an open-source framework for building domain-specific AI assistants using composable agentic workflows. Please check our post for more detail. In this post we will dive into Graphite event driven architecture.
Event-driven architecture is at the heart of Graphite, empowering flexible, modular workflows that can adapt to complex business requirements. By leveraging publish/subscribe (pub/sub) patterns, Graphite orchestrates node execution in a way that gracefully handles everything from simple linear flows to branching and cyclical dependencies — all while ensuring the correct sequence of messages for large language models (LLMs) and other downstream tasks.
The Benefits of Event Driven Architecture
In traditional, coupled workflows, tasks often execute in a fixed sequence: when one step finishes, the next begins. By contrast, event-driven systems allow any component to “publish” an event, while interested “subscribers” automatically respond. This approach delivers significant advantages:
- Flexibility: Add or remove nodes and branches without re-engineering the entire flow.
- Scalability: Efficiently handle complex interactions with multiple data sources, functions or AI services.
- Modularity: Encapsulate functionality in discrete nodes that each listen for specific events and publish their results.
To harness these benefits, Graphite uses concept of Topics — queues that store messages in the FIFO pattern. This design offers a clear, auditable trail of each event passing through your workflow, simplifying both debugging and compliance in complex systems.
Inside Graphite’s Event Driven Architecture
Graphite’s event-driven workflow consists of four primary components:
- Topic: the message queues
- Node: the processing unit
- Event: the records of every state change
- Event Store: the durable log of all events
Below is an example showing a node’s execution lifecycle and the sequence of events it generates.
Next, we’ll examine the Topic and Node components — alongside pub and sub events — to illustrate how Graphite’s event-driven workflow operates.
Topic
Under the hood, each Topic
is like a temporary, in-memory event queue that lasts for the duration of a single request, with a map which store the consume offset of each consumers.
At the start of each request, Graphite initializes its assistant Topics
. Every incoming message—encapsulated as a PublishToTopicEvent
—is appended to the appropriate Topic (subject to a customizable publish condition) message queue. A node consumed from a topic will produce ConsumeFromTopicEvent
. Under the hood, Graphite’s Topic
class maintains, for each consumer node, a map of consumed offsets so it always knows which messages have been processed and which are still pending.
By using the execution_context
, topic_name
, and offset
fields from PublishToTopicEvent
and ConsumeFromTopicEvent
, Graphite can rebuild Topic of unfinished assistant request by restoring its message queue from the event store. When a workflow must be resumed, Graphite reinstates the Topic
with the exact offsets so it picks up precisely where it left off.
Node
In Graphite, a node is an execution unit that subscribes to one or more input (“sub”) topics and publishes results to one or more output (“pub”) topics. Each node encapsulates its subscription logic — the subscribe_to
condition—which determines exactly when it should trigger. Here is the code example of the subscribe_to
condition
SubscriptionBuilder()
.subscribed_to(agent_input_topic)
.or_()
.subscribed_to(human_request_topic)
.build()
Once triggered, the node:
- Consumes events from its subscribed topics
- Processes those events
- Publishes the resulting events to its output topics
Those newly published events can then trigger downstream nodes that subscribe to the same topics.
Below is an illustration of a single node with its corresponding sub- and pub-topics in Graphite’s event-driven workflow. Whenever new events arrive on a topic, the workflow evaluates each subscribing node’s subscribe_to
condition; if the condition is satisfied, that node is added to the execution queue.
Once a node completes execution, the workflow publishes its response to the downstream topics. Within each Topic object, the topic’s publish condition is evaluated to determine whether the incoming message should be accepted or ignored.
In the next section, we’ll explore strategies for resolving circular dependencies between nodes, as well as best practices for preserving a complete, queryable history of all messages as they flow through your workflow.
Handling History and Circular Flows
AI systems, particularly those involving LLMs, often require loop of “reasoning”. For instance, in a ReAct agent workflow, an LLM-based “Thought”, “Action“ and “Observe“ nodes might repeatedly query in a loop (“Reasoning → acting → observing -> reasoning…”) before finalizing an answer.
This can create loops and branching flows that make it tricky to maintain a coherent memory or message history. Graphite solves this with time travel and time-weighted topology sort.
Time Travel
Even with multiple loops or cycles, events in Graphite can be “stretched“ as a “Directed Acyclic Graph (DAG)“. By tracking each event’s offset and storing them in Topics, Graphite can “time travel” back to reconstruct which messages existed at each step. In the ReAct example above, the node forms a cycle, but events still unfold in that linear sequence. The illustration below shows how it would appear if the Thought node ended its loop on the third iteration.
Time-Weighted Topology Sort
For workflows that resemble general graphs (with branches and circular dependencies), Graphite “stretched“ the events into a DAG, and then is able to sort events by combining traditional topological ordering with timestamps. Events with the same number of dependencies (“in-degree”) are ordered by the time their events were published. This ensures the most recent and contextually relevant events are processed in the correct sequence.
Now let’s look at the weighted topology sort. Suppose you have an events lineage like following:
The rules of our time weighted topology sort extended the topology sort such that if there are same in-degree events, then we will sort the corresponding event by timestamp of the event. It will guarantee that the events which are close to the current invoked now will always closer. For above the possible sorted for next input will be:
Event 1 → Event 3 → Event 2 → Event 4 → Event 5
Example
We will demonstrate the event-driven workflow of our ReAct agent. Below is the workflow captured by our in-house debugging tool, which we plan to open-source once testing is complete.
After we asked this question: What is the elevation range for the area that the eastern sector of the Colorado orogeny extends into?
Here is the response:
Here are all the events generated from the execution.
We can see it took 1 circle of ReAct to get the answer. Which is
You can also select a node — for example, the ActionNode, which will displays the corresponding filtered events.
Switching the event display mode lets you view raw events — essential for tracing, debugging, and auditing
Conclusion
Graphite’s event-driven workflow brings a robust, modular design to AI-driven applications. By blending pub/sub patterns, temporary in-memory Topics, time travel, and time-weighted topology sorting, the system tackles the challenges of complex branching, circular dependencies, and historical context retrieval. Whether you’re an AI engineer building cutting-edge tools, a software developer streamlining your application pipeline, or an product owner seeking a forward-looking platform, Graphite’s architecture highlights how thoughtful, event-centric design can unlock next-level capabilities for AI-enabled products.