Workflows graph extractor - #455

Merged
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor
Dec 27, 2025
Merged

Workflows graph extractor#455
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor

Conversation

@karthikscale3

@karthikscale3karthikscale3 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

This PR adds a new control flow graph extractor that analyzes bundled workflow files and generates graph manifests for workflow visualization.

Note: The corresponding UI updates for graph viewer are in #456

Changes

  • @workflow/builders: Add workflows-extractor.ts that parses workflow bundles using SWC to extract nodes and edges representing step calls, loops, conditionals, and parallel execution patterns
  • @workflow/builders: Add createWorkflowsManifest() method to BaseBuilder for generating workflow graph manifests post-bundle
  • @workflow/next: Integrate manifest generation into Next.js builder (initial build and watch mode rebuilds)

Output

Generates a workflows.json manifest containing React Flow-compatible graph data for each workflow, including:

  • Step nodes with metadata (loop context, conditional branches, parallel groups)
  • Edges representing control flow between steps
  • Support for transitive step resolution through helper functions

@changeset-bot

changeset-botBot commented Nov 28, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1e5807

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@workflow/world-postgresPatch
@workflow/world-localPatch
@workflow/sveltekitPatch
@workflow/buildersPatch
@workflow/nitroPatch
@workflow/utilsPatch
@workflow/worldPatch
@workflow/corePatch
@workflow/nextPatch
@workflow/webPatch
@workflow/cliPatch
workflowPatch
@workflow/astroPatch
@workflow/nuxtPatch
@workflow/errorsPatch
@workflow/web-sharedPatch
@workflow/world-testingPatch
@workflow/world-vercelPatch
@workflow/aiPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment threadworkbench/example/workflows/99_e2e.ts Outdated
Comment threadpackages/builders/src/standalone.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment thread.changeset/smart-insects-smile.md Outdated
Comment threadpackages/builders/src/base-builder.ts Outdated

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a bunch of comments we need to address. Very excited about this!

Let's try and just get things aligned with how we want to do manifests according to the versioning spec. I'll be a nuisance to try and clean this up later

@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp thanks for the review! Great and valid points! Let me do a bit of thinking to address these.

Comment threadpackages/builders/src/workflows-extractor.ts
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp Please take a look at the new iteration when you get a chance. Summary of the changes:

  1. Unified the partial manifest.debug.json files that gets generated inside .well-known/workflow/v1/flow and .well-known/workflow/v1/step directories as a single manifest.json.
  2. This new manifest.json file gets generated inside the .well-known/workflow/v1 directory for each builder.
  3. This manifest.json file is the single source of truth for all workflow metadata including the graph structure needed to build the Control Flow Graphs for the workflows and steps.
  4. See below the schema extension that allows this new structure. (A graph field is added to the workflows):
...
"workflows": {
"example/workflows/97_bench.ts": {
"noStepsWorkflow": {
"workflowId": "workflow//example/workflows/97_bench.ts//noStepsWorkflow",
"graph": {
"nodes": [
{
"id": "start",
"type": "workflowStart",
"data": {
"label": "Start: noStepsWorkflow",
"nodeKind": "workflow_start"
}
},
{
"id": "end",
"type": "workflowEnd",
"data": {
"label": "Return",
"nodeKind": "workflow_end"
}
}
],
"edges": [
{
"id": "e_start_end",
"source": "start",
"target": "end",
"type": "default"
}
]
}
},
...
image

I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8a3f152
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 252a0dd
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: b002d81
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8e21d56
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 1c45af6
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 68b23e0
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: e5f4cd8
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: d537846
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 0f62431
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Comment threadpackages/web/src/lib/flow-graph/manifest-adapter.ts Outdated
Comment threadpackages/web/src/components/run-detail-view.tsx Outdated
Comment threadpackages/world-testing/src/server.mts Outdated
Comment threadpackages/web/src/app/page.tsx Outdated
Comment threadpackages/web/src/components/settings-sidebar.tsx
@karthikscale3

karthikscale3 commented Dec 19, 2025

Copy link
Copy Markdown
ContributorAuthor

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Thanks for a comprehensive review. And the duplicate code between workflow-graph-viewer and workflow-graph-execution-viewer should be addressed with my next set of changes which I am iterating on based on some of the other feedback provided by @pranaygp. I am hoping to push my updates to this PR later today which should address your remaining comments as well.

@karthikscale3

karthikscale3 commented Dec 22, 2025

Copy link
Copy Markdown
ContributorAuthor

@pranaygp / @VaguelySerious - Thanks again for the comprehensive reviews. I have iterated further:

  • Made sure this feature is disabled for non local backend.
  • Addressed all the comments left by @VaguelySerious.
  • For representing conditionals, I have introduced a new node to show the actual condition from which the true and false edges branch out.
  • Made the node colors consistent and cleaned up the legends and made them more clear.
  • @pranaygp - For promise.all, promise.any, and promise.race, I have introduced an overlay container that holds the promises. I have kept the edges leaving each node within the container instead of having a single incoming and outgoing edge going in and out of the overlay container. While this might be cleaner, it won't accurately represent promise.race. In race scenarios, we would ideally want to see exactly which step won the race. Let me know what you think.
  • Loops are represented with a looping edge that is attached to the node on the left side.

Known limitation:

  • child workflows that are triggered within a step are not shown in the graph. I have left this for now as this requires a recursive extraction and I am not 100% sure of the best way to represent this in the graph.
imageimageimage

@karthikscale3karthikscale3 changed the title Workflows CFG ExtractorWorkflows graph extractorDec 22, 2025

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from an o11y and general maintenance perspective, will let @pranaygp voice any concerns about graph extraction, though my take is merge and ITG from here, since it's local-only, oss-ui-only, and isolated. I'm going to add plenty of error boundaries to this code once it's merged, before we release the next version, to assuage any concerns about brittle code.

Comment threadpackage.json Outdated
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@vercel

vercelBot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm to merge and iterate. Let's just fix up the merge conflicts and get this in - thanks so much for this and the multiple iterations. Very excited!

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Fixed the merge conflicts and pushed it up. Ready to merge once CI completes successfully! Thanks again for the reviews!

@VaguelySerious
VaguelySerious merged commit e3f0390 into vercel:mainDec 27, 2025
58 of 88 checks passed
Sign up for freeto 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.

3 participants

@karthikscale3@pranaygp@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Workflows graph extractor - #455

Merged
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor
Dec 27, 2025
Merged

Workflows graph extractor#455
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor

Conversation

@karthikscale3

@karthikscale3karthikscale3 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

This PR adds a new control flow graph extractor that analyzes bundled workflow files and generates graph manifests for workflow visualization.

Note: The corresponding UI updates for graph viewer are in #456

Changes

  • @workflow/builders: Add workflows-extractor.ts that parses workflow bundles using SWC to extract nodes and edges representing step calls, loops, conditionals, and parallel execution patterns
  • @workflow/builders: Add createWorkflowsManifest() method to BaseBuilder for generating workflow graph manifests post-bundle
  • @workflow/next: Integrate manifest generation into Next.js builder (initial build and watch mode rebuilds)

Output

Generates a workflows.json manifest containing React Flow-compatible graph data for each workflow, including:

  • Step nodes with metadata (loop context, conditional branches, parallel groups)
  • Edges representing control flow between steps
  • Support for transitive step resolution through helper functions

@changeset-bot

changeset-botBot commented Nov 28, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1e5807

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@workflow/world-postgresPatch
@workflow/world-localPatch
@workflow/sveltekitPatch
@workflow/buildersPatch
@workflow/nitroPatch
@workflow/utilsPatch
@workflow/worldPatch
@workflow/corePatch
@workflow/nextPatch
@workflow/webPatch
@workflow/cliPatch
workflowPatch
@workflow/astroPatch
@workflow/nuxtPatch
@workflow/errorsPatch
@workflow/web-sharedPatch
@workflow/world-testingPatch
@workflow/world-vercelPatch
@workflow/aiPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment threadworkbench/example/workflows/99_e2e.ts Outdated
Comment threadpackages/builders/src/standalone.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment thread.changeset/smart-insects-smile.md Outdated
Comment threadpackages/builders/src/base-builder.ts Outdated

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a bunch of comments we need to address. Very excited about this!

Let's try and just get things aligned with how we want to do manifests according to the versioning spec. I'll be a nuisance to try and clean this up later

@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp thanks for the review! Great and valid points! Let me do a bit of thinking to address these.

Comment threadpackages/builders/src/workflows-extractor.ts
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp Please take a look at the new iteration when you get a chance. Summary of the changes:

  1. Unified the partial manifest.debug.json files that gets generated inside .well-known/workflow/v1/flow and .well-known/workflow/v1/step directories as a single manifest.json.
  2. This new manifest.json file gets generated inside the .well-known/workflow/v1 directory for each builder.
  3. This manifest.json file is the single source of truth for all workflow metadata including the graph structure needed to build the Control Flow Graphs for the workflows and steps.
  4. See below the schema extension that allows this new structure. (A graph field is added to the workflows):
...
"workflows": {
"example/workflows/97_bench.ts": {
"noStepsWorkflow": {
"workflowId": "workflow//example/workflows/97_bench.ts//noStepsWorkflow",
"graph": {
"nodes": [
{
"id": "start",
"type": "workflowStart",
"data": {
"label": "Start: noStepsWorkflow",
"nodeKind": "workflow_start"
}
},
{
"id": "end",
"type": "workflowEnd",
"data": {
"label": "Return",
"nodeKind": "workflow_end"
}
}
],
"edges": [
{
"id": "e_start_end",
"source": "start",
"target": "end",
"type": "default"
}
]
}
},
...
image

I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8a3f152
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 252a0dd
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: b002d81
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8e21d56
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 1c45af6
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 68b23e0
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: e5f4cd8
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: d537846
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 0f62431
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Comment threadpackages/web/src/lib/flow-graph/manifest-adapter.ts Outdated
Comment threadpackages/web/src/components/run-detail-view.tsx Outdated
Comment threadpackages/world-testing/src/server.mts Outdated
Comment threadpackages/web/src/app/page.tsx Outdated
Comment threadpackages/web/src/components/settings-sidebar.tsx
@karthikscale3

karthikscale3 commented Dec 19, 2025

Copy link
Copy Markdown
ContributorAuthor

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Thanks for a comprehensive review. And the duplicate code between workflow-graph-viewer and workflow-graph-execution-viewer should be addressed with my next set of changes which I am iterating on based on some of the other feedback provided by @pranaygp. I am hoping to push my updates to this PR later today which should address your remaining comments as well.

@karthikscale3

karthikscale3 commented Dec 22, 2025

Copy link
Copy Markdown
ContributorAuthor

@pranaygp / @VaguelySerious - Thanks again for the comprehensive reviews. I have iterated further:

  • Made sure this feature is disabled for non local backend.
  • Addressed all the comments left by @VaguelySerious.
  • For representing conditionals, I have introduced a new node to show the actual condition from which the true and false edges branch out.
  • Made the node colors consistent and cleaned up the legends and made them more clear.
  • @pranaygp - For promise.all, promise.any, and promise.race, I have introduced an overlay container that holds the promises. I have kept the edges leaving each node within the container instead of having a single incoming and outgoing edge going in and out of the overlay container. While this might be cleaner, it won't accurately represent promise.race. In race scenarios, we would ideally want to see exactly which step won the race. Let me know what you think.
  • Loops are represented with a looping edge that is attached to the node on the left side.

Known limitation:

  • child workflows that are triggered within a step are not shown in the graph. I have left this for now as this requires a recursive extraction and I am not 100% sure of the best way to represent this in the graph.
imageimageimage

@karthikscale3karthikscale3 changed the title Workflows CFG ExtractorWorkflows graph extractorDec 22, 2025

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from an o11y and general maintenance perspective, will let @pranaygp voice any concerns about graph extraction, though my take is merge and ITG from here, since it's local-only, oss-ui-only, and isolated. I'm going to add plenty of error boundaries to this code once it's merged, before we release the next version, to assuage any concerns about brittle code.

Comment threadpackage.json Outdated
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@vercel

vercelBot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm to merge and iterate. Let's just fix up the merge conflicts and get this in - thanks so much for this and the multiple iterations. Very excited!

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Fixed the merge conflicts and pushed it up. Ready to merge once CI completes successfully! Thanks again for the reviews!

@VaguelySerious
VaguelySerious merged commit e3f0390 into vercel:mainDec 27, 2025
58 of 88 checks passed
Sign up for freeto 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.

3 participants

@karthikscale3@pranaygp@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Workflows graph extractor - #455

Merged
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor
Dec 27, 2025
Merged

Workflows graph extractor#455
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor

Conversation

@karthikscale3

@karthikscale3karthikscale3 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

This PR adds a new control flow graph extractor that analyzes bundled workflow files and generates graph manifests for workflow visualization.

Note: The corresponding UI updates for graph viewer are in #456

Changes

  • @workflow/builders: Add workflows-extractor.ts that parses workflow bundles using SWC to extract nodes and edges representing step calls, loops, conditionals, and parallel execution patterns
  • @workflow/builders: Add createWorkflowsManifest() method to BaseBuilder for generating workflow graph manifests post-bundle
  • @workflow/next: Integrate manifest generation into Next.js builder (initial build and watch mode rebuilds)

Output

Generates a workflows.json manifest containing React Flow-compatible graph data for each workflow, including:

  • Step nodes with metadata (loop context, conditional branches, parallel groups)
  • Edges representing control flow between steps
  • Support for transitive step resolution through helper functions

@changeset-bot

changeset-botBot commented Nov 28, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1e5807

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@workflow/world-postgresPatch
@workflow/world-localPatch
@workflow/sveltekitPatch
@workflow/buildersPatch
@workflow/nitroPatch
@workflow/utilsPatch
@workflow/worldPatch
@workflow/corePatch
@workflow/nextPatch
@workflow/webPatch
@workflow/cliPatch
workflowPatch
@workflow/astroPatch
@workflow/nuxtPatch
@workflow/errorsPatch
@workflow/web-sharedPatch
@workflow/world-testingPatch
@workflow/world-vercelPatch
@workflow/aiPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment threadworkbench/example/workflows/99_e2e.ts Outdated
Comment threadpackages/builders/src/standalone.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment thread.changeset/smart-insects-smile.md Outdated
Comment threadpackages/builders/src/base-builder.ts Outdated

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a bunch of comments we need to address. Very excited about this!

Let's try and just get things aligned with how we want to do manifests according to the versioning spec. I'll be a nuisance to try and clean this up later

@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp thanks for the review! Great and valid points! Let me do a bit of thinking to address these.

Comment threadpackages/builders/src/workflows-extractor.ts
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp Please take a look at the new iteration when you get a chance. Summary of the changes:

  1. Unified the partial manifest.debug.json files that gets generated inside .well-known/workflow/v1/flow and .well-known/workflow/v1/step directories as a single manifest.json.
  2. This new manifest.json file gets generated inside the .well-known/workflow/v1 directory for each builder.
  3. This manifest.json file is the single source of truth for all workflow metadata including the graph structure needed to build the Control Flow Graphs for the workflows and steps.
  4. See below the schema extension that allows this new structure. (A graph field is added to the workflows):
...
"workflows": {
"example/workflows/97_bench.ts": {
"noStepsWorkflow": {
"workflowId": "workflow//example/workflows/97_bench.ts//noStepsWorkflow",
"graph": {
"nodes": [
{
"id": "start",
"type": "workflowStart",
"data": {
"label": "Start: noStepsWorkflow",
"nodeKind": "workflow_start"
}
},
{
"id": "end",
"type": "workflowEnd",
"data": {
"label": "Return",
"nodeKind": "workflow_end"
}
}
],
"edges": [
{
"id": "e_start_end",
"source": "start",
"target": "end",
"type": "default"
}
]
}
},
...
image

I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8a3f152
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 252a0dd
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: b002d81
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8e21d56
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 1c45af6
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 68b23e0
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: e5f4cd8
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: d537846
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 0f62431
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Comment threadpackages/web/src/lib/flow-graph/manifest-adapter.ts Outdated
Comment threadpackages/web/src/components/run-detail-view.tsx Outdated
Comment threadpackages/world-testing/src/server.mts Outdated
Comment threadpackages/web/src/app/page.tsx Outdated
Comment threadpackages/web/src/components/settings-sidebar.tsx
@karthikscale3

karthikscale3 commented Dec 19, 2025

Copy link
Copy Markdown
ContributorAuthor

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Thanks for a comprehensive review. And the duplicate code between workflow-graph-viewer and workflow-graph-execution-viewer should be addressed with my next set of changes which I am iterating on based on some of the other feedback provided by @pranaygp. I am hoping to push my updates to this PR later today which should address your remaining comments as well.

@karthikscale3

karthikscale3 commented Dec 22, 2025

Copy link
Copy Markdown
ContributorAuthor

@pranaygp / @VaguelySerious - Thanks again for the comprehensive reviews. I have iterated further:

  • Made sure this feature is disabled for non local backend.
  • Addressed all the comments left by @VaguelySerious.
  • For representing conditionals, I have introduced a new node to show the actual condition from which the true and false edges branch out.
  • Made the node colors consistent and cleaned up the legends and made them more clear.
  • @pranaygp - For promise.all, promise.any, and promise.race, I have introduced an overlay container that holds the promises. I have kept the edges leaving each node within the container instead of having a single incoming and outgoing edge going in and out of the overlay container. While this might be cleaner, it won't accurately represent promise.race. In race scenarios, we would ideally want to see exactly which step won the race. Let me know what you think.
  • Loops are represented with a looping edge that is attached to the node on the left side.

Known limitation:

  • child workflows that are triggered within a step are not shown in the graph. I have left this for now as this requires a recursive extraction and I am not 100% sure of the best way to represent this in the graph.
imageimageimage

@karthikscale3karthikscale3 changed the title Workflows CFG ExtractorWorkflows graph extractorDec 22, 2025

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from an o11y and general maintenance perspective, will let @pranaygp voice any concerns about graph extraction, though my take is merge and ITG from here, since it's local-only, oss-ui-only, and isolated. I'm going to add plenty of error boundaries to this code once it's merged, before we release the next version, to assuage any concerns about brittle code.

Comment threadpackage.json Outdated
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@vercel

vercelBot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm to merge and iterate. Let's just fix up the merge conflicts and get this in - thanks so much for this and the multiple iterations. Very excited!

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Fixed the merge conflicts and pushed it up. Ready to merge once CI completes successfully! Thanks again for the reviews!

@VaguelySerious
VaguelySerious merged commit e3f0390 into vercel:mainDec 27, 2025
58 of 88 checks passed
Sign up for freeto 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.

3 participants

@karthikscale3@pranaygp@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Workflows graph extractor - #455

Merged
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor
Dec 27, 2025
Merged

Workflows graph extractor#455
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor

Conversation

@karthikscale3

@karthikscale3karthikscale3 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

This PR adds a new control flow graph extractor that analyzes bundled workflow files and generates graph manifests for workflow visualization.

Note: The corresponding UI updates for graph viewer are in #456

Changes

  • @workflow/builders: Add workflows-extractor.ts that parses workflow bundles using SWC to extract nodes and edges representing step calls, loops, conditionals, and parallel execution patterns
  • @workflow/builders: Add createWorkflowsManifest() method to BaseBuilder for generating workflow graph manifests post-bundle
  • @workflow/next: Integrate manifest generation into Next.js builder (initial build and watch mode rebuilds)

Output

Generates a workflows.json manifest containing React Flow-compatible graph data for each workflow, including:

  • Step nodes with metadata (loop context, conditional branches, parallel groups)
  • Edges representing control flow between steps
  • Support for transitive step resolution through helper functions

@changeset-bot

changeset-botBot commented Nov 28, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1e5807

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@workflow/world-postgresPatch
@workflow/world-localPatch
@workflow/sveltekitPatch
@workflow/buildersPatch
@workflow/nitroPatch
@workflow/utilsPatch
@workflow/worldPatch
@workflow/corePatch
@workflow/nextPatch
@workflow/webPatch
@workflow/cliPatch
workflowPatch
@workflow/astroPatch
@workflow/nuxtPatch
@workflow/errorsPatch
@workflow/web-sharedPatch
@workflow/world-testingPatch
@workflow/world-vercelPatch
@workflow/aiPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment threadworkbench/example/workflows/99_e2e.ts Outdated
Comment threadpackages/builders/src/standalone.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment thread.changeset/smart-insects-smile.md Outdated
Comment threadpackages/builders/src/base-builder.ts Outdated

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a bunch of comments we need to address. Very excited about this!

Let's try and just get things aligned with how we want to do manifests according to the versioning spec. I'll be a nuisance to try and clean this up later

@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp thanks for the review! Great and valid points! Let me do a bit of thinking to address these.

Comment threadpackages/builders/src/workflows-extractor.ts
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp Please take a look at the new iteration when you get a chance. Summary of the changes:

  1. Unified the partial manifest.debug.json files that gets generated inside .well-known/workflow/v1/flow and .well-known/workflow/v1/step directories as a single manifest.json.
  2. This new manifest.json file gets generated inside the .well-known/workflow/v1 directory for each builder.
  3. This manifest.json file is the single source of truth for all workflow metadata including the graph structure needed to build the Control Flow Graphs for the workflows and steps.
  4. See below the schema extension that allows this new structure. (A graph field is added to the workflows):
...
"workflows": {
"example/workflows/97_bench.ts": {
"noStepsWorkflow": {
"workflowId": "workflow//example/workflows/97_bench.ts//noStepsWorkflow",
"graph": {
"nodes": [
{
"id": "start",
"type": "workflowStart",
"data": {
"label": "Start: noStepsWorkflow",
"nodeKind": "workflow_start"
}
},
{
"id": "end",
"type": "workflowEnd",
"data": {
"label": "Return",
"nodeKind": "workflow_end"
}
}
],
"edges": [
{
"id": "e_start_end",
"source": "start",
"target": "end",
"type": "default"
}
]
}
},
...
image

I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8a3f152
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 252a0dd
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: b002d81
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8e21d56
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 1c45af6
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 68b23e0
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: e5f4cd8
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: d537846
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 0f62431
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Comment threadpackages/web/src/lib/flow-graph/manifest-adapter.ts Outdated
Comment threadpackages/web/src/components/run-detail-view.tsx Outdated
Comment threadpackages/world-testing/src/server.mts Outdated
Comment threadpackages/web/src/app/page.tsx Outdated
Comment threadpackages/web/src/components/settings-sidebar.tsx
@karthikscale3

karthikscale3 commented Dec 19, 2025

Copy link
Copy Markdown
ContributorAuthor

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Thanks for a comprehensive review. And the duplicate code between workflow-graph-viewer and workflow-graph-execution-viewer should be addressed with my next set of changes which I am iterating on based on some of the other feedback provided by @pranaygp. I am hoping to push my updates to this PR later today which should address your remaining comments as well.

@karthikscale3

karthikscale3 commented Dec 22, 2025

Copy link
Copy Markdown
ContributorAuthor

@pranaygp / @VaguelySerious - Thanks again for the comprehensive reviews. I have iterated further:

  • Made sure this feature is disabled for non local backend.
  • Addressed all the comments left by @VaguelySerious.
  • For representing conditionals, I have introduced a new node to show the actual condition from which the true and false edges branch out.
  • Made the node colors consistent and cleaned up the legends and made them more clear.
  • @pranaygp - For promise.all, promise.any, and promise.race, I have introduced an overlay container that holds the promises. I have kept the edges leaving each node within the container instead of having a single incoming and outgoing edge going in and out of the overlay container. While this might be cleaner, it won't accurately represent promise.race. In race scenarios, we would ideally want to see exactly which step won the race. Let me know what you think.
  • Loops are represented with a looping edge that is attached to the node on the left side.

Known limitation:

  • child workflows that are triggered within a step are not shown in the graph. I have left this for now as this requires a recursive extraction and I am not 100% sure of the best way to represent this in the graph.
imageimageimage

@karthikscale3karthikscale3 changed the title Workflows CFG ExtractorWorkflows graph extractorDec 22, 2025

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from an o11y and general maintenance perspective, will let @pranaygp voice any concerns about graph extraction, though my take is merge and ITG from here, since it's local-only, oss-ui-only, and isolated. I'm going to add plenty of error boundaries to this code once it's merged, before we release the next version, to assuage any concerns about brittle code.

Comment threadpackage.json Outdated
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@vercel

vercelBot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm to merge and iterate. Let's just fix up the merge conflicts and get this in - thanks so much for this and the multiple iterations. Very excited!

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Fixed the merge conflicts and pushed it up. Ready to merge once CI completes successfully! Thanks again for the reviews!

@VaguelySerious
VaguelySerious merged commit e3f0390 into vercel:mainDec 27, 2025
58 of 88 checks passed
Sign up for freeto 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.

3 participants

@karthikscale3@pranaygp@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Workflows graph extractor - #455

Merged
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor
Dec 27, 2025
Merged

Workflows graph extractor#455
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor

Conversation

@karthikscale3

@karthikscale3karthikscale3 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

This PR adds a new control flow graph extractor that analyzes bundled workflow files and generates graph manifests for workflow visualization.

Note: The corresponding UI updates for graph viewer are in #456

Changes

  • @workflow/builders: Add workflows-extractor.ts that parses workflow bundles using SWC to extract nodes and edges representing step calls, loops, conditionals, and parallel execution patterns
  • @workflow/builders: Add createWorkflowsManifest() method to BaseBuilder for generating workflow graph manifests post-bundle
  • @workflow/next: Integrate manifest generation into Next.js builder (initial build and watch mode rebuilds)

Output

Generates a workflows.json manifest containing React Flow-compatible graph data for each workflow, including:

  • Step nodes with metadata (loop context, conditional branches, parallel groups)
  • Edges representing control flow between steps
  • Support for transitive step resolution through helper functions

@changeset-bot

changeset-botBot commented Nov 28, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1e5807

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@workflow/world-postgresPatch
@workflow/world-localPatch
@workflow/sveltekitPatch
@workflow/buildersPatch
@workflow/nitroPatch
@workflow/utilsPatch
@workflow/worldPatch
@workflow/corePatch
@workflow/nextPatch
@workflow/webPatch
@workflow/cliPatch
workflowPatch
@workflow/astroPatch
@workflow/nuxtPatch
@workflow/errorsPatch
@workflow/web-sharedPatch
@workflow/world-testingPatch
@workflow/world-vercelPatch
@workflow/aiPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment threadworkbench/example/workflows/99_e2e.ts Outdated
Comment threadpackages/builders/src/standalone.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment thread.changeset/smart-insects-smile.md Outdated
Comment threadpackages/builders/src/base-builder.ts Outdated

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a bunch of comments we need to address. Very excited about this!

Let's try and just get things aligned with how we want to do manifests according to the versioning spec. I'll be a nuisance to try and clean this up later

@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp thanks for the review! Great and valid points! Let me do a bit of thinking to address these.

Comment threadpackages/builders/src/workflows-extractor.ts
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp Please take a look at the new iteration when you get a chance. Summary of the changes:

  1. Unified the partial manifest.debug.json files that gets generated inside .well-known/workflow/v1/flow and .well-known/workflow/v1/step directories as a single manifest.json.
  2. This new manifest.json file gets generated inside the .well-known/workflow/v1 directory for each builder.
  3. This manifest.json file is the single source of truth for all workflow metadata including the graph structure needed to build the Control Flow Graphs for the workflows and steps.
  4. See below the schema extension that allows this new structure. (A graph field is added to the workflows):
...
"workflows": {
"example/workflows/97_bench.ts": {
"noStepsWorkflow": {
"workflowId": "workflow//example/workflows/97_bench.ts//noStepsWorkflow",
"graph": {
"nodes": [
{
"id": "start",
"type": "workflowStart",
"data": {
"label": "Start: noStepsWorkflow",
"nodeKind": "workflow_start"
}
},
{
"id": "end",
"type": "workflowEnd",
"data": {
"label": "Return",
"nodeKind": "workflow_end"
}
}
],
"edges": [
{
"id": "e_start_end",
"source": "start",
"target": "end",
"type": "default"
}
]
}
},
...
image

I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8a3f152
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 252a0dd
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: b002d81
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8e21d56
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 1c45af6
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 68b23e0
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: e5f4cd8
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: d537846
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 0f62431
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Comment threadpackages/web/src/lib/flow-graph/manifest-adapter.ts Outdated
Comment threadpackages/web/src/components/run-detail-view.tsx Outdated
Comment threadpackages/world-testing/src/server.mts Outdated
Comment threadpackages/web/src/app/page.tsx Outdated
Comment threadpackages/web/src/components/settings-sidebar.tsx
@karthikscale3

karthikscale3 commented Dec 19, 2025

Copy link
Copy Markdown
ContributorAuthor

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Thanks for a comprehensive review. And the duplicate code between workflow-graph-viewer and workflow-graph-execution-viewer should be addressed with my next set of changes which I am iterating on based on some of the other feedback provided by @pranaygp. I am hoping to push my updates to this PR later today which should address your remaining comments as well.

@karthikscale3

karthikscale3 commented Dec 22, 2025

Copy link
Copy Markdown
ContributorAuthor

@pranaygp / @VaguelySerious - Thanks again for the comprehensive reviews. I have iterated further:

  • Made sure this feature is disabled for non local backend.
  • Addressed all the comments left by @VaguelySerious.
  • For representing conditionals, I have introduced a new node to show the actual condition from which the true and false edges branch out.
  • Made the node colors consistent and cleaned up the legends and made them more clear.
  • @pranaygp - For promise.all, promise.any, and promise.race, I have introduced an overlay container that holds the promises. I have kept the edges leaving each node within the container instead of having a single incoming and outgoing edge going in and out of the overlay container. While this might be cleaner, it won't accurately represent promise.race. In race scenarios, we would ideally want to see exactly which step won the race. Let me know what you think.
  • Loops are represented with a looping edge that is attached to the node on the left side.

Known limitation:

  • child workflows that are triggered within a step are not shown in the graph. I have left this for now as this requires a recursive extraction and I am not 100% sure of the best way to represent this in the graph.
imageimageimage

@karthikscale3karthikscale3 changed the title Workflows CFG ExtractorWorkflows graph extractorDec 22, 2025

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from an o11y and general maintenance perspective, will let @pranaygp voice any concerns about graph extraction, though my take is merge and ITG from here, since it's local-only, oss-ui-only, and isolated. I'm going to add plenty of error boundaries to this code once it's merged, before we release the next version, to assuage any concerns about brittle code.

Comment threadpackage.json Outdated
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@vercel

vercelBot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm to merge and iterate. Let's just fix up the merge conflicts and get this in - thanks so much for this and the multiple iterations. Very excited!

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Fixed the merge conflicts and pushed it up. Ready to merge once CI completes successfully! Thanks again for the reviews!

@VaguelySerious
VaguelySerious merged commit e3f0390 into vercel:mainDec 27, 2025
58 of 88 checks passed
Sign up for freeto 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.

3 participants

@karthikscale3@pranaygp@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Workflows graph extractor - #455

Merged
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor
Dec 27, 2025
Merged

Workflows graph extractor#455
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor

Conversation

@karthikscale3

@karthikscale3karthikscale3 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

This PR adds a new control flow graph extractor that analyzes bundled workflow files and generates graph manifests for workflow visualization.

Note: The corresponding UI updates for graph viewer are in #456

Changes

  • @workflow/builders: Add workflows-extractor.ts that parses workflow bundles using SWC to extract nodes and edges representing step calls, loops, conditionals, and parallel execution patterns
  • @workflow/builders: Add createWorkflowsManifest() method to BaseBuilder for generating workflow graph manifests post-bundle
  • @workflow/next: Integrate manifest generation into Next.js builder (initial build and watch mode rebuilds)

Output

Generates a workflows.json manifest containing React Flow-compatible graph data for each workflow, including:

  • Step nodes with metadata (loop context, conditional branches, parallel groups)
  • Edges representing control flow between steps
  • Support for transitive step resolution through helper functions

@changeset-bot

changeset-botBot commented Nov 28, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1e5807

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@workflow/world-postgresPatch
@workflow/world-localPatch
@workflow/sveltekitPatch
@workflow/buildersPatch
@workflow/nitroPatch
@workflow/utilsPatch
@workflow/worldPatch
@workflow/corePatch
@workflow/nextPatch
@workflow/webPatch
@workflow/cliPatch
workflowPatch
@workflow/astroPatch
@workflow/nuxtPatch
@workflow/errorsPatch
@workflow/web-sharedPatch
@workflow/world-testingPatch
@workflow/world-vercelPatch
@workflow/aiPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment threadworkbench/example/workflows/99_e2e.ts Outdated
Comment threadpackages/builders/src/standalone.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment thread.changeset/smart-insects-smile.md Outdated
Comment threadpackages/builders/src/base-builder.ts Outdated

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a bunch of comments we need to address. Very excited about this!

Let's try and just get things aligned with how we want to do manifests according to the versioning spec. I'll be a nuisance to try and clean this up later

@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp thanks for the review! Great and valid points! Let me do a bit of thinking to address these.

Comment threadpackages/builders/src/workflows-extractor.ts
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp Please take a look at the new iteration when you get a chance. Summary of the changes:

  1. Unified the partial manifest.debug.json files that gets generated inside .well-known/workflow/v1/flow and .well-known/workflow/v1/step directories as a single manifest.json.
  2. This new manifest.json file gets generated inside the .well-known/workflow/v1 directory for each builder.
  3. This manifest.json file is the single source of truth for all workflow metadata including the graph structure needed to build the Control Flow Graphs for the workflows and steps.
  4. See below the schema extension that allows this new structure. (A graph field is added to the workflows):
...
"workflows": {
"example/workflows/97_bench.ts": {
"noStepsWorkflow": {
"workflowId": "workflow//example/workflows/97_bench.ts//noStepsWorkflow",
"graph": {
"nodes": [
{
"id": "start",
"type": "workflowStart",
"data": {
"label": "Start: noStepsWorkflow",
"nodeKind": "workflow_start"
}
},
{
"id": "end",
"type": "workflowEnd",
"data": {
"label": "Return",
"nodeKind": "workflow_end"
}
}
],
"edges": [
{
"id": "e_start_end",
"source": "start",
"target": "end",
"type": "default"
}
]
}
},
...
image

I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8a3f152
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 252a0dd
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: b002d81
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8e21d56
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 1c45af6
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 68b23e0
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: e5f4cd8
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: d537846
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 0f62431
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Comment threadpackages/web/src/lib/flow-graph/manifest-adapter.ts Outdated
Comment threadpackages/web/src/components/run-detail-view.tsx Outdated
Comment threadpackages/world-testing/src/server.mts Outdated
Comment threadpackages/web/src/app/page.tsx Outdated
Comment threadpackages/web/src/components/settings-sidebar.tsx
@karthikscale3

karthikscale3 commented Dec 19, 2025

Copy link
Copy Markdown
ContributorAuthor

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Thanks for a comprehensive review. And the duplicate code between workflow-graph-viewer and workflow-graph-execution-viewer should be addressed with my next set of changes which I am iterating on based on some of the other feedback provided by @pranaygp. I am hoping to push my updates to this PR later today which should address your remaining comments as well.

@karthikscale3

karthikscale3 commented Dec 22, 2025

Copy link
Copy Markdown
ContributorAuthor

@pranaygp / @VaguelySerious - Thanks again for the comprehensive reviews. I have iterated further:

  • Made sure this feature is disabled for non local backend.
  • Addressed all the comments left by @VaguelySerious.
  • For representing conditionals, I have introduced a new node to show the actual condition from which the true and false edges branch out.
  • Made the node colors consistent and cleaned up the legends and made them more clear.
  • @pranaygp - For promise.all, promise.any, and promise.race, I have introduced an overlay container that holds the promises. I have kept the edges leaving each node within the container instead of having a single incoming and outgoing edge going in and out of the overlay container. While this might be cleaner, it won't accurately represent promise.race. In race scenarios, we would ideally want to see exactly which step won the race. Let me know what you think.
  • Loops are represented with a looping edge that is attached to the node on the left side.

Known limitation:

  • child workflows that are triggered within a step are not shown in the graph. I have left this for now as this requires a recursive extraction and I am not 100% sure of the best way to represent this in the graph.
imageimageimage

@karthikscale3karthikscale3 changed the title Workflows CFG ExtractorWorkflows graph extractorDec 22, 2025

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from an o11y and general maintenance perspective, will let @pranaygp voice any concerns about graph extraction, though my take is merge and ITG from here, since it's local-only, oss-ui-only, and isolated. I'm going to add plenty of error boundaries to this code once it's merged, before we release the next version, to assuage any concerns about brittle code.

Comment threadpackage.json Outdated
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@vercel

vercelBot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm to merge and iterate. Let's just fix up the merge conflicts and get this in - thanks so much for this and the multiple iterations. Very excited!

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Fixed the merge conflicts and pushed it up. Ready to merge once CI completes successfully! Thanks again for the reviews!

@VaguelySerious
VaguelySerious merged commit e3f0390 into vercel:mainDec 27, 2025
58 of 88 checks passed
Sign up for freeto 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.

3 participants

@karthikscale3@pranaygp@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Workflows graph extractor - #455

Merged
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor
Dec 27, 2025
Merged

Workflows graph extractor#455
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor

Conversation

@karthikscale3

@karthikscale3karthikscale3 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

This PR adds a new control flow graph extractor that analyzes bundled workflow files and generates graph manifests for workflow visualization.

Note: The corresponding UI updates for graph viewer are in #456

Changes

  • @workflow/builders: Add workflows-extractor.ts that parses workflow bundles using SWC to extract nodes and edges representing step calls, loops, conditionals, and parallel execution patterns
  • @workflow/builders: Add createWorkflowsManifest() method to BaseBuilder for generating workflow graph manifests post-bundle
  • @workflow/next: Integrate manifest generation into Next.js builder (initial build and watch mode rebuilds)

Output

Generates a workflows.json manifest containing React Flow-compatible graph data for each workflow, including:

  • Step nodes with metadata (loop context, conditional branches, parallel groups)
  • Edges representing control flow between steps
  • Support for transitive step resolution through helper functions

@changeset-bot

changeset-botBot commented Nov 28, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1e5807

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@workflow/world-postgresPatch
@workflow/world-localPatch
@workflow/sveltekitPatch
@workflow/buildersPatch
@workflow/nitroPatch
@workflow/utilsPatch
@workflow/worldPatch
@workflow/corePatch
@workflow/nextPatch
@workflow/webPatch
@workflow/cliPatch
workflowPatch
@workflow/astroPatch
@workflow/nuxtPatch
@workflow/errorsPatch
@workflow/web-sharedPatch
@workflow/world-testingPatch
@workflow/world-vercelPatch
@workflow/aiPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment threadworkbench/example/workflows/99_e2e.ts Outdated
Comment threadpackages/builders/src/standalone.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment thread.changeset/smart-insects-smile.md Outdated
Comment threadpackages/builders/src/base-builder.ts Outdated

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a bunch of comments we need to address. Very excited about this!

Let's try and just get things aligned with how we want to do manifests according to the versioning spec. I'll be a nuisance to try and clean this up later

@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp thanks for the review! Great and valid points! Let me do a bit of thinking to address these.

Comment threadpackages/builders/src/workflows-extractor.ts
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp Please take a look at the new iteration when you get a chance. Summary of the changes:

  1. Unified the partial manifest.debug.json files that gets generated inside .well-known/workflow/v1/flow and .well-known/workflow/v1/step directories as a single manifest.json.
  2. This new manifest.json file gets generated inside the .well-known/workflow/v1 directory for each builder.
  3. This manifest.json file is the single source of truth for all workflow metadata including the graph structure needed to build the Control Flow Graphs for the workflows and steps.
  4. See below the schema extension that allows this new structure. (A graph field is added to the workflows):
...
"workflows": {
"example/workflows/97_bench.ts": {
"noStepsWorkflow": {
"workflowId": "workflow//example/workflows/97_bench.ts//noStepsWorkflow",
"graph": {
"nodes": [
{
"id": "start",
"type": "workflowStart",
"data": {
"label": "Start: noStepsWorkflow",
"nodeKind": "workflow_start"
}
},
{
"id": "end",
"type": "workflowEnd",
"data": {
"label": "Return",
"nodeKind": "workflow_end"
}
}
],
"edges": [
{
"id": "e_start_end",
"source": "start",
"target": "end",
"type": "default"
}
]
}
},
...
image

I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8a3f152
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 252a0dd
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: b002d81
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8e21d56
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 1c45af6
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 68b23e0
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: e5f4cd8
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: d537846
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 0f62431
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Comment threadpackages/web/src/lib/flow-graph/manifest-adapter.ts Outdated
Comment threadpackages/web/src/components/run-detail-view.tsx Outdated
Comment threadpackages/world-testing/src/server.mts Outdated
Comment threadpackages/web/src/app/page.tsx Outdated
Comment threadpackages/web/src/components/settings-sidebar.tsx
@karthikscale3

karthikscale3 commented Dec 19, 2025

Copy link
Copy Markdown
ContributorAuthor

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Thanks for a comprehensive review. And the duplicate code between workflow-graph-viewer and workflow-graph-execution-viewer should be addressed with my next set of changes which I am iterating on based on some of the other feedback provided by @pranaygp. I am hoping to push my updates to this PR later today which should address your remaining comments as well.

@karthikscale3

karthikscale3 commented Dec 22, 2025

Copy link
Copy Markdown
ContributorAuthor

@pranaygp / @VaguelySerious - Thanks again for the comprehensive reviews. I have iterated further:

  • Made sure this feature is disabled for non local backend.
  • Addressed all the comments left by @VaguelySerious.
  • For representing conditionals, I have introduced a new node to show the actual condition from which the true and false edges branch out.
  • Made the node colors consistent and cleaned up the legends and made them more clear.
  • @pranaygp - For promise.all, promise.any, and promise.race, I have introduced an overlay container that holds the promises. I have kept the edges leaving each node within the container instead of having a single incoming and outgoing edge going in and out of the overlay container. While this might be cleaner, it won't accurately represent promise.race. In race scenarios, we would ideally want to see exactly which step won the race. Let me know what you think.
  • Loops are represented with a looping edge that is attached to the node on the left side.

Known limitation:

  • child workflows that are triggered within a step are not shown in the graph. I have left this for now as this requires a recursive extraction and I am not 100% sure of the best way to represent this in the graph.
imageimageimage

@karthikscale3karthikscale3 changed the title Workflows CFG ExtractorWorkflows graph extractorDec 22, 2025

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from an o11y and general maintenance perspective, will let @pranaygp voice any concerns about graph extraction, though my take is merge and ITG from here, since it's local-only, oss-ui-only, and isolated. I'm going to add plenty of error boundaries to this code once it's merged, before we release the next version, to assuage any concerns about brittle code.

Comment threadpackage.json Outdated
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@vercel

vercelBot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm to merge and iterate. Let's just fix up the merge conflicts and get this in - thanks so much for this and the multiple iterations. Very excited!

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Fixed the merge conflicts and pushed it up. Ready to merge once CI completes successfully! Thanks again for the reviews!

@VaguelySerious
VaguelySerious merged commit e3f0390 into vercel:mainDec 27, 2025
58 of 88 checks passed
Sign up for freeto 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.

3 participants

@karthikscale3@pranaygp@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Workflows graph extractor - #455

Merged
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor
Dec 27, 2025
Merged

Workflows graph extractor#455
VaguelySerious merged 43 commits into
vercel:mainfrom
karthikscale3:karthik/workflow-cfg-extractor

Conversation

@karthikscale3

@karthikscale3karthikscale3 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

This PR adds a new control flow graph extractor that analyzes bundled workflow files and generates graph manifests for workflow visualization.

Note: The corresponding UI updates for graph viewer are in #456

Changes

  • @workflow/builders: Add workflows-extractor.ts that parses workflow bundles using SWC to extract nodes and edges representing step calls, loops, conditionals, and parallel execution patterns
  • @workflow/builders: Add createWorkflowsManifest() method to BaseBuilder for generating workflow graph manifests post-bundle
  • @workflow/next: Integrate manifest generation into Next.js builder (initial build and watch mode rebuilds)

Output

Generates a workflows.json manifest containing React Flow-compatible graph data for each workflow, including:

  • Step nodes with metadata (loop context, conditional branches, parallel groups)
  • Edges representing control flow between steps
  • Support for transitive step resolution through helper functions

@changeset-bot

changeset-botBot commented Nov 28, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1e5807

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@workflow/world-postgresPatch
@workflow/world-localPatch
@workflow/sveltekitPatch
@workflow/buildersPatch
@workflow/nitroPatch
@workflow/utilsPatch
@workflow/worldPatch
@workflow/corePatch
@workflow/nextPatch
@workflow/webPatch
@workflow/cliPatch
workflowPatch
@workflow/astroPatch
@workflow/nuxtPatch
@workflow/errorsPatch
@workflow/web-sharedPatch
@workflow/world-testingPatch
@workflow/world-vercelPatch
@workflow/aiPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment threadworkbench/example/workflows/99_e2e.ts Outdated
Comment threadpackages/builders/src/standalone.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment threadpackages/next/src/builder.ts Outdated
Comment thread.changeset/smart-insects-smile.md Outdated
Comment threadpackages/builders/src/base-builder.ts Outdated

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a bunch of comments we need to address. Very excited about this!

Let's try and just get things aligned with how we want to do manifests according to the versioning spec. I'll be a nuisance to try and clean this up later

@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp thanks for the review! Great and valid points! Let me do a bit of thinking to address these.

Comment threadpackages/builders/src/workflows-extractor.ts
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

@pranaygp Please take a look at the new iteration when you get a chance. Summary of the changes:

  1. Unified the partial manifest.debug.json files that gets generated inside .well-known/workflow/v1/flow and .well-known/workflow/v1/step directories as a single manifest.json.
  2. This new manifest.json file gets generated inside the .well-known/workflow/v1 directory for each builder.
  3. This manifest.json file is the single source of truth for all workflow metadata including the graph structure needed to build the Control Flow Graphs for the workflows and steps.
  4. See below the schema extension that allows this new structure. (A graph field is added to the workflows):
...
"workflows": {
"example/workflows/97_bench.ts": {
"noStepsWorkflow": {
"workflowId": "workflow//example/workflows/97_bench.ts//noStepsWorkflow",
"graph": {
"nodes": [
{
"id": "start",
"type": "workflowStart",
"data": {
"label": "Start: noStepsWorkflow",
"nodeKind": "workflow_start"
}
},
{
"id": "end",
"type": "workflowEnd",
"data": {
"label": "Return",
"nodeKind": "workflow_end"
}
}
],
"edges": [
{
"id": "e_start_end",
"source": "start",
"target": "end",
"type": "default"
}
]
}
},
...
image

I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8a3f152
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 252a0dd
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: b002d81
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 8e21d56
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 1c45af6
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 68b23e0
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: e5f4cd8
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: d537846
I, Karthik Kalyanaraman <karthik@scale3labs.com>, hereby add my Signed-off-by to this commit: 0f62431
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.
Single-statement if/while/for/for-of bodies without braces were ignored.
Added recursive analysis for non-block bodies and corresponding tests.

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Comment threadpackages/web/src/lib/flow-graph/manifest-adapter.ts Outdated
Comment threadpackages/web/src/components/run-detail-view.tsx Outdated
Comment threadpackages/world-testing/src/server.mts Outdated
Comment threadpackages/web/src/app/page.tsx Outdated
Comment threadpackages/web/src/components/settings-sidebar.tsx
@karthikscale3

karthikscale3 commented Dec 19, 2025

Copy link
Copy Markdown
ContributorAuthor

Overall LGTM and super excited for this!

The only major comment is that we should be disabling this feature for non-local environments until we ship a way to reliably fetch manifests via the world interface. Once that's done, I think we're good to merge.

A minor comment is that workflow-graph-viewer and workflow-graph-execution-viewer seem to duplicate a ton of code and might be hard to iterate on since we don't have a view that shows both side-by-side. Not something you need to do in this PR, but maybe something to think about, e.g. if debug=1 (we already use this search param), the run-detail-view may show both graph viewers side by side, allowing for quick style iteration, and also gives some confidence if we e.g. ask AI to DRY up the graph code a bit.

I also have a ton of tiny nits that I would love to see addressed but aren't blocking merge.

Thanks for a comprehensive review. And the duplicate code between workflow-graph-viewer and workflow-graph-execution-viewer should be addressed with my next set of changes which I am iterating on based on some of the other feedback provided by @pranaygp. I am hoping to push my updates to this PR later today which should address your remaining comments as well.

@karthikscale3

karthikscale3 commented Dec 22, 2025

Copy link
Copy Markdown
ContributorAuthor

@pranaygp / @VaguelySerious - Thanks again for the comprehensive reviews. I have iterated further:

  • Made sure this feature is disabled for non local backend.
  • Addressed all the comments left by @VaguelySerious.
  • For representing conditionals, I have introduced a new node to show the actual condition from which the true and false edges branch out.
  • Made the node colors consistent and cleaned up the legends and made them more clear.
  • @pranaygp - For promise.all, promise.any, and promise.race, I have introduced an overlay container that holds the promises. I have kept the edges leaving each node within the container instead of having a single incoming and outgoing edge going in and out of the overlay container. While this might be cleaner, it won't accurately represent promise.race. In race scenarios, we would ideally want to see exactly which step won the race. Let me know what you think.
  • Loops are represented with a looping edge that is attached to the node on the left side.

Known limitation:

  • child workflows that are triggered within a step are not shown in the graph. I have left this for now as this requires a recursive extraction and I am not 100% sure of the best way to represent this in the graph.
imageimageimage

@karthikscale3karthikscale3 changed the title Workflows CFG ExtractorWorkflows graph extractorDec 22, 2025

@VaguelySeriousVaguelySerious left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from an o11y and general maintenance perspective, will let @pranaygp voice any concerns about graph extraction, though my take is merge and ITG from here, since it's local-only, oss-ui-only, and isolated. I'm going to add plenty of error boundaries to this code once it's merged, before we release the next version, to assuage any concerns about brittle code.

Comment threadpackage.json Outdated
Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@vercel

vercelBot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

@pranaygppranaygp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm to merge and iterate. Let's just fix up the merge conflicts and get this in - thanks so much for this and the multiple iterations. Very excited!

Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Fixed the merge conflicts and pushed it up. Ready to merge once CI completes successfully! Thanks again for the reviews!

@VaguelySerious
VaguelySerious merged commit e3f0390 into vercel:mainDec 27, 2025
58 of 88 checks passed
Sign up for freeto 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.

3 participants

@karthikscale3@pranaygp@VaguelySerious