You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Feat] Web UI: author, run-with-inputs, approve, and monitor a saved workflow
Overview
Today the Workflows tab is read-only. WorkflowsPanel.tsx and web/src/api.ts call GET /workflows/runs, GET /workflows/runs/{id}, /events, /compare, /diagnostics
and DELETE /workflows/runs/{id}, and nothing else. A user who wants to run a saved
workflow has to leave the browser, open a terminal, and type cao workflow run <name> --inputs .... A user who wants to create one has to hand-write a file into ~/.aws/cli-agent-orchestrator/workflows/ (the unguarded path #698 describes), or drive
an agent through the cao-workflow skill.
The server already has every route the UI needs to close that gap: GET /workflows, GET /workflows/{name} (returns inputs{} with type / required / default), POST /workflows/validate, POST /workflows/runs:submit (202, non-blocking), GET /workflows/runs/{id}/plan, POST /workflows/plans/approve, and once #699 lands,
the guarded create/update write path. The run detail view with the live event timeline
already exists too.
This issue proposes making the Workflows tab a complete surface: pick a saved workflow,
fill in its declared inputs from a generated form, submit, approve the frozen plan when
the gate asks for it, and land on the existing run timeline. Then, as a second step, let
the user create and edit the workflow spec from the same tab, using the same guarded
write path and the same validator the CLI uses. The workflow name stays the durable id,
so "run it again" is one click and the same name works from the CLI and from another
agent.
This is where the Profiles work (#510, shipped as #575 / #585 / #692) was heading. Profiles
gave the UI a place to create and validate the workers; this gives it a place to compose
those workers into a saved workflow and run it. The step form's agent picker reads the
same catalog the Profiles tab writes, so the two surfaces close the loop: author a
profile, use it in a step, run the workflow, watch the run. We can say, the UI half of #583.
Parent roadmap: #583. Depends on: #699 (create/update surfaces). Related: #601 (agent
authors the workflow; this issue is the human editing and launching it), #640 (single-step
re-execute, which the run detail view can expose later), #641 (mid-run approval gates; the
plan-approval view here should generalise to those when they land), #356 (Runs dashboard
RFC for sessions; different object, see Alternatives), #519 (AG-UI operator surfaces;
different UI stack, default-off, see Alternatives), #777 / #774 / #780 (CAO 3.0 ownership
and sharing; this issue stays inside the single-user laptop case and does not pre-empt
them), #510 / #692 (Profiles tab, the pattern this follows).
User Stories
As a service owner running a recurring end-to-end test against a beta stack, I want to
open the Workflows tab, pick adsp-ecs-e2e, fill in table_name, entity_id and log_group, press Run, and watch the steps go green, so that I do not need a terminal
or a hand-rolled status page for each service I own.
As the same owner, I want to run that exact workflow again next week with different
input values, without editing any file, so that one saved artifact covers every
environment.
As a workflow author, I want to create a new sequential workflow in the browser by
choosing agent profiles from the catalog for each step and writing the prompt, and to
see the validator's findings before the file is saved, so that CAO never writes a spec
it would refuse to run.
As a Python workflow author, I want to paste or edit a .py spec in the browser and
get the same lint findings cao workflow validate prints, so that I fix missing-recovery-policy and non-determinism warnings before the first run.
As the human in the loop, when the run stops on plan approval I want to read the frozen
plan in the UI (steps, profiles, providers, inputs) and approve it there, so that the
approval stays a deliberate human act but does not require switching to a terminal.
As a teammate who was told "run adsp-ecs-e2e on the shared box", I want to open the
UI, find the workflow by name, and run it with my own inputs, so that the author does
not have to be present.
Acceptance Criteria
Run (PR A)
The Workflows tab lists saved workflows from GET /workflows (name, tier, description,
declared inputs) next to the existing run list.
Selecting a workflow shows a Run form generated from GET /workflows/{name}'s inputs:
one control per declared input, typed by InputDecl.type (string, int, bool, path), required inputs marked, defaults pre-filled. No hand-written per-workflow form.
Submit calls POST /workflows/runs:submit with {name_or_path, inputs, run_id?} and
navigates to the existing RunDetail for the returned run_id. The UI never uses the
blocking POST /workflows/runs.
A 422 from input validation is shown next to the offending field, not as a toast.
The Run action is disabled with an explanatory title when the token lacks cao:write; Approve is disabled without cao:write or cao:admin. The UI adds no
approval path an agent could call; it only renders the existing human route.
A visible note on the form: inputs are journaled in plaintext and replayed on resume;
do not enter secrets (mirrors R2 of the cao-workflow skill).
Delete workflow (DELETE /workflows/{name}, cao:admin) behind a confirm modal.
Author (PR B)
Create and Edit open a schema-driven form for the YAML sequential tier: name, description, inputs (add/remove typed declarations), ordered steps with provider, agent (picker fed by the profiles catalog), prompt, on_failure, retries. Object-valued or reserved fields are not invented in the UI; anything the
form does not model is left to the raw editor.
A raw editor tab for the Python tier with the lint findings from POST /workflows/validate rendered by the existing ValidationFindings component.
Save is blocked while any error-severity finding is present; warnings are shown and
do not block.
Editing a workflow that has runs shows a note that the change affects future runs
only; existing runs keep their frozen manifest.
Both
No change to AgentPanel, Profiles, Flows or the mcp-apps surface.
tsc -b and the existing web tests pass; new components have unit tests for the form
generator (each InputDecl.type, required, default) and for the 403 / 503 / 422
branches.
Proposed solution
Frontend (web/src/)
components/workflow/WorkflowCatalog.tsx: list of saved workflows, select to open Run
or Edit. Sits left of the existing run list inside WorkflowsPanel.tsx.
components/workflow/RunWorkflowModal.tsx: form generated from inputs{}; submit,
422 field errors, secret warning.
components/workflow/PlanApprovalModal.tsx: renders the frozen plan, Approve button,
distinguishes 403 from 503.
components/workflow/WorkflowEditorModal.tsx (PR B): schema-driven YAML form plus raw
editor, wired to POST /workflows/validate and the create/update route; reuses ValidationFindings.tsx and the profile catalog fetch already used by ProfilesPanel.
Is your feature request related to a problem? Please describe.
I built a supervisor-plus-workers integration test for a service on CAO v2.2.0 (a test-supervisor profile doing sequential handoffs, a STATUS_FILE written with jq,
a tmux cleanup loop, and a Flask plus React page to watch it). Every piece of that is now
a CAO workflow feature: journal, resume, plan approval, per-step recovery policy, and the
Workflows tab timeline. I want to rebuild it for two new services as saved workflows, but
the last mile is the terminal: cao workflow run for every run, and a hand-written file
for every edit. For a teammate who is not the author, that is the difference between
"open the tab and press Run" and "learn the CLI first". The Profiles tab was the first
half of fixing this (workers you can create and validate in the browser); the workflow
that uses them is the second half, and the part I actually set out to build.
Describe alternatives you've considered
Keep the hand-rolled status page per project. Rejected: it duplicates the run timeline
that already exists in the Workflows tab, and it does not get journal, resume or
approval for free.
Use Flows (cao schedule) to trigger the supervisor profile. Rejected: Flow is a
time trigger for one agent prompt. It has no steps, inputs, or resume, so it does not
replace the workflow; it can later trigger one.
Python-only editor, no YAML form. Possible, and consistent with [Roadmap] Conversational deterministic workflows and portable goal loops #583 calling Python the
primary format. I lean toward a YAML form for the sequential case because it is the
format a non-author teammate can read and tweak in a browser, but I am fine dropping the
form if maintainers would rather not maintain two authoring surfaces.
Additional context
Questions I would like a nod on before opening PR A:
PR split as A (run/approve/delete) then B (author), or one PR?
Placement: inside the existing Workflows tab (my preference, no new tab), or a
separate tab?
For PR B, YAML form plus Python raw editor, or Python raw editor only?
Evidence from main at 29b235c (2026-09-14): web/src/components/WorkflowsPanel.tsx
and web/src/api.ts contain only the read routes listed above; POST /workflows/runs
and POST /workflows/runs:submit require cao:write or cao:admin; POST /workflows/plans/approve accepts cao:write or cao:admin; DELETE /workflows/{name} requires cao:admin; WorkflowSpec.inputs is Dict[str, InputDecl] with type: Literal["string","int","bool","path"], required, default.
I am happy to take PR A as soon as the split and placement are agreed.
[Feat] Web UI: author, run-with-inputs, approve, and monitor a saved workflow
Overview
Today the Workflows tab is read-only.
WorkflowsPanel.tsxandweb/src/api.tscallGET /workflows/runs,GET /workflows/runs/{id},/events,/compare,/diagnosticsand
DELETE /workflows/runs/{id}, and nothing else. A user who wants to run a savedworkflow has to leave the browser, open a terminal, and type
cao workflow run <name> --inputs .... A user who wants to create one has to hand-write a file into~/.aws/cli-agent-orchestrator/workflows/(the unguarded path #698 describes), or drivean agent through the
cao-workflowskill.The server already has every route the UI needs to close that gap:
GET /workflows,GET /workflows/{name}(returnsinputs{}withtype/required/default),POST /workflows/validate,POST /workflows/runs:submit(202, non-blocking),GET /workflows/runs/{id}/plan,POST /workflows/plans/approve, and once #699 lands,the guarded create/update write path. The run detail view with the live event timeline
already exists too.
This issue proposes making the Workflows tab a complete surface: pick a saved workflow,
fill in its declared inputs from a generated form, submit, approve the frozen plan when
the gate asks for it, and land on the existing run timeline. Then, as a second step, let
the user create and edit the workflow spec from the same tab, using the same guarded
write path and the same validator the CLI uses. The workflow name stays the durable id,
so "run it again" is one click and the same name works from the CLI and from another
agent.
This is where the Profiles work (#510, shipped as #575 / #585 / #692) was heading. Profiles
gave the UI a place to create and validate the workers; this gives it a place to compose
those workers into a saved workflow and run it. The step form's agent picker reads the
same catalog the Profiles tab writes, so the two surfaces close the loop: author a
profile, use it in a step, run the workflow, watch the run. We can say, the UI half of #583.
Parent roadmap: #583. Depends on: #699 (create/update surfaces). Related: #601 (agent
authors the workflow; this issue is the human editing and launching it), #640 (single-step
re-execute, which the run detail view can expose later), #641 (mid-run approval gates; the
plan-approval view here should generalise to those when they land), #356 (Runs dashboard
RFC for sessions; different object, see Alternatives), #519 (AG-UI operator surfaces;
different UI stack, default-off, see Alternatives), #777 / #774 / #780 (CAO 3.0 ownership
and sharing; this issue stays inside the single-user laptop case and does not pre-empt
them), #510 / #692 (Profiles tab, the pattern this follows).
User Stories
open the Workflows tab, pick
adsp-ecs-e2e, fill intable_name,entity_idandlog_group, press Run, and watch the steps go green, so that I do not need a terminalor a hand-rolled status page for each service I own.
input values, without editing any file, so that one saved artifact covers every
environment.
choosing agent profiles from the catalog for each step and writing the prompt, and to
see the validator's findings before the file is saved, so that CAO never writes a spec
it would refuse to run.
.pyspec in the browser andget the same lint findings
cao workflow validateprints, so that I fixmissing-recovery-policyand non-determinism warnings before the first run.plan in the UI (steps, profiles, providers, inputs) and approve it there, so that the
approval stays a deliberate human act but does not require switching to a terminal.
adsp-ecs-e2eon the shared box", I want to open theUI, find the workflow by name, and run it with my own inputs, so that the author does
not have to be present.
Acceptance Criteria
Run (PR A)
GET /workflows(name, tier, description,declared inputs) next to the existing run list.
GET /workflows/{name}'sinputs:one control per declared input, typed by
InputDecl.type(string,int,bool,path), required inputs marked, defaults pre-filled. No hand-written per-workflow form.POST /workflows/runs:submitwith{name_or_path, inputs, run_id?}andnavigates to the existing
RunDetailfor the returnedrun_id. The UI never uses theblocking
POST /workflows/runs.PlanApprovalRequiredErroropens a plan view fed byGET /workflows/runs/{run_id}/plan, with an Approve action that callsPOST /workflows/plans/approve. A 503PlanIdentityUnavailableErrorshows "retry",not an approval prompt (the two causes feat(workflow): conversational authoring — create/update surfaces, approval on by default (#583 Bolt 3) #699 separated must stay separate in the UI).
cao:write; Approve is disabled withoutcao:writeorcao:admin. The UI adds noapproval path an agent could call; it only renders the existing human route.
do not enter secrets (mirrors R2 of the
cao-workflowskill).DELETE /workflows/{name},cao:admin) behind a confirm modal.Author (PR B)
name,description,inputs(add/remove typed declarations), orderedstepswithprovider,agent(picker fed by the profiles catalog),prompt,on_failure,retries. Object-valued or reserved fields are not invented in the UI; anything theform does not model is left to the raw editor.
POST /workflows/validaterendered by the existingValidationFindingscomponent.Save is blocked while any
error-severity finding is present; warnings are shown anddo not block.
workflows directory itself and never bypasses the tier-collision check.
only; existing runs keep their frozen manifest.
Both
AgentPanel, Profiles, Flows or the mcp-apps surface.tsc -band the existing web tests pass; new components have unit tests for the formgenerator (each
InputDecl.type, required, default) and for the 403 / 503 / 422branches.
Proposed solution
Frontend (
web/src/)components/workflow/WorkflowCatalog.tsx: list of saved workflows, select to open Runor Edit. Sits left of the existing run list inside
WorkflowsPanel.tsx.components/workflow/RunWorkflowModal.tsx: form generated frominputs{}; submit,422 field errors, secret warning.
components/workflow/PlanApprovalModal.tsx: renders the frozen plan, Approve button,distinguishes 403 from 503.
components/workflow/WorkflowEditorModal.tsx(PR B): schema-driven YAML form plus raweditor, wired to
POST /workflows/validateand the create/update route; reusesValidationFindings.tsxand the profile catalog fetch already used byProfilesPanel.api.ts: addlistWorkflows,getWorkflow,validateWorkflow,submitWorkflowRun,getRunPlan,approvePlan,deleteWorkflow, and (after feat(workflow): conversational authoring — create/update surfaces, approval on by default (#583 Bolt 3) #699)createWorkflow/updateWorkflow.workflowCatalogalongside the existingworkflowRunsslice; no changeto the runs slice.
Backend
issue is not asking for a second write path.
GET /workflows/{name}/runsfilter so the catalog can show "last runstatus" per workflow without client-side joins.
Sequencing
independently useful.
every workflow an owner, [Feat] Sharing and visibility within a tenant (schema in 3.0, experience after) #780 adds the visibility schema in 3.0 and defers the sharing
experience to after 3.0. So this issue does not propose an export bundle or a run-only
token; when [Feat] Sharing and visibility within a tenant (schema in 3.0, experience after) #780's "experience after" phase arrives, the catalog and run form here are
the surface a Share control would attach to. One thing PR A should do now so it does
not fight 3.0 later: treat the workflow identity as whatever
GET /workflowsreturns,not as a bare global name, since [Vision] CAO 3.0 — run anywhere, shared by your whole organisation as a multi-tenant SaaS #777 makes Alice's
deployand Bob'sdeploytwodifferent records.
Additional context
Is your feature request related to a problem? Please describe.
I built a supervisor-plus-workers integration test for a service on CAO v2.2.0 (a
test-supervisorprofile doing sequential handoffs, aSTATUS_FILEwritten withjq,a tmux cleanup loop, and a Flask plus React page to watch it). Every piece of that is now
a CAO workflow feature: journal, resume, plan approval, per-step recovery policy, and the
Workflows tab timeline. I want to rebuild it for two new services as saved workflows, but
the last mile is the terminal:
cao workflow runfor every run, and a hand-written filefor every edit. For a teammate who is not the author, that is the difference between
"open the tab and press Run" and "learn the CLI first". The Profiles tab was the first
half of fixing this (workers you can create and validate in the browser); the workflow
that uses them is the second half, and the part I actually set out to build.
Describe alternatives you've considered
that already exists in the Workflows tab, and it does not get journal, resume or
approval for free.
cao schedule) to trigger the supervisor profile. Rejected: Flow is atime trigger for one agent prompt. It has no steps, inputs, or resume, so it does not
replace the workflow; it can later trigger one.
not a replacement: [Workflow] Generate Python workflows using discovered agent profiles #601 has an agent generate the workflow; this issue gives the human
a place to inspect, edit, launch and approve it. Both write through the same guarded
path.
agent-to-agent messages. This issue is about the workflow spec object and its journaled
runs, which have a different lifecycle (author, validate, approve, run, resume). The two
can coexist; if maintainers prefer one "Runs" front door, the workflow catalog and run
form here can mount inside it.
default-off behind
CAO_AGUI_ENABLED, metadata-only on the wire, and composed from afrozen construct allow-list; a workflow editor with a full spec body does not fit that
contract, and the Workflows tab already lives in the main UI. If the maintainers want
the run form exposed there too, an
approval_cardfor plan approval is the obviousfirst construct, but that is a follow-up, not this issue.
primary format. I lean toward a YAML form for the sequential case because it is the
format a non-author teammate can read and tweak in a browser, but I am fine dropping the
form if maintainers would rather not maintain two authoring surfaces.
Additional context
Questions I would like a nod on before opening PR A:
agent granting approval, not a human clicking a button that calls the same route
cao workflow approveuses. If the maintainers want approval to stay CLI-only, PR Awill show the plan read-only with the exact CLI command to run.
separate tab?
Evidence from main at 29b235c (2026-09-14):
web/src/components/WorkflowsPanel.tsxand
web/src/api.tscontain only the read routes listed above;POST /workflows/runsand
POST /workflows/runs:submitrequirecao:writeorcao:admin;POST /workflows/plans/approveacceptscao:writeorcao:admin;DELETE /workflows/{name}requirescao:admin;WorkflowSpec.inputsisDict[str, InputDecl]withtype: Literal["string","int","bool","path"],required,default.I am happy to take PR A as soon as the split and placement are agreed.