fix(team): allow agent only in do mode for leads

This commit is contained in:
iliya 2026-04-07 13:25:25 +03:00
parent 53868d6a49
commit 49e46da563
4 changed files with 23 additions and 3 deletions

View file

@ -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}

View file

@ -13,13 +13,16 @@ const ACTION_MODE_BLOCKS: Record<AgentActionMode, string[]> = {
'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<AgentActionMode, string[]> = {
'- 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.',
],
};

View file

@ -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',

View file

@ -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');