diff --git a/packages/types/src/__tests__/orchestrator-permissions-prompt.spec.ts b/packages/types/src/__tests__/orchestrator-permissions-prompt.spec.ts new file mode 100644 index 0000000000..1a6a9bcc3a --- /dev/null +++ b/packages/types/src/__tests__/orchestrator-permissions-prompt.spec.ts @@ -0,0 +1,32 @@ +import { describe, it, expect } from "vitest" +import { DEFAULT_MODES } from "../mode.js" +import type { ModeConfig } from "../mode.js" + +describe("Orchestrator mode - permissions prompt guidance", () => { + const orchestratorMode = DEFAULT_MODES.find((m: ModeConfig) => m.slug === "orchestrator") + + it("should have the orchestrator mode defined", () => { + expect(orchestratorMode).toBeDefined() + }) + + it("should include permissions guidance in customInstructions", () => { + expect(orchestratorMode!.customInstructions).toContain("permissions") + expect(orchestratorMode!.customInstructions).toContain("filePatterns") + expect(orchestratorMode!.customInstructions).toContain("commandPatterns") + expect(orchestratorMode!.customInstructions).toContain("allowedTools") + expect(orchestratorMode!.customInstructions).toContain("deniedTools") + }) + + it("should mention most-restrictive-wins semantics", () => { + expect(orchestratorMode!.customInstructions).toContain("most-restrictive-wins") + }) + + it("should provide example use cases for permissions", () => { + // Guidance about restricting file access + expect(orchestratorMode!.customInstructions).toContain("specific directory") + // Guidance about read-only research tasks + expect(orchestratorMode!.customInstructions).toContain("read-only research") + // Guidance about blocking shell access + expect(orchestratorMode!.customInstructions).toContain("shell access") + }) +}) diff --git a/packages/types/src/mode.ts b/packages/types/src/mode.ts index f981ba7bf9..11f9a9c5da 100644 --- a/packages/types/src/mode.ts +++ b/packages/types/src/mode.ts @@ -222,6 +222,6 @@ export const DEFAULT_MODES: readonly ModeConfig[] = [ description: "Coordinate tasks across multiple modes", groups: [], customInstructions: - "Your role is to coordinate complex workflows by delegating tasks to specialized modes. As an orchestrator, you should:\n\n1. When given a complex task, break it down into logical subtasks that can be delegated to appropriate specialized modes.\n\n2. For each subtask, use the `new_task` tool to delegate. Choose the most appropriate mode for the subtask's specific goal and provide comprehensive instructions in the `message` parameter. These instructions must include:\n * All necessary context from the parent task or previous subtasks required to complete the work.\n * A clearly defined scope, specifying exactly what the subtask should accomplish.\n * An explicit statement that the subtask should *only* perform the work outlined in these instructions and not deviate.\n * An instruction for the subtask to signal completion by using the `attempt_completion` tool, providing a concise yet thorough summary of the outcome in the `result` parameter, keeping in mind that this summary will be the source of truth used to keep track of what was completed on this project.\n * A statement that these specific instructions supersede any conflicting general instructions the subtask's mode might have.\n\n3. Track and manage the progress of all subtasks. When a subtask is completed, analyze its results and determine the next steps.\n\n4. Help the user understand how the different subtasks fit together in the overall workflow. Provide clear reasoning about why you're delegating specific tasks to specific modes.\n\n5. When all subtasks are completed, synthesize the results and provide a comprehensive overview of what was accomplished.\n\n6. Ask clarifying questions when necessary to better understand how to break down complex tasks effectively.\n\n7. Suggest improvements to the workflow based on the results of completed subtasks.\n\nUse subtasks to maintain clarity. If a request significantly shifts focus or requires a different expertise (mode), consider creating a subtask rather than overloading the current one.", + 'Your role is to coordinate complex workflows by delegating tasks to specialized modes. As an orchestrator, you should:\n\n1. When given a complex task, break it down into logical subtasks that can be delegated to appropriate specialized modes.\n\n2. For each subtask, use the `new_task` tool to delegate. Choose the most appropriate mode for the subtask\'s specific goal and provide comprehensive instructions in the `message` parameter. These instructions must include:\n * All necessary context from the parent task or previous subtasks required to complete the work.\n * A clearly defined scope, specifying exactly what the subtask should accomplish.\n * An explicit statement that the subtask should *only* perform the work outlined in these instructions and not deviate.\n * An instruction for the subtask to signal completion by using the `attempt_completion` tool, providing a concise yet thorough summary of the outcome in the `result` parameter, keeping in mind that this summary will be the source of truth used to keep track of what was completed on this project.\n * A statement that these specific instructions supersede any conflicting general instructions the subtask\'s mode might have.\n\n3. Track and manage the progress of all subtasks. When a subtask is completed, analyze its results and determine the next steps.\n\n4. Help the user understand how the different subtasks fit together in the overall workflow. Provide clear reasoning about why you\'re delegating specific tasks to specific modes.\n\n5. When all subtasks are completed, synthesize the results and provide a comprehensive overview of what was accomplished.\n\n6. Ask clarifying questions when necessary to better understand how to break down complex tasks effectively.\n\n7. Suggest improvements to the workflow based on the results of completed subtasks.\n\n8. When delegating subtasks, consider using the optional `permissions` parameter on `new_task` to restrict what the subtask can do. This is especially useful when:\n * The subtask should only modify files in a specific directory (use `filePatterns`, e.g. `["src/components/.*"]`).\n * The subtask should only run certain commands (use `commandPatterns`, e.g. `["npm test.*", "npm run lint"]`).\n * The subtask should be limited to specific tools (use `allowedTools`, e.g. `["read_file", "search_files"]` for read-only research tasks).\n * Certain tools should be explicitly blocked (use `deniedTools`, e.g. `["execute_command"]` to prevent shell access).\n Permissions are enforced at runtime and follow most-restrictive-wins semantics when subtasks are nested. Use them to keep subtasks focused and safe.\n\nUse subtasks to maintain clarity. If a request significantly shifts focus or requires a different expertise (mode), consider creating a subtask rather than overloading the current one.', }, ] as const diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index d8d2bab0f8..52f07493c1 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -795,6 +795,13 @@ export interface ClineSayTool { description?: string // Properties for skill tool skill?: string + // Properties for newTask tool - permission boundaries set by parent + permissions?: { + filePatterns?: string[] + commandPatterns?: string[] + allowedTools?: string[] + deniedTools?: string[] + } } export interface ClineAskUseMcpServer { diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index ec02fda04c..3c71d1e96c 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -869,6 +869,39 @@ export const ChatRowContent = ({
+ {tool.permissions && ( +
+
{t("chat:subtasks.permissionBoundaries")}
+ {tool.permissions.filePatterns && ( +
+ {t("chat:subtasks.permissionFilePatterns", { + patterns: tool.permissions.filePatterns.join(", "), + })} +
+ )} + {tool.permissions.commandPatterns && ( +
+ {t("chat:subtasks.permissionCommandPatterns", { + patterns: tool.permissions.commandPatterns.join(", "), + })} +
+ )} + {tool.permissions.allowedTools && ( +
+ {t("chat:subtasks.permissionAllowedTools", { + tools: tool.permissions.allowedTools.join(", "), + })} +
+ )} + {tool.permissions.deniedTools && ( +
+ {t("chat:subtasks.permissionDeniedTools", { + tools: tool.permissions.deniedTools.join(", "), + })} +
+ )} +
+ )}
{childTaskId && !isFollowedBySubtaskResult && (