Skip to content

Getting Started

Model your domain

  • Events — facts about what happened.
  • Commands — intents for what should happen.

Group both under a Namespace; for simple cases, colocate the handler inline. A Command's nested DomainEvents auto-form its return contract (Command.Outcomes):

from langgraph_events import Command, DomainEvent, EventGraph, Namespace


class Order(Namespace):
    class Place(Command):
        customer_id: str
        items: tuple[str, ...]

        class Placed(DomainEvent):
            order_id: str

        class Rejected(DomainEvent):
            reason: str

        def handle(self) -> Placed | Rejected:
            if not self.items:
                return Order.Place.Rejected(reason="empty order")
            return Order.Place.Placed(order_id=f"o-{self.customer_id}")

    class Shipped(DomainEvent):
        tracking: str


graph = EventGraph([Order.Place])
log = graph.invoke(Order.Place(customer_id="alice", items=("book",)))
print(log.latest(Order.Place.Placed))

See Concepts for the full taxonomy and the Outcomes contract. For class-level invariants / raises or cross-domain reactors via @on(...), see Control Flow.

Run the graph

log = graph.invoke(seed)                    # sync; returns EventLog
log = await graph.ainvoke(seed)             # async
for event in graph.stream_events(seed): ... # stream as produced

Inspect

print(graph.namespaces().text())             # human-readable tree
print(graph.namespaces().mermaid())          # Mermaid diagram
graph.namespaces().namespaces                # structured NamespaceModel access
log.filter(Order.Place.Placed)
log.latest(Order.Place.Rejected)
log.has(Order.Shipped)

Cross-cutting events

IntegrationEvent for facts that don't belong to any domain (external signals, shared events). Must live at module scope.

from langgraph_events import Auditable, IntegrationEvent

class MessageReceived(IntegrationEvent):
    text: str

class TaskStarted(IntegrationEvent, Auditable):  # @on(Auditable) for auto-logging
    name: str

Common Tasks

I want to... Reach for... Docs
Query past events in a handler EventLog (log.filter(), log.latest()) Concepts
Enforce a precondition before a handler runs invariants on the Command (or @on() for non-Command handlers) Control Flow
Register every inline handler on a domain EventGraph.from_namespaces(Order) Concepts
Accumulate state across events ScalarReducer on the domain class Reducers
Accumulate LangChain messages message_reducer() Reducers
Fan out parallel work Scatter[Item] Control Flow
Pause for human approval Interrupted + graph.resume() Control Flow
Stop the graph early Return a Halted subclass Concepts
Catch handler exceptions raises on the Command + @on(HandlerRaised, ...) Control Flow
Stream LLM tokens astream_events(include_llm_tokens=True) Streaming
Connect to an AG-UI frontend AGUIAdapter AG-UI
Keep old checkpoints working after a rename @migrate_from / @on(previously=) + coverage gates Event Migrations
Know what's safe to change on a live graph Checkpointer Evolution

Where to go next

  • Modelling your domain (taxonomy, handlers, signature injection) → Concepts
  • Enforcing rules / handling failures (invariants, HITL, exceptions, scatter) → Control Flow
  • Building a real examplePatterns
  • Need the full export list?API Reference