MCE

Monadic Context Engineering
A composable framework for AI agent orchestration built on monad transformers, explicit state, deterministic errors, and applicative parallelism.

Yifan Zhang, Mengdi Wang
Princeton University
StateT + EitherT + IO Async Applicatives Explicit Effects Composable Agents Deterministic Failures

Abstract

Large language model agents often rely on imperative orchestration that is difficult to test, scale, or reason about. MCE introduces a formal, algebraic foundation based on Functors, Applicatives, and Monads, enabling a uniform structure for stateful, fallible, and asynchronous workflows. By stacking monad transformers, MCE composes these concerns into a single, reusable interface for agent development.

The result is a workflow model that reads like a specification while remaining runnable, observable, and easy to extend with tool effects. Context, errors, and side effects are explicit at the type level, so orchestration logic stays predictable as systems scale.

Code and Library Read the Paper

The Monad Stack

MCE models every run as a transformer stack that composes state, error handling, and effects into a single algebra. The formal type signature of the AgentMonad encapsulates these capabilities via Monad Transformer composition:

$$ \text{AgentMonad} \cong S \to \text{IO}(\text{Either}(E, (A, S))) $$

The Context Stack

Structure: Monad Transformers


1. StateT: Context as a first-class value. Threads memory and tool outputs without plumbing.

2. EitherT: Deterministic failures. Short-circuits execution upon error with structured info.

3. Task / IO: Explicit effects. Encapsulates async tool calls and side effects.

The Algebraic Interface

Operation: Functor / Applicative / Monad


$\text{map} (f)$: Transform values purely within the context.

$\text{then} (f)$: Sequence dependent steps (The "Railway"). Fails fast if previous step errored.

$\text{gather} ([f])$: Run independent async flows in parallel (Applicative).

Declarative Flow

The AgentMonad exposes a small surface area for sequencing. Workflows stay linear and readable while retaining full introspection. The code below demonstrates how a complex agent loop reads like a linear specification.

Sequential Logic

# The workflow reads like a high-level spec.
# Failures in any step automatically short-circuit the rest of the chain.

task = "What is a Monad?"
initial_state = AgentState(task=task)

flow = (
    AgentMonad.start(initial_state)
    .then(lambda s, _: plan_action(s, task))
    .then(lambda s, call: execute_tool(s, call))
    .then(synthesize_answer)
    .then(format_output)
)

Logic is separated from orchestration. Each function focuses on one task, while the Monad handles the "glue".

Applicative Parallelism

While Monads sequence dependent tasks, Applicative Functors handle independent ones. Using AsyncAgentMonad.gather, MCE allows agents to branch out, execute multiple IO-bound tool calls concurrently, and merge results back into the main context.

Parallel Execution

# Independent tasks run concurrently via Applicative 'gather'.
# The result preserves ordering and propagates the first failure.

gathered_flow = AsyncAgentMonad.gather([
    news_agent_flow,
    weather_agent_flow,
    stocks_agent_flow,
])

# The final AgentMonad holds the combined outputs in .value
result_flow = await gathered_flow.run()
combined = result_flow.value

This creates a Fork-Join topology purely through algebraic composition, recovering high-performance concurrency patterns without manual thread management.

Meta-Agents

Meta-agents operate on workflows instead of raw data. They synthesize sub-agent chains, run them, and combine results into a higher-level monadic context. MCE keeps these systems predictable by reusing the same algebra at every layer.

Planner

Build new agent graphs from reusable primitives and apply policy constraints.

Evaluator

Score and repair outputs, rerouting failures to new monadic branches.

Governor

Gate expensive calls, enforce budgets, and log traces with minimal coupling.

Citation

If you find this work useful, please cite:

@article{zhang2025monadic,
  title   = {Monadic Context Engineering},
  author  = {Zhang, Yifan and Wang, Mengdi},
  year    = {2025},
  month   = {Dec},
  journal = {Github},
  url     = {https://yifanzhang-pro.github.io/monadic-context-engineering/MCE.pdf}
}