From ac570f32e02158abed6b0e9cfde2b170a76b97d5 Mon Sep 17 00:00:00 2001 From: James Feng <47167674+GhostDragon124@users.noreply.github.com> Date: Fri, 12 Jun 2026 18:54:09 +0800 Subject: [PATCH 1/3] fix(TeamCreate): warn model that lead already exists, add status fields - description(): explicit 'never spawn with Agent' warning to block redundant Agent calls at planning stage - Output type: add lead_agent_status + next_step fields to reinforce correct next action in return value --- .../src/tools/TeamCreateTool/TeamCreateTool.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/builtin-tools/src/tools/TeamCreateTool/TeamCreateTool.ts b/packages/builtin-tools/src/tools/TeamCreateTool/TeamCreateTool.ts index 3a2f8aee..138b9137 100644 --- a/packages/builtin-tools/src/tools/TeamCreateTool/TeamCreateTool.ts +++ b/packages/builtin-tools/src/tools/TeamCreateTool/TeamCreateTool.ts @@ -53,6 +53,8 @@ export type Output = { team_name: string team_file_path: string lead_agent_id: string + lead_agent_status: string + next_step: string } export type Input = z.infer @@ -106,7 +108,8 @@ export const TeamCreateTool: Tool = buildTool({ }, async description() { - return 'Create a new team for coordinating multiple agents' + return 'Create a new team with an automatically-started lead agent. ' + + 'The lead already exists after this call — never spawn it with Agent.' }, async prompt() { @@ -239,6 +242,8 @@ export const TeamCreateTool: Tool = buildTool({ team_name: finalTeamName, team_file_path: teamFilePath, lead_agent_id: leadAgentId, + lead_agent_status: `already running — created by TeamCreate, do not spawn`, + next_step: `SendMessage(to: "${leadAgentId}"). Use Agent only for additional teammates.`, }, } }, From 69f6b8025064f3e25345cc90b3520b50f5fe0795 Mon Sep 17 00:00:00 2001 From: James Feng <47167674+GhostDragon124@users.noreply.github.com> Date: Fri, 12 Jun 2026 18:54:13 +0800 Subject: [PATCH 2/3] fix(TeamCreate): replace unconditional spawn imperative with explicit warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace 'Spawn teammates using Agent' with conditional: 'only when task genuinely needs more than one agent' - Name the exact wrong action: 'do NOT pass name: team-lead to Agent' - Add Minimal Lifecycle section showing 3-step single-agent path (TeamCreate→SendMessage→TeamDelete) with zero Agent calls --- .../src/tools/TeamCreateTool/prompt.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/builtin-tools/src/tools/TeamCreateTool/prompt.ts b/packages/builtin-tools/src/tools/TeamCreateTool/prompt.ts index dddf6fb1..523cc281 100644 --- a/packages/builtin-tools/src/tools/TeamCreateTool/prompt.ts +++ b/packages/builtin-tools/src/tools/TeamCreateTool/prompt.ts @@ -38,12 +38,24 @@ This creates: 1. **Create a team** with TeamCreate - this creates both the team and its task list 2. **Create tasks** using the Task tools (TaskCreate, TaskList, etc.) - they automatically use the team's task list -3. **Spawn teammates** using the Agent tool with \`team_name\` and \`name\` parameters to create teammates that join the team +3. **Spawn teammates** (beyond the lead) using the Agent tool with \`team_name\` and \`name\` parameters — but only when the task genuinely needs more than one agent. **TeamCreate already creates the lead (\`team-lead@\`)** — do NOT pass \`name: "team-lead"\` to the Agent tool; that creates a duplicate agent, not the lead. Talk to the lead with SendMessage using the returned lead_agent_id. 4. **Assign tasks** using TaskUpdate with \`owner\` to give tasks to idle teammates 5. **Teammates work on assigned tasks** and mark them completed via TaskUpdate 6. **Teammates go idle between turns** - after each turn, teammates automatically go idle and send a notification. IMPORTANT: Be patient with idle teammates! Don't comment on their idleness until it actually impacts your work. 7. **Shutdown your team** - when the task is completed, gracefully shut down your teammates via SendMessage with \`message: {type: "shutdown_request"}\`. +## Minimal Lifecycle (Single-Agent Task) + +When the task needs only one agent (not a multi-agent parallel workload), do NOT spawn additional teammates. The lead agent created by TeamCreate is sufficient: + +\`\`\` +1. TeamCreate(team_name: "my-sweep") +2. SendMessage(to: , ...) — the lead receives and processes your instructions +3. TeamDelete(team_name: "my-sweep") +\`\`\` + +Use the Agent tool only to add teammates BEYOND the lead, and only when the task genuinely needs multiple agents working in parallel. + ## Task Ownership Tasks are assigned using TaskUpdate with the \`owner\` parameter. Any agent can set or change task ownership via TaskUpdate. From e0687ea48af8fca0abe716ee83ce43a2ca24e566 Mon Sep 17 00:00:00 2001 From: James Feng <47167674+GhostDragon124@users.noreply.github.com> Date: Fri, 12 Jun 2026 18:54:17 +0800 Subject: [PATCH 3/3] fix(Agent): reject 'team-lead' spawn with redirect error, not silent dedup - generateUniqueTeammateName now throws when baseName is 'team-lead' and already exists in team members (created by TeamCreate) - Error message redirects: 'Use SendMessage to communicate with the lead' - Previously silently deduped to team-lead-2, cascading into wrong SendMessage recipients and blocked TeamDelete --- .../builtin-tools/src/tools/shared/spawnMultiAgent.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/builtin-tools/src/tools/shared/spawnMultiAgent.ts b/packages/builtin-tools/src/tools/shared/spawnMultiAgent.ts index 78d81102..6dd193da 100644 --- a/packages/builtin-tools/src/tools/shared/spawnMultiAgent.ts +++ b/packages/builtin-tools/src/tools/shared/spawnMultiAgent.ts @@ -279,6 +279,17 @@ export async function generateUniqueTeammateName( const existingNames = new Set(teamFile.members.map(m => m.name.toLowerCase())) + // If the caller tries to spawn "team-lead" which already exists (created by + // TeamCreate), fail with a redirect — silently deduping to "team-lead-2" + // would cascade into wrong SendMessage recipients and blocked TeamDelete. + if (baseName.toLowerCase() === TEAM_LEAD_NAME && existingNames.has(TEAM_LEAD_NAME)) { + throw new Error( + `"${TEAM_LEAD_NAME}" already exists in team "${teamName}" — it was created by TeamCreate. ` + + `Use SendMessage to communicate with the lead. ` + + `To add a different teammate, choose another name.`, + ) + } + // If the base name doesn't exist, use it as-is if (!existingNames.has(baseName.toLowerCase())) { return baseName