title: Regnify Tool: spawn_agent¶
Regnify Tool: spawn_agent¶
Purpose¶
spawn_agent creates a short-lived sub-agent to handle an independent sub-task in parallel with other work. It is the concurrency primitive in the chatbot tool ecosystem -- use it when the user's request decomposes cleanly into 2+ independent work items that do not need to share intermediate state. The parent chatbot issues N concurrent spawn_agent calls in one turn; each sub-agent runs with a restricted tool allowlist on a fresh context; results return as tool-result messages for the parent's next turn to synthesize.
Do NOT use for: single-lookup questions, work items that must execute in sequence, or sub-tasks that need the parent's intermediate reasoning. Sub-agents are stateless workers -- they cannot call spawn_agent themselves (max nesting = 0).
Signature¶
spawn_agent(ctx, prompt: str, tools_subset: list[str], timeout: int = 120) -> SubAgentResult
Parameters¶
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
prompt |
str |
Yes | -- | Natural-language sub-task description. Must be at least 10 characters (at least one complete sentence). Validated: too-short prompts return status="error". |
tools_subset |
list[str] |
Yes | -- | Non-empty allowlist of tool names the sub-agent may call. Must be names from the tool registry. "spawn_agent" is stripped unconditionally (max nesting = 0). Unknown tool names are rejected with an error. |
timeout |
int |
No | 120 |
Per-sub-agent wall-clock budget in seconds. Hard-capped at 300. Must be positive. Timeouts return status="timeout" with partial results rather than raising. |
Concurrency Model¶
Concurrent Limit: 10 Per Turn (Hard Cap)¶
The parent chatbot loop uses a single asyncio.Semaphore(10) that bounds all parallel tool calls in one turn -- not just spawn_agent calls but any concurrent tool invocations. When the user's request requires more than 10 sub-agents:
- Issue 10
spawn_agentcalls in the current turn. - Read all 10 results when they return.
- Issue the next batch of up to 10 in the next turn.
- Repeat until all N sub-tasks are complete.
The sub-agents within a batch run truly concurrently (each in its own asyncio.Task). The semaphore throttles how many start simultaneously but does not serialize them once running.
Max Nesting: 0¶
Sub-agents cannot call spawn_agent. If "spawn_agent" appears in tools_subset, validation returns status="error" with the message: "spawn_agent failed: sub-agents cannot spawn further sub-agents (max nesting = 0). Remove \"spawn_agent\" from tools_subset.". This is enforced client-side in _validate_spawn_args before the sub-agent even starts.
Validation Rules (Pre-Launch)¶
All validation runs BEFORE the sub-agent is spawned. Validation failures return a SubAgentResult with status="error" and the error message in the error field -- the parent LLM sees this as a normal tool result, not an exception.
| Validation | Error Message |
|---|---|
prompt is not a string or < 10 chars |
"spawn_agent failed: prompt too short (N chars); describe the sub-task in at least one complete sentence." |
tools_subset is empty (falsy list) |
"spawn_agent failed: tools_subset must be a non-empty allowlist. For read-only research, try [\"search_mas_knowledge\", \"read_document\"]." |
"spawn_agent" in tools_subset |
"spawn_agent failed: sub-agents cannot spawn further sub-agents (max nesting = 0). Remove \"spawn_agent\" from tools_subset." |
Unknown tool name in tools_subset |
"spawn_agent failed: unknown tool \"X\". Valid tools: ..." (lists all valid tool names from the registry) |
timeout > 300 |
"spawn_agent failed: timeout Ns exceeds 300s cap." |
timeout <= 0 |
"spawn_agent failed: timeout Ns must be positive." |
Available Tools for Sub-Agents¶
Sub-agents can use any tool from the main tool registry except spawn_agent. The valid tool list (resolved at call time from the registry) includes:
search_mas_knowledge-- KB search (common for research sub-tasks)read_document-- fetch full document nodesget_declaration-- fetch a specific declarationget_workflow_state-- fetch workflow approval statevalidate_nric-- NRIC checksum validationanalyze_cert_gap-- CMFAS gap analysisget_rep_register-- org-wide rep rosterget_cpd_status-- CPD hour totals for a repdraft_cpd_reminder-- draft CPD reminder emaillaunch_attestation_cycle-- create attestation cycledetect_attestation_anomaly-- anomaly review for a repcreate_incident_declaration-- file an incidentgenerate_passport-- issue/rotate passport token
Common tools_subset Recommendations¶
| Sub-Task Type | Recommended tools_subset |
|---|---|
| Read-only KB research | ["search_mas_knowledge", "read_document"] |
| Per-rep anomaly scan | ["detect_attestation_anomaly"] |
| Per-rep CPD check | ["get_cpd_status"] |
| Per-rep CMFAS gap | ["analyze_cert_gap"] |
| Multi-angle regulation comparison | ["search_mas_knowledge", "read_document"] |
Give each sub-agent only the tools it needs. Over-provisioning tools_subset wastes context window space and increases the chance of incorrect tool selection.
Return Shape (SubAgentResult)¶
{
"text": "<sub-agent's final assistant message or empty string on error/timeout>",
"tool_calls": [<list of tool call dicts the sub-agent made>],
"tokens_in": <int>,
"tokens_out": <int>,
"wall_ms": <int>,
"status": "ok" | "timeout" | "error",
"error": "<string or null>"
}
Status Values¶
| Status | Meaning | text Field |
|---|---|---|
"ok" |
Sub-agent completed successfully | Contains the sub-agent's final assistant message |
"timeout" |
Wall-clock budget exceeded | Empty string -- sub-agent was killed mid-execution |
"error" |
Validation failure or runtime exception | Empty string -- error field carries the message |
The tool_calls, tokens_in, tokens_out, and wall_ms fields are audit metadata -- the parent LLM typically only needs text and status to synthesize results.
Use Cases¶
1. Batch Attestation Anomaly Scan¶
User: "Scan all 50 reps in org 1 for attestation anomalies in cycle abc-123."
Strategy:
1. Call get_rep_register(org={"kind":"org","id":1}) to get rep list.
2. Split 50 reps into 5 batches of 10.
3. Turn 1: Issue 10 spawn_agent calls, each with prompt="Review rep {id} for anomalies in cycle abc-123", tools_subset=["detect_attestation_anomaly"], timeout=180.
4. Turn 2: Issue next 10, etc.
5. Final turn: Synthesize all results into a summary table: rep ID, status, severity, fields_flagged count.
2. Parallel KB Research¶
User: "Compare the fitness and propriety requirements under FAA vs SFA."
Strategy:
1. Turn 1: Issue 2 spawn_agent calls in parallel:
- Agent A: prompt="Find all FAA fitness and propriety requirements", tools_subset=["search_mas_knowledge", "read_document"]
- Agent B: prompt="Find all SFA fitness and propriety requirements", tools_subset=["search_mas_knowledge", "read_document"]
2. Turn 2: Synthesize both findings into a comparison.
3. Multi-Rep CPD Status Check¶
User: "Check CPD status for reps 10, 11, 12, 13, 14."
Strategy:
1. Turn 1: Issue 5 concurrent spawn_agent calls (under the 10 cap), each with tools_subset=["get_cpd_status"].
2. Turn 2: Tabulate all 5 CPD totals.
Cost Transparency Rule¶
Always inform the user before fanning out. Before issuing spawn_agent calls, tell the user:
"This will spawn N sub-agents, each checking [task]. Estimated time: approximately Y minutes (N agents x Z seconds each, running in parallel batches of 10)."
This gives the user a chance to narrow scope if the fan-out would be expensive.
Timeout Behaviour¶
- Default timeout: 120 seconds per sub-agent.
- Hard cap: 300 seconds (5 minutes) per sub-agent.
- On timeout: the sub-agent's
asyncio.Taskis cancelled; the partially-collected result is returned withstatus="timeout"andtext="". - The parent should treat timeout results as partial data. Relay what was gathered and offer to retry the timed-out sub-agents.
Important Rules¶
- 10 concurrent max per turn -- split larger workloads into batches.
- No nesting -- sub-agents cannot spawn further sub-agents.
- tools_subset must be non-empty and valid -- check the error message if validation fails.
- Prompt must be meaningful -- at least one complete sentence describing the sub-task.
- Inform user before fanning out -- cost transparency is mandatory.
- Synthesize results -- the parent's job is to aggregate sub-agent outputs into a coherent response. Do not dump raw SubAgentResult dicts to the user.