Skip to content
Built by Postindustria. We help teams build agentic production systems.

neograph

3 functions. That's a production agent.

PyPI versionPython versionsLicenseGitHub stars

@node(outputs=ChangedFiles)
def parse_diff(raw_diff: Annotated[str, FromInput]) -> ChangedFiles:
return parse_git_diff(raw_diff)
@node(outputs=FileReview, prompt="review this file for bugs and security issues",
model="reason", map_over="parse_diff.files", map_key="path",
ensemble_n=3, merge_fn="pick_best")
def review(file: ChangedFile) -> FileReview: ...
@node(outputs=Report, prompt="synthesize all findings into a final report", model="fast")
def report(review: list[FileReview]) -> Report: ...
Terminal window
uv add neograph && python review_agent.py

That’s a production code review agent. Here’s what those 8 lines do:

  • Fan-out: every changed file is reviewed in parallel
  • Ensemble: 3 different models review each file, best answer wins
  • Type-safe: ChangedFile in, FileReview out — validated at assembly time, not runtime
  • Auto-retries: malformed LLM output? Pydantic errors sent back to the model for self-correction
  • Structured output: Report is a Pydantic model, not a string blob

The same thing in raw LangGraph? 130 lines. Two state models, two graphs, a router, a barrier, a reducer, manual edge wiring, and a subgraph wrapper. See the comparison.

A function is a node. A parameter name is an edge. The graph assembles itself.

@node(outputs=Claims, prompt='decompose', model='reason')
def decompose(topic: Annotated[str, FromInput]) -> Claims: ...
@node(outputs=Classified, prompt='classify', model='fast')
def classify(decompose: Claims) -> Classified: ...
# ^^^^^^^^^
# this parameter name IS the dependency

classify takes decompose: Claims — neograph reads the signature, verifies decompose produces Claims, and wires the edge. Rename the function? Your IDE flags the broken reference before you hit save.

Mode is inferred. prompt= + model= = LLM call. Neither = the function body runs. Keywords add superpowers: map_over= for fan-out, ensemble_n= for N-way ensemble, interrupt_when= for human approval gates.

Code Review Agent

Fan-out over changed files. 3 models per file. Merge best answers. Synthesize report.

map_over= + ensemble_n= + merge_fn=

See the code

Lead Research Pipeline

For each lead: scrape website, search news, synthesize findings, qualify and score.

Each fan-out + sub-construct + LLM synthesis

See the code

Document Analyzer

Chunk large docs. Decompose each chunk with Oracle ensemble. Loop until quality threshold met.

Each x Oracle fusion + Loop refinement

See the code

Spec Builder

Describe a workflow in plain English. LLM generates the pipeline spec. neograph validates and compiles it.

LLM-driven runtime construction

See the code

neograph handles:

You writeneograph handles
@node(map_over="items")Fan-out router, Send() dispatch, barrier, dict collection, dedup
ensemble_n=3, merge_fn="best"N generators x M models, merge barrier, result selection
interrupt_when=lambda s: ...Checkpointer setup, interrupt/resume flow, human feedback injection
Annotated[T, FromInput]Config injection, bundled model construction, DI resolution
prompt="analyze"Prompt compilation, structured output, retry with error feedback
Parameter namesDAG inference, topological sort, type validation, fan-in wiring
ConstructError: Node 'verify' declares inputs=ClusterGroup but no upstream
produces a compatible value.
upstream producers:
- node 'cluster': Clusters
hint: did you forget to fan out? try .map(lambda s: s.cluster.groups, key='...')
at my_pipeline.py:42

68 compile-time check fixtures backed by a rustc-style fixture suite. If it compiles, it runs. Validate any pipeline without executing: neograph check my_pipeline.py.

Terminal window
uv add neograph
from neograph import node, construct_from_module, compile, run
@node(outputs=Result, prompt="do the thing", model="reason")
def my_agent(topic: str) -> Result: ...
graph = compile(construct_from_module(__import__(__name__)))
result = run(graph, input={"topic": "hello", "node_id": "demo"})

1362 tests. Hypothesis property-based testing. MIT license. Built on LangGraph.


Documentation © 2025-2026 Constantine Mirin, mirin.pro. Licensed under CC BY-ND 4.0.