99 * - What MCP servers and package manager detector to use
1010 * - What happens after the agent completes
1111 *
12- * The pipeline itself is fixed:
13- * init → health check → settings → OAuth → [skill install] →
14- * agent init → prompt → run → errors → [postRun] → outro
12+ * The pipeline runs a shared bootstrap (logging, health check, settings, OAuth,
13+ * flags, MCP url), then forks. The `orchestrator` variant routes to the
14+ * experimental task-queue runner. Every other variant runs the fixed linear
15+ * pipeline:
16+ * [skill install] → agent init → prompt → run → errors → [postRun] → outro
1517 */
1618
1719import {
@@ -53,7 +55,7 @@ import { getSkillsBaseUrl } from '@lib/constants';
5355import { runtimeEnv } from '@env' ;
5456import { installSkillById , type InstallSkillResult } from '@lib/wizard-tools' ;
5557import { createWizardAskBridge } from '@lib/wizard-ask-bridge' ;
56- import type { WizardRunOptions } from '@utils/types' ;
58+ import type { WizardRunOptions , CloudRegion } from '@utils/types' ;
5759
5860import type { ProgramConfig } from '@lib/programs/program-step' ;
5961import { assemblePrompt , type PromptContext } from './agent-prompt' ;
@@ -108,7 +110,7 @@ export interface ProgramRun {
108110 buildOutroData ?: (
109111 session : WizardSession ,
110112 credentials : Credentials ,
111- cloudRegion : import ( '@utils/types' ) . CloudRegion | undefined ,
113+ cloudRegion : CloudRegion | undefined ,
112114 ) => WizardSession [ 'outroData' ] ;
113115 /**
114116 * Per-run cap on `wizard_ask` invocations. Defaults to 10. The 4th call
@@ -124,6 +126,23 @@ export interface ProgramRun {
124126 askTimeoutMs ?: number ;
125127}
126128
129+ /**
130+ * Result of the shared bootstrap, consumed by both the linear and the
131+ * orchestrator arm. Credentials, role, and user are already applied to the
132+ * session by `bootstrapProgram`; this carries the values both arms still need.
133+ */
134+ export interface BootstrapResult {
135+ skillsBaseUrl : string ;
136+ projectApiKey : Credentials [ 'projectApiKey' ] ;
137+ host : Credentials [ 'host' ] ;
138+ accessToken : Credentials [ 'accessToken' ] ;
139+ projectId : Credentials [ 'projectId' ] ;
140+ cloudRegion : CloudRegion ;
141+ mcpUrl : string ;
142+ wizardFlags : Record < string , string > ;
143+ wizardMetadata : Record < string , string > ;
144+ }
145+
127146// ── Helpers ──────────────────────────────────────────────────────────
128147
129148/**
@@ -179,16 +198,31 @@ export async function runAgent(
179198/**
180199 * Run a program's agent pipeline.
181200 *
182- * This is the single execution path for all programs — both skill-based
183- * (revenue analytics) and framework-based (core integration). The
184- * `ProgramRun` controls what varies between them; `programConfig` carries
185- * the program-level static metadata (tool allow/disallow lists, etc.).
201+ * Runs the shared bootstrap, then forks on the `wizard-variant` flag. The
202+ * `orchestrator` variant routes to the experimental task-queue runner; every
203+ * other variant runs the linear pipeline.
186204 */
187205export async function runProgram (
188206 session : WizardSession ,
189207 config : ProgramRun ,
190208 programConfig : ProgramConfig ,
191209) : Promise < void > {
210+ const boot = await bootstrapProgram ( session , config , programConfig ) ;
211+
212+ return runLinearProgram ( session , config , programConfig , boot ) ;
213+ }
214+
215+ /**
216+ * Shared setup for both arms: logging, health check, settings conflicts, OAuth
217+ * and credentials, then the feature flags, variant metadata, and MCP url. Sets
218+ * `session.credentials`, role, and user as a side effect. Returns the values the
219+ * arms still need.
220+ */
221+ async function bootstrapProgram (
222+ session : WizardSession ,
223+ config : ProgramRun ,
224+ programConfig : ProgramConfig ,
225+ ) : Promise < BootstrapResult > {
192226 // 1. Init logging + debug
193227 initLogFile ( ) ;
194228 session . skillId = config . skillId ?? config . integrationLabel ;
@@ -310,10 +344,60 @@ export async function runProgram(
310344 // install and agent start, so no source leaves the machine. The screen
311345 // alone is cosmetic; this await is the actual gate. Resolves
312346 // immediately when the program declared requiresAi: false or in CI.
347+ // In bootstrapProgram so both the linear and orchestrator arms gate.
313348 logToFile ( '[agent-runner] checking AI opt-in gate' ) ;
314349 await getUI ( ) . waitForAiOptIn ( ) ;
315350 logToFile ( '[agent-runner] AI opt-in gate cleared' ) ;
316351
352+ // Feature flags, variant metadata, and MCP url. Both arms need these, and the
353+ // fork decision reads the flags.
354+ const wizardFlags = await analytics . getAllFlagsForWizard ( ) ;
355+ const wizardMetadata = buildWizardMetadata ( wizardFlags ) ;
356+
357+ const mcpUrl = session . localMcp
358+ ? 'http://localhost:8787/mcp'
359+ : runtimeEnv ( 'MCP_URL' ) ||
360+ ( cloudRegion === 'eu'
361+ ? 'https://mcp-eu.posthog.com/mcp'
362+ : 'https://mcp.posthog.com/mcp' ) ;
363+
364+ return {
365+ skillsBaseUrl,
366+ projectApiKey,
367+ host,
368+ accessToken,
369+ projectId,
370+ cloudRegion,
371+ mcpUrl,
372+ wizardFlags,
373+ wizardMetadata,
374+ } ;
375+ }
376+
377+ /**
378+ * The linear pipeline. Single execution path for all non-orchestrator programs,
379+ * both skill-based (revenue analytics) and framework-based (core integration).
380+ * The `ProgramRun` controls what varies between them; `programConfig` carries the
381+ * program-level static metadata (tool allow/disallow lists, etc.).
382+ */
383+ async function runLinearProgram (
384+ session : WizardSession ,
385+ config : ProgramRun ,
386+ programConfig : ProgramConfig ,
387+ boot : BootstrapResult ,
388+ ) : Promise < void > {
389+ const {
390+ skillsBaseUrl,
391+ projectApiKey,
392+ host,
393+ accessToken,
394+ projectId,
395+ cloudRegion,
396+ mcpUrl,
397+ wizardFlags,
398+ wizardMetadata,
399+ } = boot ;
400+
317401 // 5. Skill install (if skillId provided)
318402 let skillPath : string | undefined ;
319403 if ( config . skillId ) {
@@ -333,15 +417,6 @@ export async function runProgram(
333417
334418 // 6. Initialize agent
335419 const spinner = getUI ( ) . spinner ( ) ;
336- const wizardFlags = await analytics . getAllFlagsForWizard ( ) ;
337- const wizardMetadata = buildWizardMetadata ( wizardFlags ) ;
338-
339- const mcpUrl = session . localMcp
340- ? 'http://localhost:8787/mcp'
341- : runtimeEnv ( 'MCP_URL' ) ||
342- ( cloudRegion === 'eu'
343- ? 'https://mcp-eu.posthog.com/mcp'
344- : 'https://mcp.posthog.com/mcp' ) ;
345420
346421 const restoreSettings = ( ) => restoreClaudeSettings ( session . installDir ) ;
347422 getUI ( ) . onEnterScreen ( 'outro' , restoreSettings ) ;
0 commit comments