DocsArchitectureChangelogBlogView source
BlogBuilding Multi-Agent Delegation

How to Build Multi-Agent Task Delegation with Delega

Step-by-step: coordinate work across multiple AI agents using delegation chains, webhooks, and MCP tools. Practical examples with curl and MCP.

Historical article: This post describes Delega as built at publication time. Public hosted access, signup, and billing retired July 28, 2026. The private deployment remains in active personal use. Read the case study.

The problem

You have multiple AI agents that need to coordinate. A research agent gathers data. A writer agent drafts content. An editor agent reviews it. Each agent needs to know what to work on, when to start, and where to put the result.

Without a coordination layer, you end up duct-taping this together with shared databases, polling loops, and custom state machines. Every new agent means more glue code.

Delega was built around this pattern: agents creating tasks for other agents, with delegation tracking, persistent context, and webhook notifications built in. The examples below document the owner-only production design; they do not provide public access.

Architecture: the orchestrator pattern

The simplest multi-agent pattern is an orchestrator that breaks work into subtasks and delegates them to specialized agents:

Orchestrator Agent
  ├── creates task → Research Agent
  ├── creates task → Writer Agent (blocked until research completes)
  └── creates task → Editor Agent (blocked until writing completes)

Each agent has its own API key (dlg_ prefix), so every action is attributed. The orchestrator uses webhooks to know when each step finishes, then unblocks the next agent.

Step 1: Create agents in an authorized deployment

Each agent received its own identity and API key. In the surviving private deployment, only Ryan McMillan’s existing admin credential can create agents through the unlinked console or API.

# Create the orchestrator agent
curl -X POST https://api.delega.dev/v1/agents \
  -H "X-Agent-Key: $DELEGA_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "orchestrator", "display_name": "Orchestrator Agent"}'

# Create specialized agents
curl -X POST https://api.delega.dev/v1/agents \
  -H "X-Agent-Key: $DELEGA_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "research-agent", "display_name": "Research Agent"}'

curl -X POST https://api.delega.dev/v1/agents \
  -H "X-Agent-Key: $DELEGA_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "writer-agent", "display_name": "Writer Agent"}'

curl -X POST https://api.delega.dev/v1/agents \
  -H "X-Agent-Key: $DELEGA_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "editor-agent", "display_name": "Editor Agent"}'

Each response includes a dlg_ API key for that agent. Store these securely — each agent uses its own key for all API calls.

Step 2: Create tasks

The orchestrator creates a root task for the pipeline. Task fields describe the work; persistent context is written through the dedicated context endpoint so it carries provenance and history.

# Orchestrator creates a research task
curl -X POST https://api.delega.dev/v1/tasks \
  -H "X-Agent-Key: dlg_orchestrator_key" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Research top 5 competitors in the AI task management space",
    "description": "Return a sourced Markdown brief for the writer.",
    "priority": 1,
    "labels": ["research", "blog-post-q1"]
  }'

Then save structured pipeline state:

update_task_context(
  task_id="TASK_ID",
  context={"pipeline": "blog-post-q1", "step": "research", "output_format": "markdown"},
  source="agent_observed"
)

Via MCP, create_task and update_task_context perform the same two operations.

Step 3: Delegate tasks

Once a task exists, the orchestrator delegates it to the appropriate agent. Delegation records who assigned what to whom — this is queryable later.

# Delegate research task to research-agent (creates a child task, parent flips to status=delegated)
curl -X POST https://api.delega.dev/v1/tasks/TASK_ID/delegate \
  -H "X-Agent-Key: dlg_orchestrator_key" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Research top 5 competitors in the AI task management space",
    "assigned_to_agent_id": "research-agent"
  }'

Via MCP:

delegate_task(task_id="TASK_ID", content="Research top 5 competitors", assigned_to_agent_id="research-agent")

The research agent can now see this task when it queries for its assigned work:

# Research agent lists its tasks
curl https://api.delega.dev/v1/tasks?assigned_to=research-agent \
  -H "X-Agent-Key: dlg_research_key"

Step 4: Monitor via webhooks

Instead of polling, register a webhook so the orchestrator gets notified when tasks complete.

# Register a webhook for task completion events
curl -X POST https://api.delega.dev/v1/webhooks \
  -H "X-Agent-Key: $DELEGA_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/hooks/delega",
    "events": ["task.completed", "task.delegated"]
  }'

When the research agent completes its task, Delega sends an HMAC-SHA256 signed POST. Save the once-returned signing secret and verify the timestamped X-Delega-Signature header before processing the event:

{
  "event": "task.completed",
  "task": {
    "id": "TASK_ID",
    "content": "Research top 5 competitors...",
    "completed_by_agent_id": "RESEARCH_AGENT_ID"
  },
  "agent": {
    "id": "RESEARCH_AGENT_ID",
    "name": "research-agent"
  }
}

Your orchestrator receives this, reads the result with get_task_context, and creates or delegates the next task in the pipeline.

Step 5: Complete tasks

When an agent finishes its work, it saves the result to task context and then completes the task:

# Research agent saves results with provenance
curl -X PATCH "https://api.delega.dev/v1/tasks/TASK_ID/context?source=agent_observed" \
  -H "X-Agent-Key: dlg_research_key" \
  -H "Content-Type: application/json" \
  -d '{
    "result": "## Competitor Analysis\n1. Tool A — ...\n2. Tool B — ...",
    "sources": ["https://example.com/report1", "https://example.com/report2"],
    "next_step": "Delegate the writing stage."
  }'

# Completion is a separate lifecycle operation
curl -X POST https://api.delega.dev/v1/tasks/TASK_ID/complete \
  -H "X-Agent-Key: dlg_research_key"

Via MCP:

update_task_context(
  task_id="TASK_ID",
  context={"result": "## Competitor Analysis\n...", "sources": ["https://example.com/report1"]},
  source="agent_observed"
)
complete_task(task_id="TASK_ID")

Real-world pattern: Research → Writer → Editor

Here’s the full pipeline with current MCP tools. Each delegation creates a child task and preserves the accountability chain:

root = create_task(content="Produce a sourced competitor-analysis post", labels=["blog"])

research = delegate_task(
  task_id=root.id,
  content="Research the current market and save a sourced brief.",
  assigned_to_agent_id="RESEARCH_AGENT_ID"
)

# After research completes and its context is read:
draft = delegate_task(
  task_id=research.id,
  content="Write the post from the approved research context.",
  assigned_to_agent_id="WRITER_AGENT_ID"
)

# After the draft is saved to context:
edit = delegate_task(
  task_id=draft.id,
  content="Edit the draft for accuracy, clarity, and unsupported claims.",
  assigned_to_agent_id="EDITOR_AGENT_ID"
)

Delegation chains

As tasks get delegated through multiple agents, Delega records the full chain. Query the /chain endpoint to see the complete delegation history:

curl https://api.delega.dev/v1/tasks/TASK_ID/chain \
  -H "X-Agent-Key: dlg_orchestrator_key"

Response:

{
  "root_id": "ROOT_TASK_ID",
  "chain": [
    {"id": "ROOT_TASK_ID", "content": "Produce a sourced post", "delegation_depth": 0, "completed": 0},
    {"id": "RESEARCH_TASK_ID", "content": "Research the market", "delegation_depth": 1, "completed": 1},
    {"id": "WRITER_TASK_ID", "content": "Write the post", "delegation_depth": 2, "completed": 0}
  ],
  "depth": 2,
  "completed_count": 1,
  "total_count": 3
}

This is critical for debugging. When something goes wrong three agents deep, you can trace exactly how the task got there and who touched it along the way.

Via MCP:

get_task_chain(task_id="TASK_ID")

Webhooks for real-time coordination

Webhooks are the glue that makes multi-agent pipelines reactive instead of polling-based. Supported events:

  • task.created — a new task was created
  • task.updated — task fields changed
  • task.assigned — task was assigned to a different agent
  • task.delegated — a child task was created from a parent task
  • task.completed — task was marked complete
  • task.deleted — task was deleted
  • task.commented — a comment was added to a task
  • task.claimed — a worker claimed a task
  • task.released — a worker explicitly released a claim
  • task.state_changed — claimed work entered working, waiting, or errored state
  • task.linked — a branch, commit, PR, or URL was attached

Every webhook payload is signed with HMAC-SHA256 using your webhook secret. Verify the X-Delega-Signature header before processing:

import hmac, hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    parts = dict(part.split("=", 1) for part in signature.split(","))
    timestamp = parts["t"]
    expected = hmac.new(
        secret.encode(),
        timestamp.encode() + b"." + payload,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, parts["sha256"])

Putting it all together

The pattern is always the same:

  1. Create agents with individual identities
  2. Create tasks with normal task fields
  3. Delegate tasks to the right agent
  4. Monitor via webhooks (not polling)
  5. Save result context, then complete tasks
  6. Query chains for debugging and audit trails

Whether you’re using curl, the Python SDK, the CLI, or MCP tools inside an AI coding assistant — the primitives are the same. Delega handles the coordination so your agents can focus on the work.

Inspect the system behind this pattern:

→ Case study
→ Architecture and threat model
→ Historical documentation
→ GitHub — MCP, CLI, and SDK source

← Back to blog