Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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<InputSchema>
Expand Down Expand Up @@ -106,7 +108,8 @@ export const TeamCreateTool: Tool<InputSchema, Output> = 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() {
Expand Down Expand Up @@ -239,6 +242,8 @@ export const TeamCreateTool: Tool<InputSchema, Output> = 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.`,
},
}
},
Expand Down
14 changes: 13 additions & 1 deletion packages/builtin-tools/src/tools/TeamCreateTool/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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@<team_name>\`)** — 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: <lead_agent_id from step 1>, ...) — 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.
Expand Down
11 changes: 11 additions & 0 deletions packages/builtin-tools/src/tools/shared/spawnMultiAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading