flake-update-20260505
1/**
2 * Orchestrator Mode Extension
3 *
4 * A simple mode that transforms the main agent into an orchestrator.
5 * When enabled, only the subagent tool is available and the system prompt
6 * is updated to focus on coordination and delegation.
7 *
8 * Features:
9 * - /orc command to toggle orchestrator mode
10 * - In orc mode: only subagent tool available
11 * - System prompt modified to focus on orchestration
12 * - Orange status indicator when active
13 *
14 * Usage:
15 * 1. Use /orc to toggle orchestrator mode on/off
16 * 2. Or start with --orc flag
17 */
18
19import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
20
21// Tools available in orchestrator mode - subagent for delegation, subagent_status for async monitoring
22const ORC_MODE_TOOLS = ["subagent", "subagent_status"];
23
24// Store the original tools to restore them when disabling orc mode
25let savedTools: string[] | null = null;
26
27export default function orcModeExtension(pi: ExtensionAPI) {
28 let orcModeEnabled = false;
29
30 // Register --orc CLI flag
31 pi.registerFlag("orc", {
32 description: "Start in orchestrator mode (coordinator-only)",
33 type: "boolean",
34 default: false,
35 });
36
37 // Helper to update status displays
38 function updateStatus(ctx: ExtensionContext) {
39 if (orcModeEnabled) {
40 ctx.ui.setStatus("orc-mode", ctx.ui.theme.fg("warning", "🎠ORC"));
41 ctx.ui.setWidget("orc-mode", [
42 ctx.ui.theme.fg("warning", "🎠Orchestrator mode active"),
43 ctx.ui.theme.fg("muted", "Only subagent tool available"),
44 ctx.ui.theme.fg("dim", "Use /orc to disable"),
45 ]);
46 } else {
47 ctx.ui.setStatus("orc-mode", undefined);
48 ctx.ui.setWidget("orc-mode", undefined);
49 }
50 }
51
52 function enableOrcMode(ctx: ExtensionContext) {
53 if (orcModeEnabled) return;
54
55 // Save current tools before switching
56 savedTools = pi.getActiveTools();
57 orcModeEnabled = true;
58 pi.setActiveTools(ORC_MODE_TOOLS);
59 ctx.ui.notify("🎠Orchestrator mode enabled. Only subagent tool available.");
60 updateStatus(ctx);
61 persistState();
62 }
63
64 function disableOrcMode(ctx: ExtensionContext) {
65 if (!orcModeEnabled) return;
66
67 orcModeEnabled = false;
68 // Restore original tools or use defaults
69 if (savedTools && savedTools.length > 0) {
70 pi.setActiveTools(savedTools);
71 } else {
72 // Fallback to standard tools
73 pi.setActiveTools(["read", "bash", "edit", "write", "subagent"]);
74 }
75 savedTools = null;
76 ctx.ui.notify("Orchestrator mode disabled. Full tool access restored.");
77 updateStatus(ctx);
78 persistState();
79 }
80
81 function toggleOrcMode(ctx: ExtensionContext) {
82 if (orcModeEnabled) {
83 disableOrcMode(ctx);
84 } else {
85 enableOrcMode(ctx);
86 }
87 }
88
89 function persistState() {
90 pi.appendEntry("orc-mode-state", {
91 enabled: orcModeEnabled,
92 savedTools,
93 });
94 }
95
96 // Register /orc command
97 pi.registerCommand("orc", {
98 description: "Toggle orchestrator mode (only subagent tool available)",
99 handler: async (_args, ctx) => {
100 toggleOrcMode(ctx);
101 },
102 });
103
104 // Modify system prompt when orc mode is active
105 pi.on("before_agent_start", async (event) => {
106 if (!orcModeEnabled) return;
107
108 const orcSystemPrompt = `${event.systemPrompt}
109
110## ORCHESTRATOR MODE
111
112You are operating as an **orchestrator**. Your primary role is to coordinate, plan, and delegate work—not to implement directly.
113
114### Your Tools
115You only have access to the **subagent** tool. Use it to delegate all work:
116- **scout**: Fast codebase recon, find files, return compressed context for handoff
117- **planner**: Create implementation plans from context and requirements
118- **worker**: General-purpose subagent with full capabilities for implementation
119- **reviewer**: Code review specialist for quality and security analysis
120- **oracle**: Deep analysis, debugging, and architecture decisions
121
122### Subagent Modes
123
124**Single agent:**
125\`\`\`typescript
126{ agent: "explorer", task: "Find all auth-related files" }
127\`\`\`
128
129**Parallel tasks** (independent work):
130\`\`\`typescript
131{ tasks: [
132 { agent: "explorer", task: "Find frontend modules" },
133 { agent: "explorer", task: "Find backend modules" }
134]}
135\`\`\`
136
137**Chain** (sequential pipeline with \`{previous}\` carrying output forward):
138\`\`\`typescript
139{ chain: [
140 { agent: "explorer", task: "Gather context for auth refactor" },
141 { agent: "oracle", task: "Analyze and plan based on {previous}" },
142 { agent: "operator" }, // defaults to {previous}
143 { agent: "oracle", task: "Review changes from {previous}" }
144]}
145\`\`\`
146
147**Chain with parallel fan-out/fan-in:**
148\`\`\`typescript
149{ chain: [
150 { agent: "explorer", task: "Find all service modules" },
151 { parallel: [
152 { agent: "operator", task: "Refactor auth service from {previous}" },
153 { agent: "operator", task: "Refactor user service from {previous}" }
154 ]},
155 { agent: "oracle", task: "Review all changes from {previous}" }
156]}
157\`\`\`
158
159### Chain Variables
160- \`{task}\` - Original task from first step
161- \`{previous}\` - Output from prior step (or aggregated parallel outputs)
162- \`{chain_dir}\` - Shared artifacts directory for inter-step files
163
164### Workflow
1651. **Analyze** the user's request
1662. **Plan** the approach (break into steps if complex)
1673. **Delegate** each task to the appropriate subagent
1684. **Synthesize** results and report back
169
170### Guidelines
171- Always use subagent to delegate work
172- For complex multi-step tasks, use chain mode
173- For independent tasks, use parallel mode
174- Use parallel-in-chain for fan-out/fan-in patterns
175- Provide clear, specific task descriptions to subagents
176- After subagents complete, summarize findings or confirm changes`;
177
178 return { systemPrompt: orcSystemPrompt };
179 });
180
181 // Initialize state on session start
182 pi.on("session_start", async (_event, ctx) => {
183 // Check CLI flag
184 if (pi.getFlag("orc") === true) {
185 // Defer enabling to let other extensions initialize first
186 setTimeout(() => {
187 if (!orcModeEnabled) {
188 enableOrcMode(ctx);
189 }
190 }, 0);
191 return;
192 }
193
194 // Restore state from session
195 const entries = ctx.sessionManager.getEntries();
196 const stateEntry = entries
197 .filter((e: { type: string; customType?: string }) => e.type === "custom" && e.customType === "orc-mode-state")
198 .pop() as { data?: { enabled: boolean; savedTools?: string[] | null } } | undefined;
199
200 if (stateEntry?.data) {
201 if (stateEntry.data.enabled) {
202 savedTools = stateEntry.data.savedTools ?? null;
203 orcModeEnabled = true;
204 pi.setActiveTools(ORC_MODE_TOOLS);
205 }
206 }
207
208 updateStatus(ctx);
209 });
210}