Add server-side workflows with YAML files, task freeze and lead tools

This commit is contained in:
Ian Gulliver
2026-10-15 21:17:58 -07:00
parent 2f02f5ac3c
commit 2ce10a6c65
19 changed files with 1293 additions and 199 deletions
+107
View File
@@ -236,6 +236,22 @@ paths:
schema: { $ref: "#/components/schemas/Task" }
"404": { $ref: "#/components/responses/Error" }
/api/tasks/{taskId}/workflow:
parameters:
- { name: taskId, in: path, required: true, schema: { type: string } }
get:
operationId: getTaskWorkflow
description: >
The workflow the task froze when it was created, as it was then. Later edits and deletes of the workflow
don't change it.
responses:
"200":
description: The frozen workflow.
content:
application/json:
schema: { $ref: "#/components/schemas/TaskWorkflow" }
"404": { $ref: "#/components/responses/Error" }
/api/tasks/{taskId}/unmerged:
parameters:
- { name: taskId, in: path, required: true, schema: { type: string } }
@@ -781,6 +797,54 @@ paths:
application/json:
schema: { $ref: "#/components/schemas/Status" }
/api/workflows:
get:
operationId: listWorkflows
responses:
"200":
description: Every workflow's name and description, by name.
content:
application/json:
schema:
type: array
items: { $ref: "#/components/schemas/WorkflowSummary" }
/api/workflows/{name}:
parameters:
- { name: name, in: path, required: true, schema: { type: string } }
get:
operationId: getWorkflow
responses:
"200":
description: "The workflow's file: its WorkflowDefinition as YAML, as an attachment named after it."
content:
application/yaml:
schema: { type: string }
"404": { $ref: "#/components/responses/Error" }
put:
operationId: putWorkflow
description: >
Creates or replaces the workflow from its file, a WorkflowDefinition as YAML (or JSON). The name is one line
of 1 to 100 characters. Tasks that already froze the workflow keep their copy.
requestBody:
required: true
content:
application/yaml:
schema: { type: string }
responses:
"200":
description: The stored workflow.
content:
application/json:
schema: { $ref: "#/components/schemas/WorkflowSummary" }
"400": { $ref: "#/components/responses/Error" }
delete:
operationId: deleteWorkflow
responses:
"204":
description: Deleted. Tasks that froze it keep their copy.
"404": { $ref: "#/components/responses/Error" }
components:
responses:
Error:
@@ -868,6 +932,7 @@ components:
forked_from: { type: string, description: "The task this one was forked from; absent for other tasks." }
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." }
Todo:
type: object
@@ -917,6 +982,48 @@ 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
required: [name, description]
properties:
name: { type: string }
description: { type: string }
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.
required: [stages]
properties:
description: { type: string, x-go-type-skip-optional-pointer: true }
stages:
type: array
minItems: 1
items: { $ref: "#/components/schemas/Stage" }
Stage:
type: object
required: [name, vendor, model, prompt]
properties:
name: { type: string, description: "One line of 1 to 100 characters, unique within the workflow." }
vendor:
type: string
enum: [claude, codex]
x-enum-varnames: [StageVendorClaude, StageVendorCodex]
description: Must be the vendor that runs model (gpt-* models run on Codex, every other model on Claude Code).
model: { type: string }
prompt: { type: string, description: "The stage agent's instructions." }
TaskWorkflow:
type: object
description: The workflow a task froze when it was created, as it was then.
required: [name, definition]
properties:
name: { type: string }
definition: { type: string, description: The WorkflowDefinition as YAML. }
TaskChanges:
type: object