Getting Started

Learn the core concepts: nodes, graphs, and runners.

  • Nodes - Wrap functions with named inputs and outputs

  • Graphs - Connect nodes automatically via matching names

  • Runners - Execute graphs synchronously or asynchronously

Core Concepts

Nodes

A node is a function wrapped as a graph component. Nodes have:

  • Inputs - Parameter names from the function signature

  • Outputs - Named values produced by the function

  • A name - Identifier for the node (defaults to function name)

from hypergraph import node

@node(output_name="result")
def add(x: int, y: int) -> int:
    return x + y

# Properties
print(add.name)      # "add"
print(add.inputs)    # ("x", "y")
print(add.outputs)   # ("result",)

Automatic Edge Inference

Hypergraph connects nodes automatically based on matching names. If node A produces output "embedding" and node B takes input "embedding", they're connected.

Name your outputs and inputs consistently — edges are inferred automatically.

Creating Your First Node

Simple Function

Side-Effect Only Nodes

If a function doesn't return a value, omit output_name:

Warning: If you accidentally have a return annotation without output_name, hypergraph warns you:

Multiple Outputs

Functions can produce multiple outputs:

The return value must be a tuple matching the number of output names. Unpacking is automatic.

Working with Nodes

Renaming Inputs and Outputs

Use with_inputs() and with_outputs() to rename without creating new functions:

Renaming the Node

Chaining Renames

All rename methods return new instances:

Building Graphs

Now that you know how to create nodes, let's compose them into graphs.

Basic Graph Construction

A Graph connects nodes together automatically based on matching parameter names. If node A produces output "x" and node B takes input "x", they're connected.

The graph automatically connects adddouble because add produces "result" and double consumes "result".

Graph Properties

Binding Values

You can pre-fill some inputs with bind():

Binding is immutable - it returns a new graph, leaving the original unchanged.

Type Validation with strict_types

This is hypergraph's core feature: catch type errors at graph construction time, before you run anything.

Why This Matters

Without type validation, you might wire nodes incorrectly and only discover the error at runtime:

Enable strict_types

Add strict_types=True to catch these errors immediately:

Type Mismatch Errors

When types don't match, you get a clear error at construction time:

Missing Annotations

With strict_types=True, all connected nodes must have type annotations:

Union Types

Union types work as you'd expect - a more specific type satisfies a broader one:

When to Use strict_types

  • Development: Enable it to catch wiring mistakes early

  • Production: Enable it for safety in critical pipelines

  • Prototyping: Disable it (default) for quick experiments

Execution Modes

Hypergraph supports four execution modes, auto-detected from the function signature:

1. Synchronous Function (Default)

2. Asynchronous Function

3. Synchronous Generator

4. Asynchronous Generator

Function Node Properties

Every node created with @node has these properties:

name

The public identifier for this node (defaults to function name).

inputs

Tuple of input parameter names from the function signature.

outputs

Tuple of output names (empty if no output_name).

func

Direct reference to the underlying Python function.

cache

Whether this node's results are cached (default: False).

is_async

True if the function is async or async generator.

is_generator

True if the function yields values (sync or async generator).

definition_hash

SHA256 hash of the function's source code (for cache invalidation).

Error Handling: RenameError

When you try to rename a name that doesn't exist, you get a helpful error:

If you renamed and then try to use the old name:

Running Graphs

Graphs need a runner to execute. Hypergraph provides two runners:

  • SyncRunner - Sequential execution for synchronous nodes

  • AsyncRunner - Concurrent execution with async support

Basic Execution with SyncRunner

Async Execution with Concurrent Nodes

Batch Processing with runner.map()

Process multiple inputs efficiently:

Map Modes: zip vs product

When mapping over multiple parameters:

Selecting Specific Outputs

By default, run() returns all graph outputs. Configure output scope on the graph to filter:

Error Handling

Conditional Routing

Use @route to control execution flow based on data.

Basic Routing

Terminating Early with END

Agentic Loops

Routing enables cycles for multi-turn workflows:

For more patterns including multi-target routing and real-world RAG examples, see the Routing Guide.

Next Steps

  • Routing Guide - Conditional routing, agentic loops, and real-world patterns

  • Explore API Reference for complete documentation on nodes, graphs, and types

  • Read Runners API for detailed runner documentation

  • Read Philosophy to understand the design principles

  • Try building a small pipeline with strict_types=True to catch errors early

Common Patterns

Creating Multiple Variants

Reuse a function in different contexts:

Reconfiguring an Existing Node

Pass a FunctionNode to FunctionNode() to create a fresh node with new configuration. Only the underlying function is extracted - all other settings are discarded:

This is useful when you want to completely reconfigure a node rather than just rename parts of it.

Conditional Output Names

Choose output names at creation time:

Last updated