Agentic Research

A Complete Tutorial for Open Multi-Agent (OMA): A TypeScript Multi-Agent Orchestration Framework from Goal to Task DAG

2026/06/2657 min readBryan Chan閱讀中文原文
TopicsMulti-AgentTypeScript

A Complete Tutorial for Open Multi-Agent (OMA)

TL;DR: OMA is a TypeScript-native multi-Agent orchestration framework. Its core selling point is Goal-First: you give it a goal, the Coordinator Agent automatically decomposes it into a Task DAG, executes independent tasks in parallel, and finally synthesizes the result. v1.8.0 adds Checkpoint resume and Consensus verification.

Why Is OMA Worth Watching?

The Agent framework market in 2026 is already highly mature:

FrameworkLanguageStarsCore Positioning
LangGraphPython + JS120K+Graph-First, precise control
CrewAIPython52.8KRole-Based, rapid prototyping
MastraTypeScript24.8KNative TS, Vercel deployment
OMATypeScript6.4KGoal-First, automatic DAG

OMA's differentiation lies in its Goal-First design: you do not need to predefine nodes and edges; you only describe the goal, and the framework generates the task graph automatically.


Core Concepts

Goal-First vs Graph-First

Graph-First (LangGraph approach):
  You define Node A → Node B → Node C → compile → execute
  Pros: precise control, predictable
  Cons: need to know all steps in advance

Goal-First (OMA approach):
  You describe the goal → Coordinator automatically generates a DAG → execute in parallel → synthesize results
  Pros: flexible, highly adaptable
  Cons: non-deterministic (decomposition may differ each time)

Architecture Panorama

┌─────────────────────────────────────────────────────────┐
│                    OpenMultiAgent                        │
│                                                          │
│  ┌──────────────┐     ┌──────────────────────────────┐  │
│  │  Coordinator │────▶│        TaskQueue              │  │
│  │  (Temporary Agent) │     │  - dependency graph           │  │
│  │  - Decompose goals   │     │  - auto unblock               │  │
│  │  - Generate DAG  │     │  - maxConcurrency (default: 5) │  │
│  └──────────────┘     └──────────────────────────────┘  │
│         │                        │                       │
│         ▼                        ▼                       │
│  ┌──────────────┐     ┌──────────────────────────────┐  │
│  │  AgentPool   │     │      SharedMemory             │  │
│  │  - Semaphore │     │  - Cross-Agent data sharing          │  │
│  │  - Parallel execution  │     │  - MemoryStore interface      │  │
│  └──────────────┘     └──────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

Quick Start

Installation

npm install @open-multi-agent/core

# Or run directly with npx
npx oma run --goal "Build a REST API" --team team.json

There are only 3 runtime dependencies: anthropic-ai/sdk, openai, and zod. The entire codebase is 27 source files, readable in an afternoon.

Your First Single Agent

import { OpenMultiAgent } from '@open-multi-agent/core'

const orchestrator = new OpenMultiAgent({
  defaultModel: 'deepseek-v4-flash',
  defaultProvider: 'deepseek',
})

const result = await orchestrator.runAgent(
  {
    name: 'assistant',
    systemPrompt: 'You are a helpful TypeScript expert.',
  },
  'Explain TypeScript generics in 3 sentences'
)

console.log(result.output)
// TypeScript generics allow you to write reusable code by parameterizing types,
// enabling functions and classes to work with any data type while maintaining
// type safety. They use angle bracket syntax (<T>) to declare type variables...

Your First Multi-Agent Team

import { OpenMultiAgent, type AgentConfig } from '@open-multi-agent/core'

const orchestrator = new OpenMultiAgent({
  defaultModel: 'deepseek-v4-flash',
  defaultProvider: 'deepseek',
})

// Define team members
const researcher: AgentConfig = {
  name: 'researcher',
  provider: 'deepseek',
  model: 'deepseek-v4-pro',
  systemPrompt: 'You research topics and gather concrete facts with sources.',
}

const writer: AgentConfig = {
  name: 'writer',
  provider: 'anthropic',
  model: 'claude-sonnet-4-6',
  systemPrompt: 'You turn research notes into clear, engaging prose.',
}

// Create team (enable shared memory)
const team = orchestrator.createTeam('content-team', {
  name: 'content-team',
  agents: [researcher, writer],
  sharedMemory: true,  // Key! Lets writer see researcher's findings
})

// Done in one call
const result = await orchestrator.runTeam(team, 'Write a guide on TypeScript decorators')

console.log(result.success)        // true
console.log(result.totalTokenUsage) // { input_tokens: 2847, output_tokens: 1203 }

What happened?

  1. The Coordinator received the goal and decomposed it into 3 research tasks + 1 writing task
  2. The 3 research tasks executed in parallel (no dependencies)
  3. The writing task waited for all research to finish before starting
  4. The Coordinator finally synthesized the final answer

Three Run Modes

Mode 1: runAgent(), Single Agent

The simplest entry point. One Agent, one prompt.

const result = await orchestrator.runAgent(agent, 'Your prompt here')

Mode 2: runTeam(), Automatic Orchestration

Give it a goal, and the framework plans automatically.

const result = await orchestrator.runTeam(team, 'Build a REST API with auth')

Note: the Coordinator is an LLM, so the decomposition may differ each time. If you need determinism, use runTasks().

Mode 3: runTasks(), Explicit Pipeline

You define the task graph yourself, fully controllable.

const result = await orchestrator.runTasks(team, [
  {
    title: 'Design schema',
    description: 'Design the database schema for a blog.',
    assignee: 'architect',
  },
  {
    title: 'Implement API',
    description: 'Build REST endpoints based on the schema.',
    assignee: 'developer',
    dependsOn: ['Design schema'],  // wait for schema to complete
  },
  {
    title: 'Write tests',
    description: 'Write unit tests for all endpoints.',
    assignee: 'tester',
    dependsOn: ['Implement API'],
  },
])

Provider Support (10+ Built-In)

OMA supports mixing different providers within the same team:

const team = orchestrator.createTeam('mixed-team', {
  name: 'mixed-team',
  agents: [
    // Anthropic Claude
    { name: 'architect', provider: 'anthropic', model: 'claude-opus-4-7',
      systemPrompt: 'You design systems.' },
    // OpenAI GPT
    { name: 'developer', provider: 'openai', model: 'gpt-4o',
      systemPrompt: 'You write code.' },
    // DeepSeek (cheap and easy to use)
    { name: 'reviewer', provider: 'deepseek', model: 'deepseek-v4-flash',
      systemPrompt: 'You review code.' },
    // MiniMax (domestic pride)
    { name: 'documenter', provider: 'minimax', model: 'MiniMax-M3',
      systemPrompt: 'You write docs.' },
    // Local model (Ollama)
    { name: 'helper', provider: 'openai', model: 'llama3',
      baseURL: 'http://localhost:11434/v1',
      apiKey: 'ollama',
      systemPrompt: 'You help with tasks.' },
  ],
  sharedMemory: true,
})

Full Provider List

ProviderConfigDefault ModelNotes
Anthropicprovider: 'anthropic'claude-sonnet-4-6Strongest reasoning
OpenAIprovider: 'openai'gpt-4oGeneral purpose
DeepSeekprovider: 'deepseek'deepseek-v4-flashKing of cost-performance
MiniMaxprovider: 'minimax'MiniMax-M3Top domestic choice
Geminiprovider: 'gemini'gemini-2.5-proGoogle ecosystem
Grokprovider: 'grok'grok-3xAI
Bedrockprovider: 'bedrock'-AWS enterprise-grade
Azureprovider: 'azure-openai'-Microsoft cloud
Copilotprovider: 'copilot'-GitHub
Ollamaprovider: 'openai' + baseURLCustomFree and local

Deep Dive into v1.8.0's New Features

1. Checkpoint & Resume

Long-running tasks can recover after a crash:

import { OpenMultiAgent, InMemoryStore } from '@open-multi-agent/core'

// Method 1: shorthand (using team's sharedMemoryStore)
const result = await orchestrator.runTeam(team, goal, {
  checkpoint: true,
})

// Method 2: specify an independent store
const result = await orchestrator.runTeam(team, goal, {
  checkpoint: {
    enabled: true,
    runId: 'production-run-001',  // must be provided
    store: new RedisStore(),       // Redis / Postgres / custom
  },
})

// Recovery after crash
const restored = await orchestrator.restore({
  team,
  runId: 'production-run-001',
})
// Completed task will be skipped, only the remaining part will be executed

Technical details:

  • Based on the MemoryStore interface, sharing the same storage layer as SharedMemory
  • Each completed task writes a snapshot (JSON format)
  • On resume, the Coordinator synthesis runs again
  • Task-level granularity recovery (an interrupted task restarts from the beginning, not mid-task)

Limitations:

  • Snapshot-based, not event-sourced (each snapshot overwrites the previous one)
  • If the checkpoint store and the sharedMemory store are the same, serialization is not duplicated (avoiding O(N²) writes)

2. Consensus Verification

A multi-Judge consensus verification mechanism that guards against a single Agent's errors:

const result = await orchestrator.runTeam(team, goal, {
  verifyJudges: [
    {
      name: 'critic-1',
      provider: 'anthropic',
      model: 'claude-opus-4-7',
      systemPrompt: 'You are a strict code reviewer. Find bugs and security issues.',
    },
    {
      name: 'critic-2',
      provider: 'openai',
      model: 'gpt-4o',
      systemPrompt: 'You verify factual accuracy and completeness.',
    },
  ],
})

Workflow:

  1. The Proposer Agent generates an answer
  2. The Judge Agents try to refute it
  3. If quorum is reached (majority agreement) → it passes
  4. If not → changes are required and verification repeats

3. CLI Dashboard

npx oma run --goal "Build a REST API" --team team.json --dashboard

Generates a static HTML page showing:

  • The Task DAG visualization
  • The execution time of each task
  • Token usage
  • The Agent assignment

CLI Usage (the oma binary)

OMA's CLI is designed JSON-first, suited to CI/CD integration:

# Installation
npm install -g @open-multi-agent/core

# Run
npx oma run --goal "Your goal" --team team.json

# Output to file
npx oma run --goal "..." --team team.json > result.json

# Pretty output
npx oma run --goal "..." --team team.json --pretty

# Include full message history
npx oma run --goal "..." --team team.json --include-messages

Team JSON Format

{
  "name": "my-team",
  "agents": [
    {
      "name": "researcher",
      "provider": "deepseek",
      "model": "deepseek-v4-pro",
      "systemPrompt": "You research topics thoroughly."
    },
    {
      "name": "writer",
      "provider": "anthropic",
      "model": "claude-sonnet-4-6",
      "systemPrompt": "You write clear, engaging content."
    }
  ],
  "sharedMemory": true
}

Exit Codes

CodeMeaningCI/CD Handling
0SuccessContinue
1Run completed but failedCheck result.json
2Input/file errorFix the configuration
3Crash or API errorRetry or alert

GitHub Actions Integration

name: AI Code Review
on: [pull_request]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm install @open-multi-agent/core
      - run: |
          npx oma run \
            --goal "Review the code changes in this PR for bugs, security issues, and style violations" \
            --team review-team.json \
            --pretty > review-result.json
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
      - run: |
          cat review-result.json | jq '.agentResults.coordinator.output'

Field Examples

Example 1: Contract Review DAG

import { OpenMultiAgent, type TaskConfig } from '@open-multi-agent/core'

const orchestrator = new OpenMultiAgent({
  defaultModel: 'claude-sonnet-4-6',
  defaultProvider: 'anthropic',
})

const team = orchestrator.createTeam('contract-review', {
  name: 'contract-review',
  agents: [
    { name: 'extractor', systemPrompt: 'Extract clauses from contracts.' },
    { name: 'compliance', systemPrompt: 'Check regulatory compliance.' },
    { name: 'summarizer', systemPrompt: 'Generate executive summaries.' },
    { name: 'notifier', systemPrompt: 'Generate final reports.' },
  ],
  sharedMemory: true,
})

const tasks: TaskConfig[] = [
  {
    title: 'extract-clauses',
    description: 'Extract all clauses from the contract into structured JSON.',
    assignee: 'extractor',
  },
  {
    title: 'compliance-check',
    description: 'Check each clause for regulatory compliance.',
    assignee: 'compliance',
    dependsOn: ['extract-clauses'],
    maxRetries: 2,
    retryDelayMs: 500,
    retryBackoff: 2,  // exponential backoff
  },
  {
    title: 'summary',
    description: 'Generate executive summary.',
    assignee: 'summarizer',
    dependsOn: ['extract-clauses'],
  },
  {
    title: 'final-report',
    description: 'Compile all analysis into a Markdown report.',
    assignee: 'notifier',
    dependsOn: ['compliance-check', 'summary'],
  },
]

const result = await orchestrator.runTasks(team, tasks)
// Task 2 (compliance) and Task 3 (summary) will run in parallel!

Example 2: Incident Postmortem

const team = orchestrator.createTeam('sre-team', {
  name: 'sre-team',
  agents: [
    { name: 'log-analyzer', systemPrompt: 'Analyze log patterns.' },
    { name: 'deploy-checker', systemPrompt: 'Check recent deployments.' },
    { name: 'impact-assessor', systemPrompt: 'Assess user impact.' },
    { name: 'hypothesizer', systemPrompt: 'Form root cause hypotheses.' },
    { name: 'writer', systemPrompt: 'Write postmortem documents.' },
  ],
  sharedMemory: true,
})

const result = await orchestrator.runTeam(team, `
  Analyze the incident logs from 2026-06-25 14:00-14:30 UTC.
  Correlate with recent deployments and produce a postmortem.
`)
// Coordinator automatically generates a DAG of 5 tasks
// The first 3 run in parallel → hypothesizer waits → writer last

Example 3: Cost-Tiered Pipeline

// Cheap models handle classification, expensive models handle creative work
const team = orchestrator.createTeam('cost-optimized', {
  name: 'cost-optimized',
  agents: [
    { name: 'classifier', provider: 'openai', model: 'gpt-4o-mini',
      systemPrompt: 'Classify support tickets by urgency.' },
    { name: 'responder', provider: 'anthropic', model: 'claude-opus-4-7',
      systemPrompt: 'Draft detailed responses for urgent tickets.' },
    { name: 'qa', provider: 'deepseek', model: 'deepseek-v4-flash',
      systemPrompt: 'Review responses for accuracy.' },
  ],
})
// Cost per 100 runs drops from $450 (all Opus) to ~$57

A Deep Dive into SharedMemory

SharedMemory is the core mechanism for communication between Agents:

// Method 1: In-memory storage (default)
const team = orchestrator.createTeam('team', {
  name: 'team',
  agents: [agent1, agent2],
  sharedMemory: true,  // Use InMemoryStore
})

// Method 2: Persistent storage (Redis)
class RedisStore implements MemoryStore {
  async get(key: string): Promise<string | null> { /* ... */ }
  async set(key: string, value: string): Promise<void> { /* ... */ }
  async list(prefix: string): Promise<string[]> { /* ... */ }
  async delete(key: string): Promise<void> { /* ... */ }
  async clear(): Promise<void> { /* ... */ }
}

const team = orchestrator.createTeam('durable-team', {
  name: 'durable-team',
  agents: [agent1, agent2],
  sharedMemoryStore: new RedisStore(),  // Takes precedence over sharedMemory: true
})

How it works:

  1. After each task completes, its result is written to SharedMemory
  2. The prompt of a downstream task automatically includes the upstream results
  3. Key format: <teamId>/<key>, with namespace isolation

Production Checklist

Before deploying OMA to production, confirm the following configuration:

ConcernConfig ItemLocation
Limit conversation lengthmaxTurns + contextStrategyAgentConfig
Limit tool outputmaxToolOutputCharsAgentConfig
Failure retrymaxRetries, retryDelayMs, retryBackoffTaskConfig
Budget controlmaxTokenBudgetOrchestratorConfig
Loop detectionloopDetection + onLoopDetectedOrchestratorConfig
Trace and auditonTraceOrchestratorConfig
Checkpoint resumecheckpoint: trueRunTeamOptions

Comparison with Loop Engineering

As OpenClaw users, we built our own Loop Engineering system. Here is a comparison of the two:

DimensionOMALoop Engineering
Task decompositionAutomatic DAG (LLM-driven)Seven-phase enforced engine
Verification mechanismConsensus (LLM Judge)External Supervisor
Permission controlNonePermission Matrix
Crash recovery✅ Checkpoint❌ None
Shared memory✅ MemoryStore❌ Agent isolation
CLIoma binaryloop_engine.py
LanguageTypeScriptPython
EcosystemnpmOpenClaw

Conclusion: OMA's Checkpoint and Consensus designs are worth borrowing, but Loop Engineering's External Supervisor is stronger in verification reliability.


Summary

FeatureRating
Design philosophy⭐⭐⭐⭐⭐ Goal-First is very elegant
Code quality⭐⭐⭐⭐⭐ 27 files, extremely readable
Provider support⭐⭐⭐⭐⭐ 10+ built-in, usable in combination
Production readiness⭐⭐⭐⭐ Checkpoint + Retry + Loop Detection
Community ecosystem⭐⭐⭐ 6.4K stars, growing
Documentation quality⭐⭐⭐⭐ Complete examples + official docs

Who is it for?

  • TypeScript backends that need multi-Agent orchestration
  • Those who do not want to predefine all steps
  • Those who need to mix multiple LLM providers
  • Those who need CLI/CI integration

Who is it not for?

  • Those who need precise control over every step (use LangGraph)
  • The Python ecosystem (use CrewAI)
  • Those who need full enterprise-grade governance (use LangGraph + LangSmith)

Reference Links