🦜️🔗 LangChain Haskell (langchain-hs)
The Pure Functional, Effect-Polymorphic AI Agent & Multi-Agent Graph Engine in Haskell
A strictly typed, effect-polymorphic, AI ecosystem built on pure AST pipelines (RunnableTree), cyclic state machines (StateGraph), Model Context Protocol (MCP), and production observability.

Why langchain-hs?
Modern AI orchestration frameworks often struggle with race conditions, hidden side-effects, fragile dynamic schemas, and uninspectable opaque execution chains. langchain-hs brings mathematical precision and functional programming principles to AI development:
- First-Class Runnable AST Composition (
RunnableTree): Every component—models, prompts, tools, chains, retrievers, and parsers—implements the Runnable typeclass. Connect components into trees or graphs using type-safe operators:
|>> : Sequential composition (data flows from left to right).
&>& : Parallel fan-out (concurrent evaluation of independent branches).
>>># : Fallback chains (automatic failover if the primary branch errors).
- LangGraph in Haskell (
StateGraph): Full cyclic state machine engine with pure monoidal state reducers (StateReducer s), thread-safe STM memory checkpointers (TVar), persistent SQLite checkpointers, Human-in-the-Loop (HITL) interrupts, and Time-Travel state replay.
Monorepo Packages
| Package |
Directory |
Version |
Description |
langchain-hs-core |
langchain-hs-core/ |
0.0.5.0 |
Zero-dependency pure core: RunnableTree, ChatModel, ContentBlock, Tool, and LangchainT. |
langchain-hs-graph |
langchain-hs-graph/ |
0.0.5.0 |
Stateful graph engine: StateGraph s m, checkpointers, HITL, time-travel, and parallel nodes. |
langchain-hs |
./ |
0.0.5.0 |
Production ecosystem: Ollama/OpenAI providers, Agents, MCP, Vector Stores, Chains, Observability. |
examples |
examples/ |
- |
41 runnable executables covering all 20 components for Ollama and OpenAI. |
site |
site/ |
- |
Hakyll documentation website with live provider toggle and component reference. |
20 Core Components & Verified Targets
| # |
Component |
Package Layer |
Ollama Executable |
OpenAI Executable |
Documentation |
| 1 |
Chat Models |
Langchain.Core.Model |
stack run simpleollama |
stack run simpleopenai |
Docs |
| 2 |
Conduit Streaming |
Langchain.Core.Stream |
stack run streamollama |
stack run streamopenai |
Docs |
| 3 |
Langchain Monad |
Langchain.Core.Monad |
stack run monadollama |
stack run monadopenai |
Docs |
| 4 |
Tools & Function Calling |
Langchain.Core.Tool |
stack run toolollama |
stack run toolopenai |
Docs |
| 5 |
Structured Outputs |
Langchain.OutputParser |
stack run jsonollama |
stack run jsonopenai |
Docs |
| 6 |
RAG & Embeddings |
Langchain.Embedding |
stack run ragollama |
stack run ragopenai |
Docs |
| 7 |
Hybrid Retrievers |
Langchain.Retriever |
stack run retrieverollama |
stack run retrieveropenai |
Docs |
| 8 |
Memory Systems |
Langchain.Memory |
stack run memoryollama |
stack run memoryopenai |
Docs |
| 9 |
Retrieval QA Chains |
Langchain.Chain.RetrievalQA |
stack run retrievalqaollama |
stack run retrievalqaopenai |
Docs |
| 10 |
Map-Reduce Processing |
Langchain.Chain.MapReduce |
stack run mapreduceollama |
stack run mapreduceopenai |
Docs |
| 11 |
ReAct Agent |
Langchain.Agent.ReAct |
stack run reactollama |
stack run reactopenai |
Docs |
| 12 |
Plan-and-Execute Agent |
Langchain.Agent.PlanAndExecute |
stack run planandexecuteollama |
stack run planandexecuteopenai |
Docs |
| 13 |
Guardrails & Safety |
Langchain.Guardrails |
stack run guardrailollama |
stack run guardrailopenai |
Docs |
| 14 |
Resilience & Retries |
Langchain.Resilience |
stack run resilienceollama |
stack run resilienceopenai |
Docs |
| 15 |
Observability & Tracing |
Langchain.Observability |
stack run observabilityollama |
stack run observabilityopenai |
Docs |
| 16 |
Model Context Protocol |
Langchain.MCP.Client |
stack run mcpollama |
stack run mcpopenai |
Docs |
| 17 |
StateGraph Workflows |
Langchain.Graph |
stack run stategraphollama |
stack run stategraphopenai |
Docs |
| 18 |
Multi-Agent Systems |
Langchain.Graph.MultiAgent |
stack run multiagentollama |
stack run multiagentopenai |
Docs |
| 19 |
Human-in-the-Loop (HITL) |
Langchain.Graph.Checkpointer |
stack run hitlollama |
stack run hitlopenai |
Docs |
| 20 |
Runnables & AST Composition |
Langchain.Core.Runnable |
stack run runnableollama |
stack run runnableopenai |
Docs |
Code Showcases
1. The Power of Runnables: Pure AST Composition
Compose complex multi-stage pipelines using typed operators without executing any IO until interpretation:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Langchain.Prelude
-- Compose pure AST pipelines with (|>>), (&>&), and (>>>#)
pipeline :: RunnableTree IO Text Text
pipeline =
runLambda (\q -> (q, q)) -- duplicate input query
|>> (fetchDocuments &>& generateFollowup) -- parallel branch fan-out
|>> runLambda (\(docs, fup) -> renderPrompt docs fup) -- pure prompt synthesis
|>> (invokeLLM primaryModel >>># invokeLLM backupModel) -- fallback resilience
|>> parseStructuredResponse -- JSON parser
main :: IO ()
main = do
output <- interpret pipeline "Explain Monads in Haskell"
print output
2. Dual-Provider Chat Comparison: Ollama vs OpenAI
Ollama (Local & Offline)
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Except (runExceptT)
import qualified Data.Text.IO as T
import Langchain.Prelude
main :: IO ()
main = do
-- Connect to local Ollama instance (DeepSeek, Llama 3, Gemma)
model <- newOllama "gemma3" defaultConfig
let msg = [userMessage "Write a poem about functional programming"]
res <- runExceptT $ invoke model msg Nothing
case res of
Left err -> T.putStrLn $ errorMessage err
Right m -> T.putStrLn $ extractMessageText m
Run: stack run simpleollama
OpenAI / OpenRouter (Cloud)
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Except (runExceptT)
import qualified Data.Text.IO as T
import Langchain.Prelude
import OpenAI.Common (defaultModelName, getOpenRouterModel)
main :: IO ()
main = do
-- Connect to OpenAI or OpenRouter using environment API key
model <- getOpenRouterModel defaultModelName
let msg = [userMessage "Write a poem about functional programming"]
res <- runExceptT $ invoke model msg Nothing
case res of
Left err -> T.putStrLn $ errorMessage err
Right m -> T.putStrLn $ extractMessageText m
Run: stack run simpleopenai
3. Stateful Graphs (StateGraph): Cyclic Multi-Agent Workflow
{-# LANGUAGE OverloadedStrings #-}
import Langchain.Graph.StateGraph
import Langchain.Prelude
-- Pure state with a list-append reducer
data AgentState = AgentState { messages :: [Message], loopCount :: Int }
-- Build the graph using pure combinators
workflow :: StateGraph AgentState IO
workflow =
addEdge "reviewer" "planner" -- cyclic feedback loop!
$ addConditionalEdge "executor"
(\s -> pure $ if done s then Right endNodeId else Right "reviewer")
$ addEdge "planner" "executor"
$ addEdge startNodeId "planner"
$ addNode "reviewer" (Node reviewerNode replaceFieldReducer)
$ addNode "executor" (Node executorNode replaceFieldReducer)
$ addNode "planner" (Node plannerNode replaceFieldReducer)
$ emptyStateGraph
main :: IO ()
main = do
checkpointer <- newMemoryCheckpointer
case compileGraph workflow of
Left err -> print err
Right compiled -> do
result <- runGraph compiled initialState (Just checkpointer)
print result
Run: stack run stategraphollama or stack run stategraphopenai
4. Model Context Protocol (MCP) Tools Integration
Connect Haskell agents to any external MCP server (e.g., Hackage doc search, SQLite, Filesystem, GitHub) over stdio:
{-# LANGUAGE OverloadedStrings #-}
import Langchain.Prelude
main :: IO ()
main = do
-- Connect to any MCP server via stdio JSON-RPC 2.0
client <- newStdioMcpClient "docker" ["run", "-i", "--rm", "mcp/hackage-doc"]
-- Discover available tools from server
mcpTools <- listMcpTools client
let nativeTools = map mcpToolToLangchainTool mcpTools
-- Bind tools to your ReAct or Plan-and-Execute Agent
let agent = createReActAgent model nativeTools defaultAgentConfig
res <- runReActAgent agent "Search Hoogle for the signature of 'traverse'"
print res
Run: stack run mcpollama or stack run mcpopenai
Installation
Stack
Add to your stack.yaml:
extra-deps:
- langchain-hs-core-0.0.5.0
- langchain-hs-graph-0.0.5.0
- langchain-hs-0.0.5.0
Then in your .cabal or package.yaml:
dependencies:
- langchain-hs # full ecosystem (providers, agents, MCP, vector stores)
- langchain-hs-core # pure core only (no HTTP dependencies)
- langchain-hs-graph # graph engine only
Cabal
cabal install langchain-hs
Development & Quality Commands
The repository enforces strict code quality and formatting via make:
# Build the entire monorepo and all 41 example executables
stack build
# Run unit and property-based test suites
stack test
# Run HLint across all source trees (zero hints policy)
make lint
# Check code formatting with Fourmolu
make format-check
# Format all files in-place
make format
# Build the documentation website (Hakyll)
make site-build
# Run live documentation server with auto-reload (port 8000)
make site-watch
Documentation & Research
| Resource |
Description |
| Hackage Docs |
Full Haddock API reference for all exported modules |
| Whitepaper |
Deep technical dive: category theory foundations, algebraic laws, effect-polymorphic design, and advanced multi-agent patterns |
| Documentation Website |
Hakyll site with 20 component pages, live provider toggle, and instant search (Cmd+K) |
| Examples |
41 runnable executables covering every component for Ollama and OpenAI |
To build the Haddock API docs locally:
make docs
# Opens in .stack-work/install/.../doc/index.html
License
Distributed under the MIT License. See LICENSE for details.