File
Blob: src/workflows.ts
| 1 | import type { AgentId } from "./store.js"; |
| 2 | |
| 3 | // ── Types ────────────────────────────────────────────────────────── |
| 4 | |
| 5 | export type WorkflowId = |
| 6 | | "custom" |
| 7 | | "research" |
| 8 | | "implementation" |
| 9 | | "implementation_codex_architect"; |
| 10 | |
| 11 | export interface WorkflowPhase { |
| 12 | id: string; |
| 13 | name: string; |
| 14 | instructions: Partial<Record<AgentId, string>>; |
| 15 | reminderForReceiver: Partial<Record<AgentId, string>>; |
| 16 | } |
| 17 | |
| 18 | export interface SubagentHint { |
| 19 | modelDirective?: string; |
| 20 | waitDirective?: string; |
| 21 | extraRelayRules?: string[]; |
| 22 | } |
| 23 | |
| 24 | export interface WorkflowRoleSpec { |
| 25 | contract: string[]; |
| 26 | stopConditions: string[]; |
| 27 | startInstruction?: string; |
| 28 | flowDesc?: string; |
| 29 | subagentHint?: SubagentHint; |
| 30 | } |
| 31 | |
| 32 | export interface WorkflowTemplate { |
| 33 | id: WorkflowId; |
| 34 | name: string; |
| 35 | description: string; |
| 36 | goalPlaceholder?: string; |
| 37 | /** If set, the session's initiator is pinned to this agent and the UI should hide its selector. */ |
| 38 | forcedInitiator?: AgentId; |
| 39 | phases: WorkflowPhase[]; |
| 40 | byRole: Record<AgentId, WorkflowRoleSpec>; |
| 41 | } |
| 42 | |
| 43 | export interface BuildContext { |
| 44 | collabId: string; |
| 45 | endpoint: string; |
| 46 | agent: AgentId; |
| 47 | otherAgent: AgentId; |
| 48 | role: "INITIATOR" | "RESPONDER"; |
| 49 | goal: string; |
| 50 | phases: WorkflowPhase[]; |
| 51 | currentPhaseIndex: number; |
| 52 | } |
| 53 | |
| 54 | export interface WorkflowSummary { |
| 55 | id: WorkflowId; |
| 56 | name: string; |
| 57 | description: string; |
| 58 | goalPlaceholder?: string; |
| 59 | forcedInitiator?: AgentId; |
| 60 | phases: Array<{ id: string; name: string }>; |
| 61 | } |
| 62 | |
| 63 | // ── Templates ────────────────────────────────────────────────────── |
| 64 | |
| 65 | const custom: WorkflowTemplate = { |
| 66 | id: "custom", |
| 67 | name: "Custom (no contract)", |
| 68 | description: |
| 69 | "Freeform collaboration. The goal field is passed straight through with the generic role prompts. Use this when you want to paste your own contract into the goal.", |
| 70 | goalPlaceholder: "Describe the shared goal for the two agents...", |
| 71 | phases: [], |
| 72 | byRole: { |
| 73 | claude: { contract: [], stopConditions: [] }, |
| 74 | codex: { contract: [], stopConditions: [] }, |
| 75 | }, |
| 76 | }; |
| 77 | |
| 78 | const relaySubagentHint: SubagentHint = { |
| 79 | modelDirective: |
| 80 | "When spawning the wait-relay subagent, set its model to `gpt-5.4 low` (pass it as the `model` argument on the `spawn_agent` call). The relay is a low-cost message wrapper.", |
| 81 | waitDirective: |
| 82 | "When you call `wait_agent` to await the relay subagent's result, use a long polling window. The relay internally long-polls `collab_wait_for_reply` for up to 5 minutes (300s), so set the `wait_agent` timeout to at least 360s -- or use the maximum 3600s to avoid any fast-poll / re-wake churn. Do NOT use short timeouts that force repeated wake-ups while the relay is still waiting.", |
| 83 | }; |
| 84 | |
| 85 | const stateMatrixRule = |
| 86 | "Before approving implementation, require an explicit correctness model whenever correctness depends on multiple modes, time ordering, async recovery, permissions, cache/state ownership, range/coordinate mapping, ownership boundaries, or cross-boundary coordination. The plan must state the invariant in one precise sentence, provide the state/transition matrix, derive any ordering or mapping-bias choices from that invariant, and name the focused tests that prove the important cells. Do not approve a lifecycle-only matrix that names phases without proving the edge cases."; |
| 87 | |
| 88 | const systematicAuditRule = |
| 89 | "If one review round finds multiple material issues in the same subsystem or behavior, or if two consecutive review rounds find material issues in the same subsystem or behavior, stop patch-by-patch churn. Before the next implementation pass, collaborate on the invariant/state matrix and require one systematic end-to-end audit of that subsystem."; |
| 90 | |
| 91 | const research: WorkflowTemplate = { |
| 92 | id: "research", |
| 93 | name: "Research (Claude synthesizes, Codex assists)", |
| 94 | description: |
| 95 | "Read-only research collaboration. Claude opens and owns the final synthesis; Codex investigates complementary areas and challenges assumptions.", |
| 96 | goalPlaceholder: |
| 97 | "Describe the research question, sources or repo areas to inspect, and the expected final deliverable...", |
| 98 | forcedInitiator: "claude", |
| 99 | phases: [], |
| 100 | byRole: { |
| 101 | claude: { |
| 102 | contract: [ |
| 103 | "You own the final synthesis and presentation to the user.", |
| 104 | "Begin with a substantive research brief: current findings, open questions, and the complementary areas you want Codex to investigate.", |
| 105 | "This workflow is read-only. Do not edit code or project files unless the user's goal explicitly asks for a written artifact; if an artifact is requested, you own producing it after the collaboration has converged.", |
| 106 | "Ask Codex to verify claims, surface risks, and challenge weak assumptions rather than duplicate your exact work.", |
| 107 | "When you have enough input, send a closing message that says no further Codex action is needed, then call `collab_close_session`.", |
| 108 | ], |
| 109 | stopConditions: [ |
| 110 | "You have enough information to produce the final user-facing synthesis.", |
| 111 | "User explicitly tells you to stop.", |
| 112 | ], |
| 113 | startInstruction: |
| 114 | "Begin by researching enough context to avoid a blind handoff, then send Codex one substantive opening research brief with specific complementary questions. Do not edit files.", |
| 115 | }, |
| 116 | codex: { |
| 117 | contract: [ |
| 118 | "You assist Claude's research and do not own the final user-facing synthesis.", |
| 119 | "This workflow is read-only. Do not edit code or project files.", |
| 120 | "Investigate complementary areas, verify claims against source material, surface risks, and push back on weak assumptions.", |
| 121 | "Do not duplicate Claude's exact research scope unless Claude explicitly asks for independent verification.", |
| 122 | "After every message, spawn the next wait-relay subagent unless Claude explicitly closes the research loop or the session is closed.", |
| 123 | ], |
| 124 | stopConditions: [ |
| 125 | "Claude explicitly says no further Codex action is needed.", |
| 126 | "The session is closed.", |
| 127 | "User explicitly dismisses you.", |
| 128 | ], |
| 129 | subagentHint: relaySubagentHint, |
| 130 | flowDesc: |
| 131 | "Message order: wait -> send -> wait -> send -> ... (you receive first). After EVERY `collab_send_message`, spawn a new wait-relay subagent unless Claude explicitly closes the research loop or the session is closed.", |
| 132 | startInstruction: |
| 133 | "Your FIRST action: spawn a wait-relay subagent to listen for Claude's opening research brief. While it waits, do not edit files; prepare to investigate complementary areas once Claude's message arrives.", |
| 134 | }, |
| 135 | }, |
| 136 | }; |
| 137 | |
| 138 | const implementation: WorkflowTemplate = { |
| 139 | id: "implementation", |
| 140 | name: "Implementation (plan -> confirm -> code -> review loop)", |
| 141 | description: |
| 142 | "Claude plans with Codex, pauses for user confirmation, implements, then loops with Codex on review until no material findings remain. Claude always initiates.", |
| 143 | goalPlaceholder: |
| 144 | "Describe the implementation task (what to build, constraints, where the code lives)...", |
| 145 | forcedInitiator: "claude", |
| 146 | phases: [ |
| 147 | { |
| 148 | id: "plan", |
| 149 | name: "Collaborative Plan", |
| 150 | instructions: { |
| 151 | claude: |
| 152 | "Discuss approach with Codex. Propose scope and trade-offs. DO NOT begin implementing yet. When planning converges, pause and wait for explicit user confirmation before advancing to the implement phase.", |
| 153 | codex: |
| 154 | "Plan immediately without waiting. Push back on scope; surface risks. DO NOT implement. After sending each message, spawn a wait subagent and stay in the loop -- do not end your turn.", |
| 155 | }, |
| 156 | reminderForReceiver: { |
| 157 | claude: |
| 158 | "PHASE: plan. Stay collaborative. No code yet. If the plan has meaningful state, async, permission, ownership, or coordinate/range complexity, require an invariant plus state/transition matrix before implementation approval. Pause for user confirmation before transitioning to implement.", |
| 159 | codex: |
| 160 | "PHASE: plan. Advisory only. Do not edit files. If the plan has meaningful state, async, permission, ownership, or coordinate/range complexity, require an invariant plus state/transition matrix before implementation approval. After you reply, immediately spawn the next wait-relay subagent. Do not end your turn without a wait subagent running.", |
| 161 | }, |
| 162 | }, |
| 163 | { |
| 164 | id: "implement", |
| 165 | name: "Claude Implements", |
| 166 | instructions: { |
| 167 | claude: |
| 168 | "Implement the agreed plan. Run the project formatter, run relevant validation for touched code, stage changes with `git add` (do NOT commit). Then ask Codex to review the staged diff.", |
| 169 | codex: |
| 170 | "You are NOT implementing. Spawn a wait subagent and keep listening for Claude's review request. STANDBY = actively waiting via a wait subagent, not idle.", |
| 171 | }, |
| 172 | reminderForReceiver: { |
| 173 | claude: |
| 174 | "PHASE: implement. You own the edits. Run formatter + validation. Stage with git add, do not commit. Then ask Codex to review.", |
| 175 | codex: |
| 176 | "PHASE: implement. Do not touch files. You should currently be running a wait-relay subagent. If this message arrived, that wait subagent just completed -- after you respond (or if no response is warranted), spawn a new wait subagent immediately. Do not end your turn.", |
| 177 | }, |
| 178 | }, |
| 179 | { |
| 180 | id: "review", |
| 181 | name: "Review Loop", |
| 182 | instructions: { |
| 183 | claude: |
| 184 | "Receive Codex's review. Address material findings (bugs, regressions, contract violations). Re-run formatter + validation, re-stage, and ask for re-review. Loop until Codex reports no material findings.", |
| 185 | codex: |
| 186 | "Code-review mode. Inspect the staged diff. Prioritize bugs and behavioral regressions over style. Use file:line specificity. Reply with findings ordered by severity, or 'no material findings' if clean. IMMEDIATELY after sending your review, spawn a new wait-relay subagent to listen for Claude's next iteration -- reporting findings is NOT a session terminator.", |
| 187 | }, |
| 188 | reminderForReceiver: { |
| 189 | claude: |
| 190 | "PHASE: review. Address material findings only. Defer style nits. If review finds multiple or repeated material issues in the same subsystem, pause patching and collaborate on the invariant/state matrix plus a systematic audit before more edits. Re-stage and re-request review until clean.", |
| 191 | codex: |
| 192 | "PHASE: review. Read the staged diff. Focus on correctness, regressions, missing tests. file:line specific. If one round has multiple same-subsystem material findings, or repeated rounds hit the same subsystem, require an invariant/state-matrix audit before the next patch. No material findings => say so explicitly. After you reply with your review, spawn the next wait-relay subagent IMMEDIATELY to await Claude's re-staged diff. Do NOT say 'I'm in standby' and stop -- say it and spawn the subagent in the same turn.", |
| 193 | }, |
| 194 | }, |
| 195 | ], |
| 196 | byRole: { |
| 197 | claude: { |
| 198 | contract: [ |
| 199 | "You PLAN collaboratively with Codex before implementing anything.", |
| 200 | stateMatrixRule, |
| 201 | "You PAUSE and wait for explicit user confirmation before transitioning from plan to implement.", |
| 202 | "You implement the agreed plan, run the project formatter, run relevant validation for touched code, and stage changes with `git add` (no commits).", |
| 203 | "You ask Codex to review the staged diff and address material findings until Codex reports none.", |
| 204 | systematicAuditRule, |
| 205 | "Bugs and behavioral regressions block; style nits are deferrable.", |
| 206 | "Do NOT ask the user again during the implementation/review loop unless blocked or the agreed plan materially changes.", |
| 207 | ], |
| 208 | stopConditions: [ |
| 209 | "Codex reports 'no material findings' on the latest staged diff.", |
| 210 | "User explicitly tells you to stop or commit.", |
| 211 | ], |
| 212 | startInstruction: |
| 213 | "Begin by collaborating with Codex on a plan. Send a substantive opening message proposing scope, trade-offs, and open questions. Do NOT begin implementing during planning.", |
| 214 | }, |
| 215 | codex: { |
| 216 | contract: [ |
| 217 | "CRITICAL LOOP RULE: After sending ANY message via `collab_send_message`, your IMMEDIATE next action is to spawn a new wait-relay subagent to listen for Claude's next message. NEVER end a turn without an active wait subagent running. NEVER stop to wait for user input -- the user is not driving this loop, Claude is.", |
| 218 | "STANDBY in this workflow means 'actively listening for Claude via a spawned wait-relay subagent' -- it does NOT mean idle, does NOT mean ending your turn, does NOT mean waiting for further user prompting. If you find yourself about to say 'I'm in standby' or 'waiting for the next diff', that sentence MUST be followed by spawning a wait subagent in the same turn.", |
| 219 | "You do NOT implement. Claude owns all file edits.", |
| 220 | "During the plan phase, push back on scope and surface risks. Start collaborating immediately without waiting for user confirmation.", |
| 221 | stateMatrixRule, |
| 222 | "Do not edit files during planning and do not make unsolicited code changes during review unless Claude explicitly asks for a narrow, scoped helper task.", |
| 223 | "When Claude asks for review after implementation begins, switch to code-review mode and inspect ONLY the staged diff or exact change set Claude identifies.", |
| 224 | "Prioritize bugs, behavioral regressions, missing tests, and risky assumptions. Use file:line specificity. Defer style nits unless they materially affect correctness.", |
| 225 | systematicAuditRule, |
| 226 | "Report findings first, ordered by severity. If you have no material findings, say so explicitly and mention any residual risks or test gaps. THEN immediately spawn the next wait subagent -- reporting findings is NOT a session terminator.", |
| 227 | "Keep reviewing on each re-request until you have no material findings.", |
| 228 | "The session is complete ONLY when Claude explicitly says implementation and review are finished, or the user explicitly dismisses you. Until then, every sent message is followed by a spawned wait subagent.", |
| 229 | ], |
| 230 | stopConditions: [ |
| 231 | "You report 'no material findings' on Claude's latest staged diff AND Claude confirms the session is done.", |
| 232 | "Claude explicitly tells you the session is complete.", |
| 233 | "User explicitly dismisses you.", |
| 234 | ], |
| 235 | subagentHint: relaySubagentHint, |
| 236 | flowDesc: |
| 237 | "Message order: wait -> send -> wait -> send -> ... (you receive first). This loop is CONTINUOUS and has no natural terminator until Claude or the user explicitly ends it. After EVERY `collab_send_message`, your immediate next action is ALWAYS to spawn a new wait-relay subagent. Never end a turn without an active wait subagent. Do not treat 'I sent my reply' as a stopping point -- the loop continues.", |
| 238 | startInstruction: |
| 239 | "Your FIRST action: spawn a wait-relay subagent to listen for Claude's opening message. Then, in parallel in your main context, propose your own independent implementation plan and push back on scope. Do NOT implement. Every time your wait subagent returns with a message, you reply AND immediately spawn the next wait subagent -- no exceptions, no 'standby without a subagent'.", |
| 240 | }, |
| 241 | }, |
| 242 | }; |
| 243 | |
| 244 | const implementationCodexArchitect: WorkflowTemplate = { |
| 245 | id: "implementation_codex_architect", |
| 246 | name: "Implementation (Codex architecture -> Claude plan -> human gate -> code -> review)", |
| 247 | description: |
| 248 | "Codex proposes the architecture, Claude independently explores the repo before responding and then authors the implementation plan, Codex approves it, the user gates the start of coding, then Claude implements and Codex reviews until clean.", |
| 249 | goalPlaceholder: |
| 250 | "Describe the implementation task (what to build, constraints, where the code lives)...", |
| 251 | forcedInitiator: "codex", |
| 252 | phases: [ |
| 253 | { |
| 254 | id: "architecture", |
| 255 | name: "Architecture", |
| 256 | instructions: { |
| 257 | codex: |
| 258 | "Explore the repo and propose the architecture first. Own the design discussion, surface trade-offs, and refine the architecture with Claude. DO NOT implement or author the step-by-step implementation plan yet.", |
| 259 | claude: |
| 260 | "Before your first substantive reply, independently explore the codebase so you are not responding blind. Then critique Codex's architecture with repo-aware constraints, edge cases, and integration concerns. DO NOT implement.", |
| 261 | }, |
| 262 | reminderForReceiver: { |
| 263 | codex: |
| 264 | "PHASE: architecture. You own the design proposal and iteration. No code edits, no implementation plan yet.", |
| 265 | claude: |
| 266 | "PHASE: architecture. Independently inspect the codebase before replying if you have not already. Provide repo-aware feedback only. No code edits.", |
| 267 | }, |
| 268 | }, |
| 269 | { |
| 270 | id: "implementation_plan", |
| 271 | name: "Implementation Plan", |
| 272 | instructions: { |
| 273 | codex: |
| 274 | "Review Claude's concrete implementation plan against the agreed architecture. Approve it explicitly if it is ready, or send blocking corrections if it is not. DO NOT let coding start without your approval and the later user confirmation.", |
| 275 | claude: |
| 276 | "Write the concrete implementation plan for this repo: touched areas, sequencing, validation, and test intent. Get explicit Codex approval. After Codex approves, PAUSE and wait for explicit user confirmation before transitioning to implement.", |
| 277 | }, |
| 278 | reminderForReceiver: { |
| 279 | codex: |
| 280 | "PHASE: implementation_plan. Approve or block Claude's repo-specific implementation plan. If correctness depends on state, async, permission, ownership, or coordinate/range behavior, block approval until the plan includes an invariant, state/transition matrix, any mapping/order derivation, and focused validation. No code edits. Coding must not start until you approve and the user advances the phase.", |
| 281 | claude: |
| 282 | "PHASE: implementation_plan. Author the concrete repo-specific implementation plan. If correctness depends on state, async, permission, ownership, or coordinate/range behavior, include an invariant, state/transition matrix, any mapping/order derivation, and focused validation. No code edits. After Codex approves, pause for explicit user confirmation before moving to implement.", |
| 283 | }, |
| 284 | }, |
| 285 | { |
| 286 | id: "implement", |
| 287 | name: "Claude Implements", |
| 288 | instructions: { |
| 289 | codex: |
| 290 | "You are NOT implementing. Stay available for clarification while Claude edits. STANDBY = actively waiting via a wait subagent, not idle.", |
| 291 | claude: |
| 292 | "Implement the approved plan only after the user explicitly confirms the transition into this phase. Run the project formatter, run relevant validation for touched code, stage changes with `git add` (do NOT commit). Then ask Codex to review the staged diff.", |
| 293 | }, |
| 294 | reminderForReceiver: { |
| 295 | codex: |
| 296 | "PHASE: implement. Do not touch files unless Claude explicitly asks for a narrow scoped helper task. Keep the wait-relay loop active.", |
| 297 | claude: |
| 298 | "PHASE: implement. The user gate has been cleared. You own the edits. Run formatter + validation. Stage with git add, do not commit. Then ask Codex to review.", |
| 299 | }, |
| 300 | }, |
| 301 | { |
| 302 | id: "review", |
| 303 | name: "Review Loop", |
| 304 | instructions: { |
| 305 | codex: |
| 306 | "Code-review mode. Inspect the staged diff. Prioritize bugs and behavioral regressions over style. Use file:line specificity. Reply with findings ordered by severity, or 'no material findings' if clean. IMMEDIATELY after sending your review, spawn a new wait-relay subagent to listen for Claude's next iteration -- reporting findings is NOT a session terminator.", |
| 307 | claude: |
| 308 | "Receive Codex's review. Address material findings (bugs, regressions, contract violations). Re-run formatter + validation, re-stage, and ask for re-review. Loop until Codex reports no material findings.", |
| 309 | }, |
| 310 | reminderForReceiver: { |
| 311 | codex: |
| 312 | "PHASE: review. Read the staged diff. Focus on correctness, regressions, missing tests. file:line specific. If one round has multiple same-subsystem material findings, or repeated rounds hit the same subsystem, require an invariant/state-matrix audit before the next patch. No material findings => say so explicitly. After you reply, spawn the next wait-relay subagent immediately.", |
| 313 | claude: |
| 314 | "PHASE: review. Address material findings only. Defer style nits. If review finds multiple or repeated material issues in the same subsystem, pause patching and collaborate on the invariant/state matrix plus a systematic audit before more edits. Re-stage and re-request review until clean.", |
| 315 | }, |
| 316 | }, |
| 317 | ], |
| 318 | byRole: { |
| 319 | claude: { |
| 320 | contract: [ |
| 321 | "Before your first substantive reply, independently explore the codebase enough to ground your feedback in the actual repo.", |
| 322 | "During the architecture phase, critique and refine Codex's design with concrete repo-aware constraints, edge cases, and execution risks.", |
| 323 | "During the implementation_plan phase, you author the concrete implementation plan for this repo and get explicit Codex approval before code starts.", |
| 324 | stateMatrixRule, |
| 325 | "After Codex approves the implementation plan, you PAUSE and wait for explicit user confirmation before transitioning to implementation.", |
| 326 | "You implement the approved plan, run the project formatter, run relevant validation for touched code, and stage changes with `git add` (no commits).", |
| 327 | "You ask Codex to review the staged diff and address material findings until Codex reports none.", |
| 328 | systematicAuditRule, |
| 329 | "Bugs and behavioral regressions block; style nits are deferrable.", |
| 330 | "Do NOT ask the user again during the implementation/review loop unless blocked or the agreed plan materially changes.", |
| 331 | ], |
| 332 | stopConditions: [ |
| 333 | "Codex reports 'no material findings' on the latest staged diff.", |
| 334 | "User explicitly tells you to stop or commit.", |
| 335 | ], |
| 336 | startInstruction: |
| 337 | "Begin NOW by spawning a subagent to call `collab_wait_for_reply` with lastSeenMessageId=0 so you can receive Codex's opening architecture proposal. While that subagent waits, independently explore the codebase and prepare repo-aware feedback. Do NOT send a blind first response based only on the incoming proposal.", |
| 338 | }, |
| 339 | codex: { |
| 340 | contract: [ |
| 341 | "CRITICAL LOOP RULE: After sending ANY message via `collab_send_message`, your IMMEDIATE next action is to spawn a new wait-relay subagent to listen for Claude's next message. NEVER end a turn without an active wait subagent running.", |
| 342 | "STANDBY in this workflow means 'actively listening for Claude via a spawned wait-relay subagent' -- it does NOT mean idle, does NOT mean ending your turn, and does NOT mean waiting for further user prompting without a subagent.", |
| 343 | "You own the architecture during the architecture phase. Start by exploring the repo and then sending one substantive architecture proposal.", |
| 344 | "You do NOT implement. Claude owns all file edits.", |
| 345 | "During the implementation_plan phase, require a concrete repo-specific plan from Claude. Approve it explicitly if ready, or return blocking corrections if it is not.", |
| 346 | stateMatrixRule, |
| 347 | "Coding must not start until you approve Claude's implementation plan AND the user explicitly advances to the implement phase.", |
| 348 | "Do not edit files during architecture or implementation planning and do not make unsolicited code changes during review unless Claude explicitly asks for a narrow, scoped helper task.", |
| 349 | "When Claude asks for review after implementation begins, switch to code-review mode and inspect ONLY the staged diff or exact change set Claude identifies.", |
| 350 | "Prioritize bugs, behavioral regressions, missing tests, and risky assumptions. Use file:line specificity. Defer style nits unless they materially affect correctness.", |
| 351 | systematicAuditRule, |
| 352 | "Report findings first, ordered by severity. If you have no material findings, say so explicitly and mention any residual risks or test gaps. THEN immediately spawn the next wait subagent -- reporting findings is NOT a session terminator.", |
| 353 | "Keep reviewing on each re-request until you have no material findings.", |
| 354 | "The session is complete ONLY when Claude explicitly says implementation and review are finished, or the user explicitly dismisses you. Until then, every sent message is followed by a spawned wait subagent.", |
| 355 | ], |
| 356 | stopConditions: [ |
| 357 | "You report 'no material findings' on Claude's latest staged diff AND Claude confirms the session is done.", |
| 358 | "Claude explicitly tells you the session is complete.", |
| 359 | "User explicitly dismisses you.", |
| 360 | ], |
| 361 | subagentHint: relaySubagentHint, |
| 362 | startInstruction: |
| 363 | "Begin by exploring the codebase and researching the goal. Once you have enough context, call `collab_send_message` with one substantive architecture proposal that covers trade-offs, risks, and open questions. Do NOT send the step-by-step implementation plan yet. Then spawn a wait-relay subagent for Claude's reply.", |
| 364 | }, |
| 365 | }, |
| 366 | }; |
| 367 | |
| 368 | // ── Registry ─────────────────────────────────────────────────────── |
| 369 | |
| 370 | export const WORKFLOWS: Readonly<Record<WorkflowId, WorkflowTemplate>> = Object.freeze({ |
| 371 | custom, |
| 372 | research, |
| 373 | implementation, |
| 374 | implementation_codex_architect: implementationCodexArchitect, |
| 375 | }); |
| 376 | |
| 377 | const VALID_IDS: readonly WorkflowId[] = [ |
| 378 | "custom", |
| 379 | "research", |
| 380 | "implementation", |
| 381 | "implementation_codex_architect", |
| 382 | ]; |
| 383 | |
| 384 | export function isValidWorkflowId(id: unknown): id is WorkflowId { |
| 385 | return typeof id === "string" && (VALID_IDS as readonly string[]).includes(id); |
| 386 | } |
| 387 | |
| 388 | export function getWorkflow(id: string | undefined): WorkflowTemplate { |
| 389 | if (id && isValidWorkflowId(id)) return WORKFLOWS[id]; |
| 390 | return WORKFLOWS.custom; |
| 391 | } |
| 392 | |
| 393 | export function getPhase(t: WorkflowTemplate, i: number): WorkflowPhase | undefined { |
| 394 | if (i < 0 || i >= t.phases.length) return undefined; |
| 395 | return t.phases[i]; |
| 396 | } |
| 397 | |
| 398 | export function listValidWorkflowIds(): readonly WorkflowId[] { |
| 399 | return VALID_IDS; |
| 400 | } |
| 401 | |
| 402 | export function summarizeWorkflows(): WorkflowSummary[] { |
| 403 | return (Object.values(WORKFLOWS) as WorkflowTemplate[]).map((t) => ({ |
| 404 | id: t.id, |
| 405 | name: t.name, |
| 406 | description: t.description, |
| 407 | goalPlaceholder: t.goalPlaceholder, |
| 408 | forcedInitiator: t.forcedInitiator, |
| 409 | phases: t.phases.map((p) => ({ id: p.id, name: p.name })), |
| 410 | })); |
| 411 | } |