Skip to content

One Multi-Agent Task, Four Implementations: Omnigent YAML vs LangGraph vs CrewAI vs Goose

Aug 26, 2026 1 min
TL;DR The same Polly task — parallel git worktrees plus cross-vendor review — implemented four ways: Omnigent YAML governs at the Server layer, LangGraph controls flow with a StateGraph, CrewAI assembles roles quickly, and Goose ships a desktop Recipe, compared on tokens, latency, and maintainability.
Table of Contents
  1. The baseline: the Polly Pattern
  2. 1. Omnigent YAML — governance at the Server layer
  3. 2. LangGraph — precise flow control with StateGraph
  4. 3. CrewAI — fast role-play assembly
  5. 4. Goose — desktop automation via Recipe
  6. Side-by-side comparison
  7. Tokens, latency, and maintainability
  8. Overall
  9. References

🌏 中文版

The previous post placed Omnigent (omnigent.ai), Zed ACP, Vercel HarnessAgent and Cloudflare Flue into a four-layer model. This post gets concrete: one task, four implementations.

The reference task is Omnigent's built-in Polly pattern — the most representative multi-agent collaboration template in the series: plan → parallel git worktree delegation → cross-vendor review → aggregate and merge. Problem statement: "Add rate-limit middleware to the API, including tests and docs."

The baseline: the Polly Pattern

Issue: "Add rate-limit middleware to API"

  ├─ Planner: splits into 3 sub-tasks (middleware / tests / docs)
  ├─ Workers: each implements in an isolated git worktree, in parallel
  ├─ Reviewers: each diff is reviewed by a different vendor model
  │             (e.g., author uses Claude, reviewer uses GPT)
  └─ Aggregator: collects reviews; a human decides to merge

Two observable collaboration properties matter most: parallel worktree isolation and cross-vendor review routing. They are exactly where the four frameworks diverge.

1. Omnigent YAML — governance at the Server layer

Polly is YAML plus Server-side Policy and Session. Its value is portability, governance, and collaboration.

# examples/polly/polly.yaml (abridged)
name: polly
prompt: |
  You are Polly, an orchestrator. You do not write code yourself.
  Plan the task, delegate to sub-agents in parallel git worktrees,
  then route each diff to a cross-vendor reviewer.

executor:
  harness: claude-sdk   # one-line switch: claude-native / codex / pi / opencode ...

tools:
  planner:
    type: agent
    prompt: Break the issue into sub-tasks with acceptance criteria.
  worker_claude:
    type: agent
    prompt: Implement one sub-task in an isolated git worktree.
    executor: { harness: claude-sdk }
    tools:
      shell: { type: function, callable: tools.shell.exec }
  worker_codex:
    type: agent
    prompt: Implement one sub-task in an isolated git worktree.
    executor: { harness: codex }
  reviewer_gpt:
    type: agent
    executor: { harness: openai-agents }
    prompt: Review the diff. Approve or request changes with rationale.
  reviewer_claude:
    type: agent
    executor: { harness: claude-sdk }
    prompt: Review the diff. Approve or request changes with rationale.

policies:
  budget:
    type: function
    handler: omnigent.policies.builtins.cost.cost_budget
    factory_params: { max_cost_usd: 5.00 }
  ask_on_push:
    type: function
    handler: omnigent.policies.builtins.safety.ask_on_os_tools

Run: omnigent run examples/polly --harness claude-sdk or omnigent start then open http://localhost:6767 and share the Session URL.

Philosophy: orchestration is declarative YAML; governance lives in Server-side Policies (allow / deny / ask) and the Omnibox sandbox. Cross-vendor capability comes from binding each sub-agent to a different harness, not from prompt tricks.

Good fit: teams already using multiple harnesses who need shareable live Sessions and auditable cost and permission guardrails. Not a good fit: single-harness, single-machine use; low tolerance for alpha (0.11.0.dev0); or Windows-native FS/network isolation needs.

2. LangGraph — precise flow control with StateGraph

LangGraph (docs) is LangChain's orchestration layer built around StateGraph + conditional edges. Parallel fan-out uses the Send API; state merging is governed by reducers.

from langgraph.graph import StateGraph, START, END
from langgraph.types import Send
from typing import TypedDict, Annotated
import operator

class State(TypedDict):
    issue: str
    plan: list[str]
    diffs: Annotated[list[str], operator.add]
    reviews: Annotated[list[str], operator.add]

def planner(state: State):
    return {"plan": ["middleware", "tests", "docs"]}

def worker(state: dict):
    diff = run_in_worktree(state["sub_task"])
    return {"diffs": [diff]}

def fanout(state: State):
    return [Send("worker", {"sub_task": t}) for t in state["plan"]]

def reviewer(state: State):
    reviews = [review_with_other_vendor(d) for d in state["diffs"]]
    return {"reviews": reviews}

g = StateGraph(State)
g.add_node("planner", planner)
g.add_node("worker", worker)
g.add_node("reviewer", reviewer)
g.add_edge(START, "planner")
g.add_conditional_edges("planner", fanout, ["worker"])
g.add_edge("worker", "reviewer")
g.add_edge("reviewer", END)
app = g.compile()
app.invoke({"issue": "Add rate-limit middleware", "diffs": [], "reviews": []})

Philosophy: the workflow is a graph where every node's input and output is observable state. Send makes "plan then run N workers in parallel" a first-class pattern — ideal when you need precise branching and join semantics.

Good fit: complex flows with conditional branches and traceable state, especially inside the LangChain ecosystem. Not a good fit: quick role-based assembly or one-line cross-vendor harness swapping (LangGraph does not abstract harnesses; you wrap them yourself).

3. CrewAI — fast role-play assembly

CrewAI (docs) sells roles, tasks, and Crews. Define each agent's role and goal in natural language — closest to "get a group of people in a room."

from crewai import Agent, Task, Crew, Process

planner = Agent(role="Planner", goal="Break the issue into sub-tasks",
                backstory="You are a senior planner.", verbose=True)
coder_a = Agent(role="Backend Coder", goal="Implement middleware in worktree A",
                backstory="You write clean Python middleware.")
coder_b = Agent(role="Test Engineer", goal="Add tests in worktree B",
                backstory="You care about coverage.")
reviewer = Agent(role="Reviewer", goal="Cross-vendor review",
                 backstory="You review diffs from a different model family.")

t1 = Task(description="Plan sub-tasks for: {issue}", expected_output="3 sub-tasks", agent=planner)
t2 = Task(description="Implement middleware", expected_output="diff in worktree A", agent=coder_a)
t3 = Task(description="Add tests", expected_output="diff in worktree B", agent=coder_b)
t4 = Task(description="Review all diffs and list blockers", expected_output="review report", agent=reviewer)

crew = Crew(agents=[planner, coder_a, coder_b, reviewer],
            tasks=[t1, t2, t3, t4], process=Process.sequential, verbose=True)
crew.kickoff(inputs={"issue": "Add rate-limit middleware"})
# For parallel worktrees, use async_execution=True or nested crews

Philosophy: minimize the cost of defining a workflow by leaning on role descriptions and task prompts. Parallelism comes via async_execution and worktree wrappers, but isolation granularity and scheduling observability are weaker than LangGraph or Omnigent.

Good fit: prototypes, teams where non-engineers need to read the workflow, quick demos of multi-agent collaboration. Not a good fit: strong worktree isolation, auditable cross-vendor routing, or flows that need precise replay and debugging.

4. Goose — desktop automation via Recipe

Goose (website) is Block's open-source desktop agent. Its Recipe is a shareable YAML automation script — a natural way to turn Polly's steps into a one-click desktop task.

# recipe.yaml
version: 1.0.0
title: polly-rate-limit
description: Plan, parallel worktree, cross-vendor review
prompt: |
  Implement rate-limit middleware for the API.
  Steps: plan sub-tasks, create git worktrees, implement in parallel,
  then review each diff with a different model.
instructions: |
  Use shell tools to create worktrees under .worktrees/,
  run tests in each worktree, and collect diffs.
activities:
  - Plan sub-tasks and write to plan.md
  - Create worktrees: git worktree add .worktrees/a -b feat/rate-limit-a
  - Implement and test in each worktree
  - Review diffs and output report
extensions:
  - type: builtin
    name: developer
    display_name: Developer
    timeout: 300

Run: goose run --recipe recipe.yaml or load the Recipe in the Goose desktop app. Extend via MCP extensions for databases, browsers, or custom tools.

Philosophy: automation as a shareable desktop script with an emphasis on local execution and one-click replay. Parallel worktrees are created via shell tools; cross-vendor review requires separate model configs inside the Recipe — less declarative than Omnigent's executor.harness.

Good fit: personal desktop automation, solo validation, Recipe-based team sharing. Not a good fit: Server-side governance, persisted shared Sessions, or per-task cloud sandbox isolation.

Side-by-side comparison

DimensionOmnigent YAMLLangGraphCrewAIGoose
Abstractionmeta-harness above harnessesin-harness flow graphrole-and-task collaborationsingle-machine Recipe automation
Parallel worktreesnative (Polly)Send fan-out, you wrap gitasync_execution + tool wrappersshell tools, you build it
Cross-vendor revieweach sub-agent binds a different harnessroute to different models yourselfeach Agent with a different LLMswitch models inside Recipe
Governancethree-layer Policy + Omnibox sandboxnone built-in, add externallynone built-inlocal permissions + extensions
Observabilitypersisted Session + WebSocket syncstate and graph traversallogs and verbose outputlocal logs and Recipe report
Best formulti-harness teams needing collaboration and auditengineering teams needing precise flow controlrapid prototyping and non-engineering readabilityindividuals and small-team automation

Tokens, latency, and maintainability

Qualitative comparison — actual numbers depend on model choice, task granularity, and tool-call count. Run the same issue three times per stack and average.

  • Tokens: Omnigent and LangGraph have similar orchestration overhead; total tokens are dominated by sub-tasks × model calls. CrewAI's role prompts tend to add 10–20% system-prompt tokens; Goose Recipes are the leanest but grow once review logic is added back.
  • Latency: with three parallel workers, end-to-end latency approaches max(worker) rather than sum(worker). Omnigent and LangGraph achieve this via native fan-out; CrewAI defaults to Process.sequential and needs explicit async; Goose depends on how shell parallelism is implemented.
  • Maintainability: adding a reviewer in Omnigent is a one-line executor.harness change with policies centralized in policies; LangGraph makes flow changes traceable but requires editing nodes and edges per branch; CrewAI adds roles fastest but workflow is implicit in task ordering and can bloat; Goose Recipes are the most readable but grow quickly under complex branching and audit requirements.

Selection heuristic:

  • Already juggling multiple harnesses and need shareable live Sessions → Omnigent.
  • Complex flows needing reproducible conditional branches → LangGraph.
  • Fastest way to get a group of roles moving → CrewAI.
  • Single-machine automation you want to share as a desktop script → Goose.

They can also be stacked: Omnigent as the control plane, LangGraph for the worker's precise flow, CrewAI role descriptions for review, and a Goose Recipe for external distribution.

Overall

The same task reveals four different places to save effort: Omnigent saves cross-harness governance and collaboration cost, LangGraph saves debugging cost for complex flows, CrewAI saves the cost of getting a team together, and Goose saves the cost of turning steps into a replayable script. There is no universal winner — only which cost hurts most right now.

The next post returns to governance internals: Omnibox egress policies and secretless credential brokering for enterprise deployment.

References