Skip to content

🤖 feat: add first-class nested workflows#3565

Merged
ThomasK33 merged 6 commits into
mainfrom
workflow-cx5h
Jun 15, 2026
Merged

🤖 feat: add first-class nested workflows#3565
ThomasK33 merged 6 commits into
mainfrom
workflow-cx5h

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Jun 15, 2026

Copy link
Copy Markdown
Member

Summary

Adds first-class nested workflow execution through the built-in action.workflows.start primitive. Parent workflow steps now deterministically map to child workflow runs, replay/resume attaches to the same child run, child failure/interruption/backgrounding is reflected on the parent, and nested runs stay out of top-level task discovery while remaining explicitly awaitable by run ID.

Background

Workflow authors needed durable conductor recursion without flattening child workflow internals into the parent journal. This implements nested workflows as normal child workflow runs linked by parent metadata, preserving each child run's own step namespace and event journal.

Implementation

  • Added parent/child workflow run metadata, deterministic child run IDs, idempotent child run creation, and self-healing for partial deterministic child-run directories.
  • Routed built-in workflows.start to runner-coordinated logic while preserving project/global overrides and allowing the runner-safe built-in in runtime-backed workspaces.
  • Coordinated child execution in WorkflowService, including current trust re-checks, child lease contention handling, background continuation, child failure finalization, cascade interruption, and replay repair for missing terminal workflow events.
  • Updated tool discovery filtering, model-bound workflow message stripping, nested workflow UI rows, tool docs, and workflow-authoring guidance.
  • Ran the deep-review-workflow and addressed its verified findings before PR creation.

Validation

  • bun test src/node/services/workflows/WorkflowService.test.ts src/node/services/workflows/WorkflowRunStore.test.ts src/node/services/workflows/WorkflowActionRegistry.test.ts src/browser/features/Tools/WorkflowRunToolCall.test.tsx src/common/utils/workflowRunMessages.test.ts --timeout 20000
  • make typecheck
  • MUX_ESLINT_CONCURRENCY=2 make static-check
  • Manual API/UI dogfooding captured under dogfood-output/nested-workflows/ locally, including desktop/mobile screenshots and workflow-card videos.

Dogfooding evidence

Desktop nested workflow card:

nested-workflow-ui-card-expanded.png

Mobile-width nested workflow card:

nested-workflow-ui-card-expanded-mobile.png

Risks

This touches the durable workflow runner, run-store persistence, task discovery, and workflow cards, so regression risk is medium-high. The main mitigations are deterministic child IDs, idempotent creation, trust gates, cascade interruption coverage, replay repair, targeted workflow tests, static checks, and manual dogfooding.

Pains

Deep review surfaced several lifecycle edge cases after the initial implementation: stale child leases, trust revocation, child failure finalization, interrupt/create races, and partial child-run directories. Those are addressed in the final patch set.


📋 Implementation Plan

Implementation Plan: First-Class Nested Workflows via action.workflows.start

Goal

Add first-class nested workflow execution so a workflow can start another workflow with transparent recursion semantics:

const result = action.workflows.start({
  id: "research",
  input: {
    name: "deep-research",
    args: { input: topic },
  },
});

The parent call should behave like any other durable workflow step: replay/resume must reuse the same child run, avoid duplicates, preserve child workflow step IDs locally, and allow nested/nested-nested workflows without child workflow definitions knowing they are nested.

Recommended approach and LoC estimate

Recommended approach: first-class runner primitive surfaced through the existing action.* syntax.

  • Net product LoC estimate: ~1,000–1,400 LoC.
    • Schema/types/run-store helpers: ~120–180 LoC
    • Runtime/WorkflowService child-run lifecycle: ~450–650 LoC
    • UI/tool filtering + nested row display: ~220–350 LoC
    • Docs/skill updates + constants/helpers: ~80–120 LoC
    • Defensive assertions and edge-case helpers: ~100 LoC
  • Why this approach: a generic host action does not currently have enough context to safely coordinate parent run backgrounding, child run leases, parent interruption, crash recovery, and replay drift checks. The workflow author API can still be action.workflows.start, but the built-in workflows.start action should route to runner-owned logic when the resolved action is the built-in one.
Alternatives considered
  1. Generic workspaceHostActions.ts host action — lower initial LoC (~600–900) but leaks workflow-runner concerns into host action context and cannot naturally throw/handle foreground backgrounding. Not recommended for transparent recursion.
  2. Flatten child workflow events into the parent by prefixing step IDs — very invasive (~1,800–2,500+ LoC) and risks breaking leases, status transitions, task ownership, child result semantics, and nested-nested workflows. Useful only as a UI display strategy, not as persistence.
  3. Agent-triggered workflow_run — already possible indirectly if the child agent has tools, but it is not deterministic conductor recursion and should not be treated as the feature.

Evidence from repo investigation

  • WorkflowRunner registers workflow globals in src/node/services/workflows/WorkflowRunner.ts (__workflowAgent, __workflowAction, __workflowApplyPatch, __workflowParallelAgents) and compiles action.* calls through __muxCreateWorkflowActionProxy.
  • WorkflowService (src/node/services/workflows/WorkflowService.ts) owns named run creation, foreground/background run choreography, leases, abort-to-interrupt wiring, and crash recovery resume behavior.
  • WorkflowRunStore (src/node/services/workflows/WorkflowRunStore.ts) persists run records plus append-only events.jsonl / steps.jsonl; WorkflowStepRecord.taskId already stores a durable handle for child work.
  • workflowReplayKey.ts hashes stable step IDs with canonical JSON input; nested workflow starts should use the same replay identity discipline.
  • Built-in actions are resolved through WorkflowActionRegistry, described by builtInWorkflowActions.ts, and executed by WorkflowActionRunner; project/global actions take precedence over built-ins.
  • Workflow run cards and foreground discovery live mainly in src/browser/features/Tools/WorkflowRunToolCall.tsx, with chat-card projection helpers in src/common/utils/workflowRunMessages.ts and discovery in src/browser/features/ChatInput/index.tsx.
  • workflow_run / workflow_resume tools and task_await already understand workflow run IDs; omitted waits intentionally exclude workflow-owned child agents, so nested child workflow runs should similarly avoid cluttering top-level waits while remaining explicitly addressable by ID.

Non-goals for V1

  • Cross-workspace child workflow starts. V1 starts child workflows in the same workspace as the parent.
  • Fire-and-forget child workflows. V1 defaults to and requires “wait for terminal child result” semantics so parent composition is deterministic.
  • Arbitrary parallel child workflow fan-out helper. Authors can call multiple nested starts sequentially in V1; parallelWorkflows can be designed later if needed.
  • Flattened parent journal persistence. Child workflows remain separate normal workflow runs.
  • Full infinitely recursive inline UI. V1 shows a child workflow row/status under the parent and exposes the child run ID; deep inline expansion can be deferred.

Phase 1 — Add durable parent/child run linkage

Files/symbols

  • src/common/orpc/schemas/workflow.ts
  • src/common/types/workflow.ts
  • src/node/services/workflows/WorkflowRunStore.ts
  • src/node/services/workflows/WorkflowRunStore.test.ts
  • New or existing helper near WorkflowService.ts / workflowReplayKey.ts for child run IDs.

Changes

  1. Extend WorkflowRunRecordSchema with optional parent linkage:

    const WorkflowRunParentSchema = z.object({
      runId: WorkflowRunIdSchema,
      stepId: z.string().min(1),
      inputHash: z.string().min(1),
      depth: z.number().int().nonnegative(),
    }).strict();
    
    // WorkflowRunRecordSchema
    parentWorkflow: WorkflowRunParentSchema.optional(),

    This keeps existing run records compatible and gives UI/tool code a reliable way to distinguish top-level runs from child runs.

  2. Add a deterministic child run ID helper:

    deriveChildWorkflowRunId(parentRunId, stepId, inputHash) => `wfr_child_${sha256(...).slice(0, 32)}`

    Use a hash, not raw step IDs, to satisfy WorkflowRunIdSchema length/character constraints and avoid leaking arbitrary workflow-authored strings.

  3. Add CreateWorkflowRunInput.parentWorkflow? and persist it in WorkflowRunStore.createRun.

  4. Add an idempotent creation path such as WorkflowRunStore.createRunIfAbsent(input) or WorkflowService.ensureChildWorkflowRun(...) that:

    • creates the child run only if absent;
    • uses an atomic no-overwrite run-directory creation/lock path instead of the current recursive createRun() write path;
    • never overwrites an existing run directory/run file;
    • returns the existing run if its workspace, snapshotted workflow name, args, and parentWorkflow linkage match;
    • does not fail merely because the current workflow definition source changed after the child run was created—the child run’s snapshotted definition is authoritative;
    • fails fast if the deterministic child run ID exists with mismatched identity.
  5. Add defensive assertions:

    • parent run ID, step ID, and input hash are non-empty;
    • derived run ID parses with WorkflowRunIdSchema;
    • child depth is bounded by a new constant, e.g. MAX_NESTED_WORKFLOW_DEPTH = 8.

Quality gate after Phase 1

  • Targeted tests for schema parsing of old/new records.
  • Targeted run-store tests proving createRunIfAbsent does not overwrite an existing child run and rejects identity drift.
  • bun test src/common/orpc/schemas/workflow.test.ts src/node/services/workflows/WorkflowRunStore.test.ts

Phase 2 — Implement the nested workflow runtime primitive

Files/symbols

  • src/node/services/workflows/WorkflowRunner.ts
  • src/node/services/workflows/WorkflowService.ts
  • src/node/services/workflows/builtInWorkflowActions.ts
  • src/node/services/workflows/WorkflowRunner.test.ts
  • src/node/services/workflows/WorkflowService.test.ts
  • src/node/services/workflows/builtInWorkflowDefinitions.test.ts or action registry tests as needed.

API shape

Support the normal action-call forms while requiring stable parent step IDs:

const result = action.workflows.start({
  id: "research",
  input: { name: "deep-research", args: { input: topic } },
});

// Existing action proxy shorthand should also work if practical:
const result = action.workflows.start("research", {
  name: "deep-research",
  args: { input: topic },
});

V1 should reject wait: false / runInBackground: true if provided, with a clear message that fire-and-forget nested workflows are deferred. This preserves deterministic parent result composition.

Runtime design

  1. Add a built-in action descriptor for workflows.start so workflow_action_list / registry discovery can expose metadata. Keep project/global action precedence intact:

    • if WorkflowActionRegistry.resolveAction("workflows.start") returns project/global scope, execute it as a normal action;
    • if it returns built-in scope/name workflows.start, route to the nested workflow primitive instead of WorkflowActionRunner.execute.
  2. Add parser/validator for the nested start spec:

    type WorkflowStartInput = {
      name: string;
      args?: JsonValue;
    };

    Normalize absent args to {} for replay identity. Assert JSON-only/canonical input using the existing replay-key canonicalization rules.

  3. In WorkflowRunner.runActionStep, after resolving the action and before generic action execution, route the built-in workflows.start to runNestedWorkflowStep(...).

  4. runNestedWorkflowStep(...) should mirror agent / applyPatch replay discipline:

    • compute inputHash = hashWorkflowStepInput(spec.id, { primitive: "workflows.start", name, args });

    • if a completed step with same hash exists, emit/repair a terminal child workflow row if needed and return cached child result;

    • if a same stepId has any prior child workflow attempt with a different input hash, fail safely instead of creating another child run under the same durable boundary;

    • derive the deterministic child runId before any child mutation;

    • record parent step started with taskId: childRunId before child creation, so replay can safely create the child if a crash happens before creation or attach to it if a crash happens after creation;

    • append a new parent WorkflowRunEvent variant for child workflow lifecycle, rather than overloading task events; these lifecycle events should be append-if-missing / replay-repairable so replay does not duplicate child status rows:

      {
        type: "workflow";
        stepId: string;
        runId: string;
        name: string;
        status: "started" | "running" | "backgrounded" | "completed" | "failed" | "interrupted";
        details?: JsonValue;
      }
    • wait for child terminal result;

    • on child completed, record parent step completed with taskId: childRunId and result equal to the child workflow result plus structured metadata { runId, status, name };

    • on child failed, record parent step failed with child error and fail the parent workflow;

    • on parent abort/interruption, stop waiting and allow cascade interruption to handle the child.

  5. Add a required WorkflowChildRunAdapter-style interface to WorkflowRunner options instead of importing or constructing WorkflowService inside WorkflowRunner:

    interface WorkflowChildRunAdapter {
      ensureChildRun(input): Promise<{ runId: string; run: WorkflowRunRecord }>;
      runChildToTerminal(input): Promise<StartNamedWorkflowResult>;
      getChildRun(input): Promise<WorkflowRunRecord | null>;
      interruptChildRun(input): Promise<void>;
    }

    WorkflowService.createRunner passes an implementation bound to the same workspace/run store/definition store.

  6. Add WorkflowService child-run helpers:

    • ensureChildWorkflowRun(...): read the child definition, create child run with deterministic ID and parentWorkflow metadata if absent.
    • runChildWorkflowToTerminal(...): run/resume/wait the child according to current status.
      • pending: run it.
      • running / backgrounded: wait/poll the existing run; resume crash-orphaned runs only through existing lease-safe mechanisms.
      • interrupted: when the parent is explicitly resumed, resume the child.
      • completed: return final result.
      • failed: return failed status; parent step fails by default.
    • Ensure child runner uses the same project trust checks as normal workflow starts and snapshots the child definition at child creation time.
  7. Preserve backgrounding semantics:

    • If the parent is a foreground run and the child backgrounds, record the parent child-step start and throw the existing foreground-backgrounding signal so the parent run becomes backgrounded.
    • The parent background continuation should re-enter the same child step and wait/poll with backgroundOnMessageQueued: false until the child terminal status.
    • Avoid treating a child backgrounded status as success.
    • Do not add a separate parent wake-up mechanism in V1; the existing background continuation path should own waiting for terminal child status.
  8. Add cascade interruption:

    • Extend WorkflowService.interruptRun to discover started child workflow runs from the parent run’s steps (taskId that parses as WorkflowRunIdSchema and/or run.parentWorkflow.runId === parent.id) and recursively interrupt non-terminal children.
    • Keep existing agent-task interruption via WorkflowTaskServiceAdapter.interruptRun.
    • Guard against cycles with parent linkage/depth assertions.

Quality gate after Phase 2

  • WorkflowRunner.test.ts cases:
    • nested start creates one child run and returns child result;
    • replay of completed parent step returns cached result without creating/running another child;
    • crash/replay after child creation but before parent completion attaches to the same deterministic child run;
    • crash/replay after parent step-start but before child creation creates the same deterministic child run;
    • replay attaches to an existing child run even if the child workflow definition source changed after the child run was created;
    • same step ID with changed workflow name/args fails safely;
    • child failure fails the parent step;
    • child backgrounding backgrounds parent, and background continuation completes parent after child terminal status.
  • WorkflowService.test.ts cases:
    • child run has parent metadata and depth;
    • parent interrupt recursively interrupts running child;
    • resumed parent resumes interrupted child;
    • depth limit rejects recursive overflow.
  • Targeted command:
    • bun test src/node/services/workflows/WorkflowRunner.test.ts src/node/services/workflows/WorkflowService.test.ts

Phase 3 — Tool/API/UI surfacing

Files/symbols

  • src/common/orpc/schemas/workflow.ts
  • src/node/services/tools/task_list.ts
  • src/node/services/tools/task_await.ts
  • src/browser/features/Tools/WorkflowRunToolCall.tsx
  • src/browser/features/Tools/WorkflowRunToolCall.test.tsx
  • src/browser/features/Tools/WorkflowRunToolCall.stories.tsx
  • src/common/utils/workflowRunMessages.ts
  • src/common/utils/workflowRunMessages.test.ts
  • src/browser/features/ChatInput/index.tsx foreground workflow discovery path.

Changes

  1. Add a shared helper such as isNestedWorkflowRun(run) / isWorkflowRunId(value) to avoid duplicating wfr_ checks.

  2. Exclude child workflow runs from top-level discovery by default:

    • task_list should list top-level workflow runs; nested child runs remain explicitly addressable by ID.
    • task_await with omitted IDs should not wait on child runs separately because the parent owns them; explicit task_await({ task_ids: [childRunId] }) should still work.
    • getWorkflowRunCardProjection / ChatInput foreground discovery should not emit separate top-level cards for child runs.
  3. Parent workflow run card display:

    • In WorkflowRunToolCall.tsx, classify nested workflow rows from the new workflow event.
    • Do not infer child workflows from generic task events; WorkflowStepRecord.taskId = childRunId is only the durable step link.
    • Show at least: child workflow name, child run ID, status, and terminal summary/error.
    • Keep the V1 UI simple and responsive; do not recursively render full child logs inline.
    • Add/copy stories for desktop and narrow/mobile viewport (~375px) so badges/IDs do not overflow.
  4. Add tests for:

    • top-level discovery ignores parentWorkflow runs;
    • nested workflow row renders started/completed/failed states;
    • mobile/narrow layout does not overflow.

Quality gate after Phase 3

  • bun test src/browser/features/Tools/WorkflowRunToolCall.test.tsx src/common/utils/workflowRunMessages.test.ts
  • Storybook story renders at desktop and pinned mobile viewport.
  • If visual snapshots are affected, regenerate approved README/story screenshots only if required by the repo’s visual workflow.

Phase 4 — Docs and workflow authoring guidance

Files/symbols

  • src/node/builtinSkills/workflow-authoring.md
  • Generated built-in skill content if the repo requires regeneration.
  • Any workflow/action docs or examples that list available workflow globals/actions.

Changes

  1. Document action.workflows.start under workflow authoring as a special built-in workflow action/primitive.
  2. State replay semantics explicitly:
    • child step IDs remain scoped to child run;
    • parent step ID + normalized input maps to exactly one child run;
    • child failure fails parent by default;
    • parent interrupt cascades to child;
    • cross-workspace and fire-and-forget are deferred.
  3. Add a minimal example parent/child workflow pair.

Quality gate after Phase 4

  • make typecheck
  • make lint
  • Targeted docs/skill generation command if required by repo scripts.

Phase 5 — End-to-end validation and dogfooding

Automated validation

Run, in order, fixing failures before claiming completion:

bun test src/common/orpc/schemas/workflow.test.ts \
  src/node/services/workflows/WorkflowRunStore.test.ts \
  src/node/services/workflows/WorkflowRunner.test.ts \
  src/node/services/workflows/WorkflowService.test.ts \
  src/browser/features/Tools/WorkflowRunToolCall.test.tsx \
  src/common/utils/workflowRunMessages.test.ts
make typecheck
make lint

If the touched surface is broad, finish with:

make static-check

Manual dogfooding setup

  1. Create scratch workflows under .mux/workflows/.scratch/ in the dogfood workspace only (do not commit scratch workflows unless intentionally turning them into fixtures):

    child-simple.js

    // description: Child workflow for nested workflow dogfooding
    export default function workflow({ args, phase, log }) {
      phase("child-start", { input: args.input });
      log("Child workflow ran", { input: args.input });
      return { reportMarkdown: "Child complete: " + String(args.input ?? "") };
    }

    parent-simple.js

    // description: Parent workflow for nested workflow dogfooding
    export default function workflow({ args, action, phase, log }) {
      phase("parent-start", { input: args.input });
      const child = action.workflows.start({
        id: "child-simple",
        input: { name: "child-simple", args: { input: args.input } },
      });
      log("Child result received", { child });
      return { reportMarkdown: "Parent complete\n\n" + child.reportMarkdown };
    }
  2. Run via the workflow_run tool or slash workflow command:

    workflow_run({ name: "parent-simple", args: { input: "nested smoke" } })
    
  3. Verify:

    • parent completes;
    • exactly one child run exists with parentWorkflow metadata;
    • re-fetching/resuming the parent does not create a duplicate child;
    • parent card shows the nested child row.

Resilience dogfooding

  1. Use a child workflow that calls agent({ id: "slow-child", ... }) so the child can background.
  2. Start the parent workflow in the UI.
  3. Interrupt the parent while the child is active.
  4. Confirm both parent and child become interrupted and no child agent keeps running.
  5. Resume the parent.
  6. Confirm parent replays into the same child run and completes.

UI dogfooding evidence

Use the repo dogfood, global agent-browser, and project dev-server-sandbox skill guidance:

  1. Start an isolated Mux dev server so dogfooding does not conflict with the developer’s normal root:

    make dev-server-sandbox

    Use DEV_SERVER_SANDBOX_ARGS="--clean-projects" if the implementation needs a clean project list, and KEEP_SANDBOX=1 only when preserving the temp MUX_ROOT is useful for debugging.

  2. Before browser automation, load the installed CLI’s current browser workflow docs and use the direct binary, never npx:

    agent-browser skills get core
  3. Initialize a dogfood evidence directory and report:

    mkdir -p dogfood-output/nested-workflows/screenshots dogfood-output/nested-workflows/videos

    Use the dogfood report template from the skill and append findings immediately as they are found. Every interactive issue needs a repro video plus step-by-step screenshots; static visible issues need at least one annotated screenshot.

  4. Open the sandboxed Mux UI with a named browser session, then orient with an annotated screenshot and interactive snapshot:

    agent-browser --session nested-workflows open <SANDBOX_UI_URL>
    agent-browser --session nested-workflows wait --load networkidle
    agent-browser --session nested-workflows screenshot --annotate dogfood-output/nested-workflows/screenshots/initial.png
    agent-browser --session nested-workflows snapshot -i
  5. Execute the nested workflow smoke and resilience scenarios from the UI. Capture:

    • annotated screenshot of the parent workflow card with child row running;

    • annotated screenshot of the parent workflow card with child row completed;

    • screenshot at ~375px mobile width;

    • agent-browser console/errors output after the workflow card updates;

    • paced repro video for interrupt → resume → complete:

      agent-browser --session nested-workflows record start dogfood-output/nested-workflows/videos/interrupt-resume-complete.webm
      # perform the interrupt/resume flow at human pace, with screenshots between steps
      agent-browser --session nested-workflows record stop
  6. Close the session only after evidence is captured:

    agent-browser --session nested-workflows close
  7. Attach screenshots/video to the final implementation report or PR so reviewers can verify the path taken.

Acceptance criteria

  • A workflow can call a built-in action.workflows.start with a stable id and child workflow { name, args }.
  • The parent step maps deterministically to exactly one child workflow run for a given parent run + step ID + normalized input.
  • Child workflow internals are unmodified: child step IDs remain local to the child run and replay normally.
  • Parent replay/resume after crashes or backgrounding reuses/resumes the linked child run rather than creating duplicates.
  • Child completed result becomes the parent step result; child failure fails the parent step by default.
  • Parent interrupt cascades to active child workflow runs and their workflow-owned agent tasks.
  • Child runs are hidden from default top-level run discovery/listing but remain explicitly addressable by run ID.
  • Parent workflow run cards show child workflow status without overflowing on mobile-width layouts.
  • Existing workflow actions, agents, parallelAgents, applyPatch, workflow scheduling, slash workflows, and CLI workflow starts continue to pass existing tests.

Main risks and mitigations

Risk Mitigation
Duplicate child run if crash occurs between child create and parent step completion Deterministic child run ID + create-if-absent + identity validation
Same parent step ID reused with different child workflow input Apply mutating-step-style drift guard and fail safely
Parent backgrounds while child is still running Treat child backgrounding like agent foreground backgrounding; parent background continuation waits with backgroundOnMessageQueued: false
Parent interrupt leaves child running Recursive interrupt by child run IDs/parent metadata
Infinite self-recursion Persist depth and enforce MAX_NESTED_WORKFLOW_DEPTH
Top-level UI/task list clutter Hide parentWorkflow runs from default discovery while preserving explicit lookup by ID
Project/global action named workflows.start conflict Resolve through registry first; only special-case the built-in workflows.start, preserving override semantics

Advisor review status

Approved after two advisor review passes. Final advisor notes incorporated: concrete workflow event model, atomic no-overwrite child creation, snapshotted child definition wins on replay, required WorkflowChildRunAdapter seam, strict same-workspace/wait-to-terminal V1, and no separate wake-up service.


Generated with mux • Model: openai:gpt-5.5 • Thinking: xhigh • Cost: 2665599{MUX_COSTS_USD:-unknown}

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please review the nested workflow implementation and the deep-review follow-up fixes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9bbeb36be0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workflows/WorkflowRunner.ts Outdated
Comment thread src/node/services/workflows/WorkflowService.ts
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please take another look. I addressed the explicit args: null preservation and the completed nested workflow report-index filtering findings in 48406a9, with targeted tests and static-check passing locally.

@mintlify

mintlify Bot commented Jun 15, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
Mux 🟢 Ready View Preview Jun 15, 2026, 6:04 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please review the latest push as well. I rebased onto the latest main, fixed the sealed-history compaction epoch regression that was failing Unit CI, and reran targeted tests plus static-check locally.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 581265eeab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workflows/WorkflowService.ts Outdated
Comment thread src/node/services/workflows/WorkflowActionRegistry.ts
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please take another look. I addressed the parent default action cwd snapshot and runtime-backed workflows.start discovery findings in 60dd947, with targeted tests and static-check passing locally.

Implement first-class nested workflow starts via the built-in action.workflows.start primitive, including deterministic child run IDs, parent/child metadata, run-store idempotency, nested workflow UI rows, tool discovery filtering, docs, and regression coverage.

---

_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `1754016{MUX_COSTS_USD:-unknown}`_

<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=84.62 -->
Address deep-review findings for nested workflow runs: re-check current project trust, finalize failed child steps/events, avoid interrupt/create orphans, tolerate child lease contention, recover partial child run directories, expose runner-coordinated workflows.start for runtime-backed workspaces, repair missing terminal events, and document nested discovery semantics.

Validation:

- bun test src/node/services/workflows/WorkflowService.test.ts src/node/services/workflows/WorkflowRunStore.test.ts src/node/services/workflows/WorkflowActionRegistry.test.ts src/browser/features/Tools/WorkflowRunToolCall.test.tsx src/common/utils/workflowRunMessages.test.ts --timeout 20000

- make typecheck

- MUX_ESLINT_CONCURRENCY=2 make static-check

---

_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `2628699{MUX_COSTS_USD:-unknown}`_

<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=84.62 -->
Preserve explicit null args for nested workflow starts and keep completed child workflow reports out of post-compaction top-level report indexes.

Validation:

- bun test src/node/services/workflows/WorkflowService.test.ts src/node/services/attachmentService.completedReports.test.ts --timeout 20000

- MUX_ESLINT_CONCURRENCY=2 make static-check

---

_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `2874038{MUX_COSTS_USD:-unknown}`_

<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=84.62 -->
Address Codex follow-up feedback by snapshotting child runs with the parent run default action cwd and listing runner-coordinated workflows.start actions in runtime-backed workspaces.

Validation:

- bun test src/node/services/workflows/WorkflowService.test.ts src/node/services/workflows/WorkflowActionRegistry.test.ts --timeout 20000

- MUX_ESLINT_CONCURRENCY=2 make static-check

---

_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `3783076{MUX_COSTS_USD:-unknown}`_

<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=84.62 -->
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please take another look after the latest rebase onto main. The previous follow-up fixes are still present, and local targeted validation plus static-check pass on the rebased branch.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 195272ec8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workflows/WorkflowService.ts
Register nested child workflow runners with the active abort-controller map once their lease is acquired so direct interrupts by child run ID abort the child runtime in addition to marking status.

Validation:

- bun test src/node/services/workflows/WorkflowService.test.ts --timeout 20000

- MUX_ESLINT_CONCURRENCY=2 make static-check

---

_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `3989322{MUX_COSTS_USD:-unknown}`_

<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=84.62 -->
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please take another look. I addressed the direct child-run interrupt issue in cc0a91a, with targeted WorkflowService coverage and static-check passing locally.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cc0a91ade4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workflows/WorkflowService.ts Outdated
Include already-interrupted nested children in parent interrupt cascades so workflow-owned child task adapters are still interrupted after the child run status was marked interrupted first.

Validation:

- bun test src/node/services/workflows/WorkflowService.test.ts --timeout 20000

- MUX_ESLINT_CONCURRENCY=2 make static-check

---

_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `4091238{MUX_COSTS_USD:-unknown}`_

<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=84.62 -->
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please take another look. I addressed the already-interrupted child cascade issue in 0895bbf, with targeted WorkflowService coverage and static-check passing locally.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 0895bbfa74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33 ThomasK33 added this pull request to the merge queue Jun 15, 2026
Merged via the queue into main with commit 168c3e4 Jun 15, 2026
23 checks passed
@ThomasK33 ThomasK33 deleted the workflow-cx5h branch June 15, 2026 19:21
mux-bot Bot added a commit that referenced this pull request Jun 15, 2026
#3565 reintroduced a hardcoded startsWith("wfr_") in WorkflowRunner's
nested-step drift detection. taskId.ts already exports the canonical
WORKFLOW_RUN_TASK_ID_PREFIX and isWorkflowRunTaskId() predicate as the
single source of truth for that prefix. Use the helper instead of the
duplicated literal; behavior is identical (both are falsy for a missing
taskId inside the find() predicate).
mux-bot Bot added a commit that referenced this pull request Jun 16, 2026
#3565 reintroduced a hardcoded startsWith("wfr_") in WorkflowRunner's
nested-step drift detection. taskId.ts already exports the canonical
WORKFLOW_RUN_TASK_ID_PREFIX and isWorkflowRunTaskId() predicate as the
single source of truth for that prefix. Use the helper instead of the
duplicated literal; behavior is identical (both are falsy for a missing
taskId inside the find() predicate).
mux-bot Bot added a commit that referenced this pull request Jun 16, 2026
#3565 reintroduced a hardcoded startsWith("wfr_") in WorkflowRunner's
nested-step drift detection. taskId.ts already exports the canonical
WORKFLOW_RUN_TASK_ID_PREFIX and isWorkflowRunTaskId() predicate as the
single source of truth for that prefix. Use the helper instead of the
duplicated literal; behavior is identical (both are falsy for a missing
taskId inside the find() predicate).
mux-bot Bot added a commit that referenced this pull request Jun 16, 2026
#3565 reintroduced a hardcoded startsWith("wfr_") in WorkflowRunner's
nested-step drift detection. taskId.ts already exports the canonical
WORKFLOW_RUN_TASK_ID_PREFIX and isWorkflowRunTaskId() predicate as the
single source of truth for that prefix. Use the helper instead of the
duplicated literal; behavior is identical (both are falsy for a missing
taskId inside the find() predicate).
mux-bot Bot added a commit that referenced this pull request Jun 17, 2026
#3565 reintroduced a hardcoded startsWith("wfr_") in WorkflowRunner's
nested-step drift detection. taskId.ts already exports the canonical
WORKFLOW_RUN_TASK_ID_PREFIX and isWorkflowRunTaskId() predicate as the
single source of truth for that prefix. Use the helper instead of the
duplicated literal; behavior is identical (both are falsy for a missing
taskId inside the find() predicate).
mux-bot Bot added a commit that referenced this pull request Jun 17, 2026
#3565 reintroduced a hardcoded startsWith("wfr_") in WorkflowRunner's
nested-step drift detection. taskId.ts already exports the canonical
WORKFLOW_RUN_TASK_ID_PREFIX and isWorkflowRunTaskId() predicate as the
single source of truth for that prefix. Use the helper instead of the
duplicated literal; behavior is identical (both are falsy for a missing
taskId inside the find() predicate).
mux-bot Bot added a commit that referenced this pull request Jun 17, 2026
#3565 reintroduced a hardcoded startsWith("wfr_") in WorkflowRunner's
nested-step drift detection. taskId.ts already exports the canonical
WORKFLOW_RUN_TASK_ID_PREFIX and isWorkflowRunTaskId() predicate as the
single source of truth for that prefix. Use the helper instead of the
duplicated literal; behavior is identical (both are falsy for a missing
taskId inside the find() predicate).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant