Hi all — sharing a project that may interest people pushing Deep Agents into multi-agent, fan-out-heavy territory.
What it is
langchain-dynamic-workflow (MIT) is a community port of Claude Code’s Dynamic Workflows onto LangChain Deep Agents:
A normal agent decides its control flow turn by turn — every loop, branch, and fan-out lives in the model’s context window. This library inverts that: a deterministic orchestration script owns the control flow, and only leaf agent() calls delegate to deepagents, each in an isolated, discarded context, so only the final result reaches the caller’s context.
| Normal agent | Dynamic workflow | |
|---|---|---|
| Who decides the next step | the LLM, turn by turn | the script (deterministic code) |
| Where intermediate results live | the context window | script variables |
| What reaches the caller | the whole trajectory | only the final result |
How it works (three layers)
- Substrate — LangGraph durable execution (
@entrypoint+@task+ checkpointer): resume, replay, cached-skip for free. - Orchestration runtime — the primitives on a
ctx:agent()(one leaf in a fresh context),parallel()(blocking barrier; a failed leaf →None, never aborts the barrier),pipeline()(no-barrier streaming),phase()/log(),
a shared tokenbudget, and one-levelworkflow()nesting. On top, two patches LangGraph lacks: a content-hash journal (success-only → resume replays completed leaves at zero model cost) and a fail-loud determinism guard (a divergent replay raises instead of serving a misaligned cache entry). - Meta layer — a host agent authors a script at runtime via a
workflowtool; an AST gate validates it (no imports / dunders / banned builtins) before a single restrictedexec. (It’s a guardrail, not a security sandbox — we say so loudly.)
Leaves reuse Deep Agents as-is: one create_deep_agent(...) per named roster entry, invoked via ainvoke, with the same context-quarantine result-folding Deep Agents already does, plus per-leaf sandbox backends for execution leaves.
Example
async def orchestrate(ctx):
ctx.phase("research")
findings = await ctx.parallel(
[lambda t=t: ctx.agent(f"Research {t}", agent_type="researcher") for t in topics]
)
surviving = [f for f in findings if f is not None]
return await ctx.agent("Synthesize:\n" + "\n".join(surviving), agent_type="writer")
The repo has runnable examples/ (offline, no API key) including a deep-research workflow (parallel search → pipeline extract → adversarial verify → synthesize) and a meta-layer run_script demo, plus strict typing and CI.
Why I’m posting
- Feedback / collaboration welcome — issues and PRs on the repo are very welcome.
- Native support — I’d love to see this pattern land natively in Deep Agents and am happy to help. Curious what the maintainers and community think.
Thanks!