Mini-A supports delegation — the ability for a parent agent to spawn child Mini-A agents to handle sub-goals concurrently. This enables hierarchical problem decomposition, parallel execution, and distributed workloads across processes, containers, or hosts.
There are two delegation modes:
- Local Delegation — A parent Mini-A instance spawns child agents in the same process using async threads (
$doV) - Remote Delegation via Worker API — A headless HTTP API server (
mini-a-worker.yaml) that accepts goal requests and returns results
- You want the LLM to autonomously decide when to delegate sub-goals
- You need concurrent execution of independent subtasks within a single session
- You want to isolate child agent context from the parent (each child starts with a clean slate)
Set usedelegation=true when starting Mini-A:
mini-a usedelegation=true usetools=true goal="Coordinate multiple research tasks"Or in the interactive console:
mini-a
/set usedelegation true
/set usetools true| Parameter | Type | Default | Description |
|---|---|---|---|
usedelegation |
boolean | false |
Enable subtask delegation |
workers |
string | (none) | Comma-separated list of worker URLs. If provided, delegation routes to remote workers instead of local child agents |
usea2a |
boolean | false |
Use A2A HTTP+JSON/REST binding (/message:send, /tasks, /tasks:cancel) for remote worker transport |
workerreg |
number | (none) | Port to start worker registration HTTP server for dynamic worker discovery |
workerregtoken |
string | (none) | Bearer token required by /worker-register, /worker-deregister, and /worker-list |
workerevictionttl |
number | 60000 |
Heartbeat TTL (ms) before dynamic workers are auto-evicted |
maxconcurrent |
number | 4 |
Maximum concurrent child agents |
delegationmaxdepth |
number | 3 |
Maximum delegation nesting depth |
delegationtimeout |
number | 300000 |
Default subtask deadline (ms) |
delegationmaxretries |
number | 2 |
Default retry count for failed subtasks |
When workers is set, Mini-A fetches each worker's /.well-known/agent.json (canonical A2A AgentCard, protocol 0.4.0+) at startup and routes delegated subtasks by matching A2A skills first. It scores workers using skill IDs, tags, names, and examples against the subtask goal. Worker name and description are secondary signals. If multiple workers share the same effective profile, Mini-A uses round-robin within that group. It falls back to the best compatible worker when no strong skill match exists.
Set usea2a=true to switch the parent-to-worker transport from the legacy /task + /status + /result endpoints to the A2A HTTP+JSON/REST flow (POST /message:send, GET /tasks?id=..., POST /tasks:cancel).
When usedelegation=true and usetools=true:
- Mini-A registers two MCP tools:
delegate-subtaskandsubtask-status - The LLM can call
delegate-subtaskto spawn a child agent for a sub-goal - Child agents run independently with their own step budget, conversation history, and context
- Results are returned to the parent when the child completes
{
"goal": "Analyze the sales data for Q4",
"maxsteps": 10,
"timeout": 300,
"waitForResult": true,
"worker": "data-east",
"skills": ["data-analysis"]
}goal(required): The sub-goal for the child agentmaxsteps(optional): Maximum steps for the child (default: 10)timeout(optional): Deadline in seconds (default: 300)waitForResult(optional): Block until child completes (default: true)worker(optional): Partial name hint to prefer a specific remote worker (matched against name, description, URL)skills(optional): Array of required skill IDs or tags — only workers with all listed skills are considered (e.g.["shell"],["time"],["network","tls"])
Shell tasks: use
skills: ["shell"]to route to a shell-capable worker. Shell capability is declared by the worker via theshellA2A skill (setshellworker=truewhen starting the worker).
The tool description is dynamic — when remote workers are registered their names and skill IDs are listed so the LLM can make informed routing decisions.
Returns:
{
"subtaskId": "a1b2c3d4e5f6g7h8",
"status": "completed",
"answer": "Q4 sales increased by 23%...",
"error": null
}{
"subtaskId": "a1b2c3d4e5f6g7h8"
}Returns:
{
"subtaskId": "a1b2c3d4e5f6g7h8",
"status": "running",
"goal": "Analyze the sales data for Q4",
"createdAt": 1707235200000,
"startedAt": 1707235201000,
"completedAt": null,
"attempt": 1,
"maxAttempts": 2
}When delegation is enabled, you can manually delegate tasks from the interactive console:
# Delegate a sub-goal
/delegate Summarize the README.md file
# List all subtasks
/subtasks
# Show subtask details
/subtask a1b2c3d4
# Show subtask result
/subtask result a1b2c3d4
# Cancel a running subtask
/subtask cancel a1b2c3d4Set showdelegate=true to display child agent events as separate console lines instead of inline output.
- Clean Slate: Children start with no parent conversation history or state
- Config Inheritance: Children inherit model config (
OAF_MODEL,OAF_LC_MODEL) but can override specific parameters - Concurrency Control: Limited by
maxconcurrent(default 4) - Depth Tracking: Maximum nesting depth enforced (default 3)
- Automatic Retry: Failed subtasks retry up to
maxAttemptstimes with knowledge of previous failures - Deadline Enforcement: Tasks exceeding
deadlineMsare marked astimeout - Event Forwarding: Child interaction events forwarded to parent with
[subtask:id]prefix
// Parent goal: "Research and compare three cloud providers"
// The LLM might decide to delegate:
delegate-subtask({ goal: "Summarize AWS features and pricing" })
delegate-subtask({ goal: "Summarize Azure features and pricing" })
delegate-subtask({ goal: "Summarize GCP features and pricing" })
// All three run concurrently (up to maxconcurrent limit)
// Parent collects results and synthesizes comparison- You need to distribute agent workload across multiple processes/containers/hosts
- You want a headless API for programmatic agent invocation
- You need to scale horizontally with multiple worker instances
- You want isolation at the process/container level
# Start worker with bearer token authentication
mini-a workermode=true onport=8080 apitoken=your-secret-token
# Or without shell wrapper
ojob mini-a-worker.yaml onport=8080 apitoken=your-secret-token| Parameter | Type | Default | Description |
|---|---|---|---|
onport |
number | 8080 |
API server port |
apitoken |
string | (none) | Required bearer token for auth |
apiallow |
string | (none) | Comma-separated IP allowlist |
maxconcurrent |
number | 4 |
Maximum concurrent tasks |
defaulttimeout |
number | 300000 |
Default task deadline (ms) |
maxtimeout |
number | 600000 |
Maximum allowed deadline (ms) |
taskretention |
number | 3600 |
Seconds to keep completed results |
workername |
string | "mini-a-worker" |
Worker name reported by /info |
workerdesc |
string | "Mini-A worker API" |
Worker description reported by /info |
workerskills |
string | (none) | JSON/SLON array of A2A skill objects, or comma-delimited skill IDs (auto-expanded to minimal { id, name, tags } objects) |
workertags |
string | (none) | Comma-separated tags appended to the default run-goal worker skill |
workerspecialties |
string | (none) | Comma-separated specialty tags also injected into run-goal. Shorthand alternative to full workerskills JSON |
shellworker |
boolean | false |
Sets useshell=true and emits a shell A2A skill, enabling parent routing via skills=["shell"] |
workerregurl |
string | (none) | Comma-separated parent registration URL(s) to self-register with |
workerregtoken |
string | (none) | Bearer token used for registration endpoint authentication |
workerreginterval |
number | 30000 |
Heartbeat interval (ms) used to refresh registration |
Plus all standard Mini-A parameters: model, mcp, rules, knowledge, useshell, readwrite, maxsteps, etc.
The canonical A2A AgentCard (protocol 0.4.0+). Parent agents probe this endpoint first for worker discovery and skill-based routing.
curl http://localhost:8080/.well-known/agent.jsonResponse:
{
"protocolVersion": "0.4.0",
"name": "network-east",
"description": "Network diagnostics worker",
"url": "http://10.0.0.2:8081",
"preferredTransport": "HTTP+JSON",
"capabilities": { "streaming": false, "pushNotifications": false, "stateTransitionHistory": true },
"skills": [
{
"id": "network-latency",
"name": "Network latency",
"description": "Measure TCP and TLS latency for remote hosts",
"tags": ["network", "latency", "tls", "port"],
"examples": ["Measure latency to yahoo.co.jp:443"]
}
]
}Legacy endpoint (protocol 0.3.x compatibility). Returns capabilities and skills. limits.useshell was removed in protocol 0.4.0 — shell capability is now declared via the shell A2A skill.
Use A2A skills to make routing behave like tool selection. Workers advertise their skills; the parent's delegate-subtask tool lists them in its description so the LLM can route intelligently.
# Shell worker — use shellworker=true for automatic shell skill emission
mini-a workermode=true onport=8081 apitoken=secret \
workername="shell-worker" workerdesc="Shell execution worker" \
shellworker=true
# Network worker — comma shorthand for workerskills
mini-a workermode=true onport=8082 apitoken=secret \
workername="network-east" workerdesc="Network diagnostics worker" \
workerspecialties="network,latency,tls" \
workerskills='[{ "id": "network-latency", "name": "Network latency", "description": "Measure TCP and TLS latency for remote hosts", "tags": ["network","latency","tls","port"], "examples": ["Measure latency to yahoo.co.jp:443"] }]'
# Time worker — plain comma shorthand (auto-expands to minimal skill objects)
mini-a workermode=true onport=8083 apitoken=secret \
workername="time-worker" workerdesc="Timezone and current time worker" \
workerspecialties="time,timezone,clock"Mini-A also infers skills from enabled features: mcp=... entries, useutils=true, useskills=true, and useshell=true (emits shell skill). Explicit workerskills take precedence.
| Version | Profile endpoint | limits.useshell |
Shell routing |
|---|---|---|---|
| 0.3.x | GET /info (primary) |
Present | requiresShell flag on caller |
| 0.4.0 | GET /.well-known/agent.json (primary, /info fallback) |
Removed | shell A2A skill on worker |
Parents on 0.4.x probe /.well-known/agent.json first; if unavailable, fall back to /info. Workers on 0.3.x still interoperate — their limits.useshell field arrives but is ignored. The shell skill (absent on 0.3.x workers) will simply not match skills=["shell"] filter, which is correct: those workers haven't declared shell capability via the new protocol.
Submit a new task.
curl -X POST http://localhost:8080/task \
-H "Authorization: Bearer your-secret-token" \
-H "Content-Type: application/json" \
-d '{
"goal": "Analyze data and produce summary",
"args": {
"maxsteps": 10,
"useplanning": true,
"format": "json"
},
"timeout": 300,
"metadata": {
"parentTaskId": "uuid-parent",
"delegatedBy": "main-agent"
}
}'Request Fields:
goal(required): Goal for the agent (max 10K chars)args(optional): Agent configuration overrides (validated against allowlist)timeout(optional): Deadline in seconds (clamped tomaxtimeout)metadata(optional): Custom metadata for tracking
Allowed args keys:
goal, format, raw, chatbotmode, useplanning, updatefreq, updateinterval, forceupdates, planlog, planmode, planformat, convertplan, maxsteps
Response (202):
{
"taskId": "uuid-task-123",
"status": "queued",
"createdAt": "2026-02-06T17:00:00.000Z"
}Poll task status.
curl -X POST http://localhost:8080/status \
-H "Authorization: Bearer your-secret-token" \
-H "Content-Type: application/json" \
-d '{ "taskId": "uuid-task-123" }'Response:
{
"taskId": "uuid-task-123",
"status": "running",
"progress": {
"step": 3,
"maxSteps": 10
},
"startedAt": "2026-02-06T17:00:01.000Z",
"elapsed": 15000,
"events": [
{
"event": "💡",
"message": "Analyzing data...",
"ts": 1707235201000
}
]
}Status values: queued, running, completed, failed, cancelled, timeout
Retrieve final result.
curl -X POST http://localhost:8080/result \
-H "Authorization: Bearer your-secret-token" \
-H "Content-Type: application/json" \
-d '{ "taskId": "uuid-task-123" }'Response:
{
"taskId": "uuid-task-123",
"status": "completed",
"result": {
"goal": "Analyze data and produce summary",
"answer": "Summary: ...",
"format": "json",
"metrics": {},
"state": {},
"error": null
},
"completedAt": "2026-02-06T17:00:12.000Z",
"duration": 12000
}Cancel a running task.
curl -X POST http://localhost:8080/cancel \
-H "Authorization: Bearer your-secret-token" \
-H "Content-Type: application/json" \
-d '{
"taskId": "uuid-task-123",
"reason": "User cancelled"
}'Response:
{
"taskId": "uuid-task-123",
"status": "cancelled"
}The worker also exposes A2A-style HTTP+JSON endpoints aligned with section 11 of the A2A protocol specification:
POST /message:send— submits a task frommessage.parts[].textGET /tasks— lists known tasksGET /tasks?id=<taskId>— returns one task record (query parameter based lookup)POST /tasks:cancel— cancels a task using{ "id": "..." }or{ "taskId": "..." }GET /.well-known/agent.json— public Agent CardGET /extendedAgentCard— authenticated extended Agent Card
Example:
curl -X POST http://localhost:8080/message:send \
-H "Authorization: Bearer your-secret-token" \
-H "Content-Type: application/json" \
-d '{
"contextId": "ctx-1",
"message": {
"messageId": "msg-1",
"role": "ROLE_USER",
"parts": [{ "text": "Summarize the release blockers" }]
}
}'
curl -H "Authorization: Bearer your-secret-token" \
"http://localhost:8080/tasks?id=<taskId>"Health check endpoint (no auth required).
curl http://localhost:8080/healthzResponse:
{
"status": "ok",
"uptime": 123456
}Task and delegation metrics (no auth required).
curl http://localhost:8080/metricsResponse:
{
"tasks": {
"total": 10,
"queued": 1,
"running": 2,
"completed": 6,
"failed": 0,
"cancelled": 1
},
"delegation": {
"total": 10,
"running": 2,
"completed": 6,
"failed": 0,
"cancelled": 1,
"timedout": 0,
"retried": 1
}
}Dynamic registration allows worker pods to self-register to a parent Mini-A instance at startup and deregister on shutdown. Static workers= and dynamic workers coexist in the same pool.
workerreg=<port>starts a dedicated registration HTTP server.workerregtoken=<token>enables bearer authentication for registration endpoints.workerevictionttl=<ms>evicts dynamic workers that miss heartbeats beyond TTL.
workerregurl="<url1,url2>"enables self-registration against one or more parents.workerregtoken=<token>sendsAuthorization: Bearer <token>.workerreginterval=<ms>controls heartbeat frequency.
POST /worker-registerregisters or refreshes a worker.POST /worker-deregisterremoves a dynamic worker.GET /worker-listreturns worker list plus registration metrics.GET /healthzsimple liveness response.
- Dynamic workers get a heartbeat timestamp on registration.
- The watchdog checks heartbeats and auto-evicts stale dynamic workers.
- Static workers from
workers=are never removed by deregistration or TTL eviction.
# Main
mini-a usedelegation=true usetools=true \
workerreg=12345 workerregtoken=secret workerevictionttl=90000
# Worker pod/container
mini-a workermode=true onport=8080 apitoken=secret \
workerregurl="http://mini-a-main-reg:12345" \
workerregtoken=secret workerreginterval=30000# Start Mini-A with delegation
mini-a usedelegation=true usetools=true
# Goal that triggers delegation
Goal: "Fetch the weather for London, then summarize it"The LLM might use:
{
"thought": "I'll delegate the weather fetch to a child agent",
"action": "delegate-subtask",
"params": {
"goal": "Get current weather for London using an API",
"maxsteps": 5,
"useshell": false,
"waitForResult": true
}
}# Goal: "Compare performance of sorting algorithms"The LLM might spawn multiple children in parallel:
// Child 1: Benchmark bubble sort
delegate-subtask({ goal: "Benchmark bubble sort on 10K elements" })
// Child 2: Benchmark quicksort
delegate-subtask({ goal: "Benchmark quicksort on 10K elements" })
// Child 3: Benchmark merge sort
delegate-subtask({ goal: "Benchmark merge sort on 10K elements" })All run concurrently (up to maxconcurrent), then parent collects and compares results.
# Depth 0 (Parent): "Plan and execute a multi-phase project"
# Depth 1 (Child): "Research phase - gather requirements"
# Depth 2 (Child): "Summarize academic papers on topic X"Each level can delegate to the next, up to delegationmaxdepth.
# Terminal 1: Start worker
mini-a workermode=true onport=8080 apitoken=my-secret maxconcurrent=8
# Terminal 2: Submit task
curl -X POST http://localhost:8080/task \
-H "Authorization: Bearer my-secret" \
-H "Content-Type: application/json" \
-d '{
"goal": "Generate a technical report on quantum computing",
"args": { "maxsteps": 20, "format": "md" },
"timeout": 600
}'
# Returns: { "taskId": "abc123...", "status": "queued", ... }
# Poll for status
curl -X POST http://localhost:8080/status \
-H "Authorization: Bearer my-secret" \
-H "Content-Type: application/json" \
-d '{ "taskId": "abc123..." }'
# Get result when complete
curl -X POST http://localhost:8080/result \
-H "Authorization: Bearer my-secret" \
-H "Content-Type: application/json" \
-d '{ "taskId": "abc123..." }'# Parent instance with registration server
mini-a usedelegation=true usetools=true \
workerreg=12345 workerregtoken=secret workerevictionttl=90000
# Worker instances self-register and heartbeat
mini-a workermode=true onport=8080 apitoken=secret \
workerregurl="http://mini-a-main-reg:12345" \
workerregtoken=secret workerreginterval=30000- Worker API: Always set
apitoken=in production - Bearer token sent via
Authorization: Bearer <token>header - No OAuth or mTLS in v1
- Set
apiallow=to restrict access by IP:
mini-a workermode=true apitoken=secret apiallow="127.0.0.1,192.168.1.0/24"The worker API only accepts a whitelist of remote parameters (goal, format, maxsteps, etc.). Server-side config (like useshell, readwrite, mcp) cannot be overridden by clients.
- Children inherit
useshellfrom parent unless overridden - Worker API disables shell by default; enable with
useshell=trueat server startup
Maximum delegation depth prevents infinite recursion and resource exhaustion.
Delegation metrics are included in agent.getMetrics():
{
delegation: {
total: 10,
running: 2,
completed: 6,
failed: 1,
cancelled: 1,
timedout: 0,
retried: 2,
workers_total: 5,
workers_static: 1,
workers_dynamic: 4,
workers_healthy: 4,
avgDurationMs: 12500,
maxDepthUsed: 2
}
}/statsShows delegation metrics alongside other agent stats.
curl http://localhost:8080/metricsReturns task counts and delegation stats from the worker API.
Ensure usedelegation=true when starting Mini-A.
Increase delegationmaxdepth= or reduce nesting levels.
Increase delegationtimeout= or timeout parameter in task submission.
Check that Authorization: Bearer <token> header matches server's apitoken=.
Check maxconcurrent= setting and ensure parent has available slots.
- No webhooks/callbacks: Polling only for status/result
- No Docker isolation: Future phase
- Result size limits: Not enforced in v1 (may cause memory issues for very large results)
- No streaming: Entire result returned when task completes
- In-memory task queue: Task state does not survive worker restarts
mcp-mini-a.yaml: Exposes Mini-A as an MCP server (STDIO/HTTP) for integration with other MCP clients. Supports templating (servername=,servertitle=,tooldesc=,toolprefix=) to run purpose-specific agent personas from a single YAML.mcp-a2a.yaml: Bridges external Google A2A-protocol agents into Mini-A as MCP tools. Discovers skills via/.well-known/agent.jsonAgent Cards and routes tasks via JSON-RPC 2.0 — enabling interoperability with LangGraph, Vertex AI ADK, CrewAI, and other A2A frameworks.mini-a-worker.yaml: Headless REST API for programmatic goal execution.
They are complementary:
- Use
mcp-mini-a.yamlwhen you want Mini-A to be discoverable as an MCP tool by other agents or clients - Use
mcp-a2a.yamlwhen you want Mini-A to call out to external A2A-compatible agents as tools - Use
mini-a-worker.yamlwhen you want a pure HTTP API for task submission
All three can run simultaneously if needed.
- Webhook/callback support for async notifications
- Docker container isolation for child agents
- Streaming results via SSE
- Persistent task queue (survives worker restart)
- Result size limits and compression
Mini-A delegation enables:
✅ Hierarchical problem decomposition — Break complex goals into manageable subtasks
✅ Parallel execution — Run independent subtasks concurrently
✅ Context isolation — Each child starts with a clean slate
✅ Distributed workloads — Scale across processes/containers/hosts via Worker API
✅ Autonomous delegation — LLM decides when to delegate
✅ Manual delegation — Use console commands for interactive control
Combine local and remote delegation to build sophisticated multi-agent workflows!