tusharad/langchain-hs

Haskell implementation of LangChain

Haskell

55

338 commits

updated Sep 16, 2026

See the code

README

🦜️🔗 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.


Hackage GHC Components Providers License: MIT Whitepaper


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:

  1. 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).
  2. 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

PackageDirectoryVersionDescription
langchain-hs-corelangchain-hs-core/0.0.5.0Zero-dependency pure core: RunnableTree, ChatModel, ContentBlock, Tool, and LangchainT.
langchain-hs-graphlangchain-hs-graph/0.0.5.0Stateful graph engine: StateGraph s m, checkpointers, HITL, time-travel, and parallel nodes.
langchain-hs./0.0.5.0Production ecosystem: Ollama/OpenAI providers, Agents, MCP, Vector Stores, Chains, Observability.
examplesexamples/-41 runnable executables covering all 20 components for Ollama and OpenAI.
sitesite/-Hakyll documentation website with live provider toggle and component reference.

20 Core Components & Verified Targets

#ComponentPackage LayerOllama ExecutableOpenAI ExecutableDocumentation
1Chat ModelsLangchain.Core.Modelstack run simpleollamastack run simpleopenaiDocs
2Conduit StreamingLangchain.Core.Streamstack run streamollamastack run streamopenaiDocs
3Langchain MonadLangchain.Core.Monadstack run monadollamastack run monadopenaiDocs
4Tools & Function CallingLangchain.Core.Toolstack run toolollamastack run toolopenaiDocs
5Structured OutputsLangchain.OutputParserstack run jsonollamastack run jsonopenaiDocs
6RAG & EmbeddingsLangchain.Embeddingstack run ragollamastack run ragopenaiDocs
7Hybrid RetrieversLangchain.Retrieverstack run retrieverollamastack run retrieveropenaiDocs
8Memory SystemsLangchain.Memorystack run memoryollamastack run memoryopenaiDocs
9Retrieval QA ChainsLangchain.Chain.RetrievalQAstack run retrievalqaollamastack run retrievalqaopenaiDocs
10Map-Reduce ProcessingLangchain.Chain.MapReducestack run mapreduceollamastack run mapreduceopenaiDocs
11ReAct AgentLangchain.Agent.ReActstack run reactollamastack run reactopenaiDocs
12Plan-and-Execute AgentLangchain.Agent.PlanAndExecutestack run planandexecuteollamastack run planandexecuteopenaiDocs
13Guardrails & SafetyLangchain.Guardrailsstack run guardrailollamastack run guardrailopenaiDocs
14Resilience & RetriesLangchain.Resiliencestack run resilienceollamastack run resilienceopenaiDocs
15Observability & TracingLangchain.Observabilitystack run observabilityollamastack run observabilityopenaiDocs
16Model Context ProtocolLangchain.MCP.Clientstack run mcpollamastack run mcpopenaiDocs
17StateGraph WorkflowsLangchain.Graphstack run stategraphollamastack run stategraphopenaiDocs
18Multi-Agent SystemsLangchain.Graph.MultiAgentstack run multiagentollamastack run multiagentopenaiDocs
19Human-in-the-Loop (HITL)Langchain.Graph.Checkpointerstack run hitlollamastack run hitlopenaiDocs
20Runnables & AST CompositionLangchain.Core.Runnablestack run runnableollamastack run runnableopenaiDocs

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

ResourceDescription
Hackage DocsFull Haddock API reference for all exported modules
WhitepaperDeep technical dive: category theory foundations, algebraic laws, effect-polymorphic design, and advanced multi-agent patterns
Documentation WebsiteHakyll site with 20 component pages, live provider toggle, and instant search (Cmd+K)
Examples41 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.

Contributors

tusharad

280 commits

lbobylev

56 commits

jhrcek

1 commits

tonyalaribe

1 commits

tusharad/langchain-hs

Haskell implementation of LangChain

Haskell

55

338 commits

updated Sep 16, 2026

See the code

README

🦜️🔗 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.


Hackage GHC Components Providers License: MIT Whitepaper


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:

  1. 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).
  2. 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

PackageDirectoryVersionDescription
langchain-hs-corelangchain-hs-core/0.0.5.0Zero-dependency pure core: RunnableTree, ChatModel, ContentBlock, Tool, and LangchainT.
langchain-hs-graphlangchain-hs-graph/0.0.5.0Stateful graph engine: StateGraph s m, checkpointers, HITL, time-travel, and parallel nodes.
langchain-hs./0.0.5.0Production ecosystem: Ollama/OpenAI providers, Agents, MCP, Vector Stores, Chains, Observability.
examplesexamples/-41 runnable executables covering all 20 components for Ollama and OpenAI.
sitesite/-Hakyll documentation website with live provider toggle and component reference.

20 Core Components & Verified Targets

#ComponentPackage LayerOllama ExecutableOpenAI ExecutableDocumentation
1Chat ModelsLangchain.Core.Modelstack run simpleollamastack run simpleopenaiDocs
2Conduit StreamingLangchain.Core.Streamstack run streamollamastack run streamopenaiDocs
3Langchain MonadLangchain.Core.Monadstack run monadollamastack run monadopenaiDocs
4Tools & Function CallingLangchain.Core.Toolstack run toolollamastack run toolopenaiDocs
5Structured OutputsLangchain.OutputParserstack run jsonollamastack run jsonopenaiDocs
6RAG & EmbeddingsLangchain.Embeddingstack run ragollamastack run ragopenaiDocs
7Hybrid RetrieversLangchain.Retrieverstack run retrieverollamastack run retrieveropenaiDocs
8Memory SystemsLangchain.Memorystack run memoryollamastack run memoryopenaiDocs
9Retrieval QA ChainsLangchain.Chain.RetrievalQAstack run retrievalqaollamastack run retrievalqaopenaiDocs
10Map-Reduce ProcessingLangchain.Chain.MapReducestack run mapreduceollamastack run mapreduceopenaiDocs
11ReAct AgentLangchain.Agent.ReActstack run reactollamastack run reactopenaiDocs
12Plan-and-Execute AgentLangchain.Agent.PlanAndExecutestack run planandexecuteollamastack run planandexecuteopenaiDocs
13Guardrails & SafetyLangchain.Guardrailsstack run guardrailollamastack run guardrailopenaiDocs
14Resilience & RetriesLangchain.Resiliencestack run resilienceollamastack run resilienceopenaiDocs
15Observability & TracingLangchain.Observabilitystack run observabilityollamastack run observabilityopenaiDocs
16Model Context ProtocolLangchain.MCP.Clientstack run mcpollamastack run mcpopenaiDocs
17StateGraph WorkflowsLangchain.Graphstack run stategraphollamastack run stategraphopenaiDocs
18Multi-Agent SystemsLangchain.Graph.MultiAgentstack run multiagentollamastack run multiagentopenaiDocs
19Human-in-the-Loop (HITL)Langchain.Graph.Checkpointerstack run hitlollamastack run hitlopenaiDocs
20Runnables & AST CompositionLangchain.Core.Runnablestack run runnableollamastack run runnableopenaiDocs

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

ResourceDescription
Hackage DocsFull Haddock API reference for all exported modules
WhitepaperDeep technical dive: category theory foundations, algebraic laws, effect-polymorphic design, and advanced multi-agent patterns
Documentation WebsiteHakyll site with 20 component pages, live provider toggle, and instant search (Cmd+K)
Examples41 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.

Contributors

tusharad

280 commits

lbobylev

56 commits

jhrcek

1 commits

tonyalaribe

1 commits

Languages

Haskell

87.8%

CSS

4.6%

HTML

4.1%

JavaScript

3.4%