From 49e46da563be4c091578a75ded7932596f32aac7 Mon Sep 17 00:00:00 2001 From: iliya Date: Tue, 7 Apr 2026 13:25:25 +0300 Subject: [PATCH] fix(team): allow agent only in do mode for leads --- src/main/services/team/TeamProvisioningService.ts | 3 ++- src/main/services/team/actionModeInstructions.ts | 8 ++++++-- test/main/ipc/teams.test.ts | 5 +++++ .../team/TeamProvisioningServicePrompts.test.ts | 10 ++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index 4285cc46..54b8b0ce 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -172,7 +172,7 @@ const TASK_WAIT_FALLBACK_MS = 15_000; const STALL_CHECK_INTERVAL_MS = 10_000; const STALL_WARNING_THRESHOLD_MS = 20_000; const APP_TEAM_RUNTIME_DISALLOWED_TOOLS = - 'TeamDelete,TodoWrite,TaskCreate,TaskUpdate,Agent,mcp__agent-teams__team_launch,mcp__agent-teams__team_stop'; + 'TeamDelete,TodoWrite,TaskCreate,TaskUpdate,mcp__agent-teams__team_launch,mcp__agent-teams__team_stop'; const TEAM_JSON_READ_TIMEOUT_MS = 5_000; const TEAM_CONFIG_MAX_BYTES = 10 * 1024 * 1024; const TEAM_INBOX_MAX_BYTES = 2 * 1024 * 1024; @@ -1561,6 +1561,7 @@ Constraints: - In a non-solo team, your default first move is delegation, NOT personal investigation. Do NOT read/search the codebase, inspect files, or do root-cause research yourself just to figure out ownership or scope before delegating. - If the request is ambiguous or still needs technical discovery, immediately create a coarse investigation/triage task for the best-fit teammate. That teammate owns the code inspection, scope refinement, and creation of any follow-up tasks needed for execution. - Only do lead-side research first if the human explicitly asked YOU for analysis/planning, or if there is genuinely no appropriate teammate to own the investigation. +- Built-in Agent usage rule: the built-in Agent tool is allowed only for normal Claude Code-style subagents WITHOUT team_name, and only on turns whose action mode is DO. In ASK or DELEGATE mode, treat Agent as forbidden. Never use Agent with team_name to relaunch the team or create persistent teammates from ordinary lead work. - Do NOT use the built-in TaskCreate tool for team-board tasks. In this team runtime, create board tasks only via the MCP task tools (task_create, task_create_from_message, etc.). - When messaging "user" (the human): write plain human language. If a task needs a status update, do it yourself via the board MCP tools; never ask the user to run a command.${soloConstraint} diff --git a/src/main/services/team/actionModeInstructions.ts b/src/main/services/team/actionModeInstructions.ts index ae6692a1..589c8ca1 100644 --- a/src/main/services/team/actionModeInstructions.ts +++ b/src/main/services/team/actionModeInstructions.ts @@ -13,13 +13,16 @@ const ACTION_MODE_BLOCKS: Record = { 'TURN ACTION MODE: DO', '- This turn is full-execution mode.', '- You may discuss, read, edit files, change state, run commands/tools, and delegate if useful.', + '- Agent tool policy for this mode: you MAY use the built-in Agent tool only as a normal Claude Code subagent helper, i.e. WITHOUT team_name.', + '- If you use Agent in this mode, use it the same way normal Claude Code would use Agent: bounded helper work, parallel research, or implementation support when useful.', + '- Even in DO mode, do NOT use Agent with team_name to create persistent teammates, and do NOT use Agent as a replacement for the team task board or normal teammate delegation.', '- No extra restrictions apply beyond your normal system/team rules.', ], ask: [ 'TURN ACTION MODE: ASK', '- This turn is STRICTLY read-only conversation mode.', '- ALLOWED: read/analyze/explain, answer questions, discuss options, and request clarification if needed.', - '- FORBIDDEN: editing files, changing code, changing task/board state, delegating work, running commands/scripts/tools with side effects, or causing any non-communication state change.', + '- FORBIDDEN: editing files, changing code, changing task/board state, delegating work, launching Agent/subagents, running commands/scripts/tools with side effects, or causing any non-communication state change.', ], delegate: [ 'TURN ACTION MODE: DELEGATE', @@ -27,7 +30,8 @@ const ACTION_MODE_BLOCKS: Record = { '- If you are the team lead, stay at orchestration level: decompose the work, create/assign tasks fast, delegate triage/research to the best teammate, and monitor progress.', '- In this mode, do NOT inspect code, do root-cause research, or spend time narrowing scope yourself before delegating unless the human explicitly asked you for analysis/planning instead of delegation.', '- If the request is underspecified, create a coarse investigation/triage task for the most relevant teammate immediately; that teammate should inspect the codebase, refine scope, and create follow-up tasks if needed.', - '- FORBIDDEN: implementing the work yourself, editing files yourself, running state-changing/code-changing commands yourself, or taking direct execution ownership unless you are truly in SOLO MODE.', + '- FORBIDDEN: implementing the work yourself, editing files yourself, running state-changing/code-changing commands yourself, launching Agent/subagents, or taking direct execution ownership unless you are truly in SOLO MODE.', + '- In particular, do NOT use Agent as a shortcut for delegation in this mode. Use the team board, real teammates, and explicit task ownership instead.', '- If you are not the lead or no delegation target exists, do not execute the work yourself; explain the limitation briefly and request a different mode or a lead handoff.', ], }; diff --git a/test/main/ipc/teams.test.ts b/test/main/ipc/teams.test.ts index 025593a4..e60cb2ed 100644 --- a/test/main/ipc/teams.test.ts +++ b/test/main/ipc/teams.test.ts @@ -282,6 +282,11 @@ describe('ipc teams handlers', () => { expect.stringContaining('TURN ACTION MODE: ASK'), undefined ); + expect(provisioningService.sendMessageToTeam).toHaveBeenCalledWith( + 'my-team', + expect.stringContaining('FORBIDDEN: editing files, changing code, changing task/board state, delegating work, launching Agent/subagents'), + undefined + ); expect(service.sendDirectToLead).toHaveBeenCalledWith( 'my-team', 'team-lead', diff --git a/test/main/services/team/TeamProvisioningServicePrompts.test.ts b/test/main/services/team/TeamProvisioningServicePrompts.test.ts index 1be584ae..911c0a96 100644 --- a/test/main/services/team/TeamProvisioningServicePrompts.test.ts +++ b/test/main/services/team/TeamProvisioningServicePrompts.test.ts @@ -126,6 +126,9 @@ describe('TeamProvisioningService prompt content (solo mode discipline)', () => expect(prompt).toContain('TURN ACTION MODE PROTOCOL (HIGHEST PRIORITY FOR EACH USER TURN):'); expect(prompt).toContain('ASK: Strict read-only conversation mode.'); expect(prompt).toContain('DELEGATE: Strict orchestration mode for leads.'); + expect(prompt).toContain( + 'Built-in Agent usage rule: the built-in Agent tool is allowed only for normal Claude Code-style subagents WITHOUT team_name, and only on turns whose action mode is DO.' + ); expect(prompt).toContain(`AGENT_BLOCK_OPEN is exactly: ${AGENT_BLOCK_OPEN}`); expect(prompt).toContain(`AGENT_BLOCK_CLOSE is exactly: ${AGENT_BLOCK_CLOSE}`); expect(prompt).not.toContain('teamctl.js'); @@ -134,6 +137,10 @@ describe('TeamProvisioningService prompt content (solo mode discipline)', () => const launchArgs = vi.mocked(spawnCli).mock.calls[0]?.[1] as string[]; expect(launchArgs).toContain('--mcp-config'); expect(launchArgs).not.toContain('--strict-mcp-config'); + expect(launchArgs).toContain('--disallowedTools'); + const disallowed = launchArgs[launchArgs.indexOf('--disallowedTools') + 1] ?? ''; + expect(disallowed).not.toContain('Agent'); + expect(disallowed).toContain('mcp__agent-teams__team_launch'); await svc.cancelProvisioning(runId); }); @@ -236,6 +243,9 @@ describe('TeamProvisioningService prompt content (solo mode discipline)', () => expect(prompt).toContain('TURN ACTION MODE PROTOCOL (HIGHEST PRIORITY FOR EACH USER TURN):'); expect(prompt).toContain('DO: Full execution mode.'); expect(prompt).toContain('DELEGATE: Strict orchestration mode for leads.'); + expect(prompt).toContain( + 'Built-in Agent usage rule: the built-in Agent tool is allowed only for normal Claude Code-style subagents WITHOUT team_name, and only on turns whose action mode is DO.' + ); expect(prompt).toContain('Your FIRST action: call MCP tool member_briefing'); expect(prompt).toContain('Do NOT start work, claim tasks, or improvise workflow/task/process rules'); expect(prompt).toContain('If member_briefing fails, send a short message to your team lead');