Run each workflow stage as its own task, with fan-out and fan-in

This commit is contained in:
Ian Gulliver
2026-10-15 22:53:54 -07:00
parent f7a0ffcd4c
commit 2180a7e824
15 changed files with 739 additions and 408 deletions
+18 -5
View File
@@ -933,6 +933,8 @@ components:
forked_at: { type: integer, description: "With forked_from: the n of the snapshot it was forked at." }
merge_queued_at: { type: string, format: date-time, description: "When Merge was requested while another task in the project was merging; absent once the merge starts or when none is held." }
workflow: { type: string, description: "The name of the workflow the task froze at creation (getTaskWorkflow has its copy); absent for a task without one." }
workflow_run: { type: string, description: "With workflow: the id every task of one run of the workflow shares." }
workflow_stage: { type: string, description: "With workflow: the name of the stage this task runs." }
Todo:
type: object
@@ -982,7 +984,6 @@ components:
required: [title]
properties:
title: { type: string }
workflow: { type: string, description: "The name of a workflow for the task to freeze: it keeps a copy of the workflow's definition as it is now." }
WorkflowSummary:
type: object
@@ -994,8 +995,8 @@ components:
WorkflowDefinition:
type: object
description: >
A workflow's file, which holds everything but its name: a sequence of stages run in order. Sent and returned
as YAML.
A workflow's file, which holds everything but its name: its stages, each run as its own task once the stages
it comes after have finished. Sent and returned as YAML.
required: [stages]
properties:
description: { type: string, x-go-type-skip-optional-pointer: true }
@@ -1009,6 +1010,20 @@ components:
required: [name, model, prompt]
properties:
name: { type: string, description: "One line of 1 to 100 characters, unique within the workflow." }
after:
type: array
items: { type: string }
description: >
The stages whose outputs this stage gets, by name; it starts once all of them have finished. Absent means
the previous stage in the list (for the first stage, none); empty means it starts from the brief.
base:
type: string
enum: [parent, main]
x-enum-varnames: [StageBaseParent, StageBaseMain]
description: >
Where the stage's task branches from. parent (the default): the commit its one after stage finished at, or
for a stage with none, where the workflow was started from. main: the project's default branch. Refused on
a stage with more than one after stage, which always branches from the default branch.
model: { type: string, description: "The stage agent's model, which also picks its vendor: gpt-* models run on Codex, every other model on Claude Code." }
prompt: { type: string, description: "The stage agent's instructions." }
@@ -1149,8 +1164,6 @@ components:
created_at: { type: string, format: date-time }
forked_from: { type: string, description: "A fork's first start resumes this vendor session, cut at forked_at, under a new vendor_session_id; absent for other sessions." }
forked_at: { type: string, description: "With forked_from: the vendor's id of the last thing the fork keeps, a message for Claude Code, a turn for Codex." }
workflow_stage: { type: integer, description: "The stage (from 1) of the task's workflow this session runs; absent for a session outside a workflow." }
SessionCreate:
type: object
required: [prompt]