Skip to main content

Declarative YAML workflow definitions for LangGraph — topology as config, logic in Python

Project description

langgraph-declarative

Topology in YAML. Logic in Python. One line to compile.

CI Python License

Quickstart · Features · YAML reference · Examples · Roadmap


Describe a LangGraph workflow's structure in YAML, keep the behaviour in Python, and compile the two into a standard CompiledStateGraph. Nothing about how you run, stream, or deploy the graph changes.

[!TIP] Topology changes become config edits, not code rewrites. Workflow structure can be diffed in review, validated in your IDE, rendered as a diagram, stored and versioned in a database, and read by people who don't write Python.

Install

pip install langgraph-declarative                 # uv add langgraph-declarative
pip install "langgraph-declarative[anthropic]"    # optional: llm: support ([openai] too)

Quickstart

1. Register your functions.

from langgraph_declarative import Registry, build_graph

registry = Registry()

@registry.node("greet")
def greet(state):
    return {"messages": [{"role": "assistant", "content": "Hello! How can I help?"}]}

@registry.node("respond")
def respond(state):
    return {"messages": [{"role": "assistant", "content": "Goodbye!"}]}

2. Declare the graph.

# workflow.yaml
nodes:
  - name: "greeter"
    function: "greet"
  - name: "responder"
    function: "respond"

edges:
  - source: "START"
    target: "greeter"
  - source: "greeter"
    target: "responder"
  - source: "responder"
    target: "END"

3. Build and run.

graph = build_graph("workflow.yaml", registry)
result = graph.invoke({"messages": [{"role": "user", "content": "Hi there"}]})

That's the whole surface area. build_graph() validates the YAML with Pydantic, cross-checks every function: and path: against the registry, and hands you a compiled LangGraph.

[!TIP] Every feature below has a commented, runnable example — see examples/.

How it fits together

flowchart LR
    Y["workflow.yaml<br/><i>or a DB row</i>"] --> V["Schema validation<br/><i>Pydantic</i>"]
    R["@registry.node<br/>@registry.router<br/>@registry.tool"] --> V
    V --> B["GraphBuilder"]
    B --> G["CompiledStateGraph<br/><i>.invoke() · .stream() · langgraph dev</i>"]

Three pieces: a registry of Python functions, a definition of the topology, and a builder that joins them. Validation happens before compilation, so a typo in the YAML gives you Unknown node function 'classfy'. Did you mean 'classify'? — not a stack trace at runtime.

Features

Feature YAML Since Example
Simple & parallel edges target: "node" / target: [a, b] v1 quickstart, fan_out
Conditional routing path: + targets: v1 conditional_routing
Dynamic fan-out (Send) path: without targets v1 dynamic_routing
Custom Python state class build_graph(..., state_class=...) v1 custom_state
State declared in YAML state: with types & reducers v1.1 declared_state
Match routing (no router fn) match: + targets: v1.1 match_routing
Mermaid diagrams draw_mermaid() v1.1 visualization
IDE autocomplete & validation workflow.schema.json v1.1 visualization
Subgraph composition subgraph: "child.yaml" v2 subgraph
Cross-file node imports imports: v2 cross_file_imports
LLM config & tool binding llm: + tools: v2 llm_and_tools
Database-stored workflows SQLiteLoader, build_graph_from_db() v2 db_workflow
LangGraph project template v2 template/

[!NOTE] v1 / v1.1 / v2 are milestone labels, not package versions. All three have shipped — see CHANGELOG.md for releases.

YAML reference

Only nodes is required. The simplest workflow is a list of nodes and edges.

Full schema — state, llm, imports, nodes, edges
state:                              # declare the state schema (default: MessagesState)
  - name: "category"
    type: "str"                     # str | int | float | bool | list | dict | list[str] | list[dict]
  - name: "notes"
    type: "list[str]"
    reducer: "append"               # append | add_messages | replace (default)

llm:                                # graph-level LLM default for opt-in nodes
  provider: "anthropic"             # anthropic | openai
  model: "claude-opus-4-8"

imports:                            # merge node declarations from other files
  - file: "shared_nodes.yaml"
    nodes: ["error_handler"]        # omit to import all nodes

nodes:
  - name: "classifier"
    function: "classify"            # registered via @registry.node()
  - name: "research"
    subgraph: "child.yaml"          # embed another workflow (function XOR subgraph)
  - name: "agent"
    function: "agent_fn"            # function must accept an `llm` parameter to opt in
    llm: { model: "claude-haiku-4-5" }  # node-level override, merged over graph llm
    tools: ["get_weather"]          # @registry.tool() names or "module.path:attr"

edges:
  - source: "START"                 # START, END, or a node name
    target: "classifier"            # simple edge
  - source: "loader"
    target: ["a", "b"]              # parallel fan-out
  - source: "classifier"
    path: "router_name"             # @registry.router(); omit targets for Send routing
    targets: { key: "node" }
  - source: "classifier"
    match: "category"               # route on a state field's value — no Python router
    targets:
      billing: "billing_agent"
      default: "fallback"           # reserved fallback key

[!TIP] Add this as the first line of any workflow file for autocomplete and inline validation in VS Code, JetBrains, and Neovim:

# yaml-language-server: $schema=path/to/workflow.schema.json

The schema ships at schema/workflow.schema.json, or regenerate it with export_json_schema().

API

Function / Class Description
Registry() Holds node, router, and tool functions in separate namespaces
@registry.node("name") Register a node function (transforms state)
@registry.router("name") Register a router (returns a routing key or a list of Send)
@registry.tool("name") Register a tool for tools: binding
build_graph(path, registry, state_class=None) YAML file → compiled CompiledStateGraph
build_graph_from_db(source, registry, db_path) DB-stored definition → compiled graph ("flow" or "flow@2")
draw_mermaid(path, registry, output_path=None) Compile and render a Mermaid diagram (.md → fenced block)
export_json_schema(output_path=None) Emit the JSON Schema for workflow YAML files
GraphBuilder(registry, state_class=None) Power-user class behind build_graph()
SQLiteLoader(db_path) Save/load versioned definitions; implements the pluggable Loader protocol

Documentation

Document Contents
examples/ 12 runnable examples, one per feature, organized by milestone
template/ Starter project for langgraph dev using the declarative pattern
ROADMAP.md What shipped per milestone, and unvalidated future ideas
CHANGELOG.md Release history
DECISIONS.md Why the API and the scope look the way they do
docs/02-requirements/REQUIREMENTS.md Problem, users, success criteria
docs/03-design/DESIGN.md Architecture, module responsibilities, trade-offs
Project layout
src/langgraph_declarative/   # library (registry, schema, builder, state/llm factories, loaders)
schema/                      # generated JSON Schema for workflow YAML
examples/                    # runnable examples — one folder per feature
template/                    # LangGraph starter template
tests/                       # pytest suite + YAML fixtures
docs/                        # requirements, design, roadmap, reviews

Requirements

  • Python 3.10+
  • LangGraph ≥ 0.2 · PyYAML ≥ 6.0 · Pydantic ≥ 2.0
  • Optional: [anthropic] / [openai] extras for llm: support

Contributing

Issues and pull requests welcome. Run the suite with uv run pytest before opening a PR.

License

MIT. Community project — not affiliated with or endorsed by LangChain. Built on top of LangGraph.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

langgraph_declarative-0.2.0.tar.gz (309.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

langgraph_declarative-0.2.0-py3-none-any.whl (21.7 kB view details)

Uploaded Python 3

File details

Details for the file langgraph_declarative-0.2.0.tar.gz.

File metadata

  • Download URL: langgraph_declarative-0.2.0.tar.gz
  • Upload date:
  • Size: 309.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for langgraph_declarative-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7822af746fc5c2b5f6a18bcb981fb37cd456d22b3dc18138000bcacc88152416
MD5 0960afc6bf907159226cbfd54dc6cb2a
BLAKE2b-256 f3ee694549621bf583e9c7eef0be110d5a69a1e682b361248a5391a52e4a0a13

See more details on using hashes here.

File details

Details for the file langgraph_declarative-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: langgraph_declarative-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 21.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for langgraph_declarative-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 96b81bf997205130fca0c37c44338642649159f1bb5c34f1f3efaac7ceffccb2
MD5 ac4b6357c37c9b1c4e5d516aa2d0e6e7
BLAKE2b-256 b920df4a4d8ce2b404f72b52348e37e276fc36a1c71391253eafdc8af05206af

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page