Plan — #287 Workflow authoring DX (scaffold + check + guide)¶
Split from #283 (which keeps the operator axis: launch entry + progress viz). This issue is the author / setup axis: a developer finds it hard to write or modify a workflow inside the framework, and mistakes only fail loud at startup.
Grill-locked decisions (the consensus reached before building):
- Core = the developer-in-repo authoring experience (axis A). The operator
config UI (forms over
collections.json/uploads/input.json) is out of scope —collections.jsonalready has a picker (#142) andinput.jsonis deliberately profile-owned freeform (workflows.md §14). - The four pains, all real: (1) don't know what blocks/API exist, (2) don't know
how to start (blank
run.py), (3) manifestphasesdrift fromrun.py, (4) mistakes only fail at startup with unclear messages. - v1 = scaffold + guide, mutually reinforcing. The scaffold gives a runnable, annotated starting point ("how to start"); the guide is the block catalog + conventions ("what blocks exist"), authored to be read by both a human and an AI assistant (CLAUDE.md points at it).
- Phase drift is low-impact / nice-to-have (the author's call). Not a
centrepiece: the scaffold writes
phasesto match the recipe, andchecksurfaces a warning on aphase="literal"inrun.pythat isn't declared (the typo case). It does not fail boot and does not flag declared-but-unused. - Delivery = a module CLI
python -m workspace_app.workflow {new,check}(same shape aspython -m workspace_app). - The guide is a new
docs/workflows-authoring.md, cross-linked fromworkflows.md, with a one-line pointer added toCLAUDE.md. No dedicated skill (over-build for v1).
Design¶
Purely additive — no change to existing workflow logic. New modules under
src/workspace_app/workflow/:
authoring.py—Diagnostic+check_app(slug)/check_profile_dir(dir, where). Fully static (AST, noexec): detects a missing/run()-less / syntactically brokenrun.py, empty/duplicate list-form workflow ids, empty phase ids (errors), and aphase="literal"used inrun.pybut not declared (warning, the drift/typo case). Non-literalphase=expris skipped (can't verify); a declared-but-unused phase is not flagged (bundled fixtures legitimately declare phases they don't emit).checkis static on top of boot validation, not a replacement.discovery.validate_workflow_profilesstays as-is at startup: itexecsrun.py, so it still catches import/NameErrorfailures static parsing can't.scaffold.py—scaffold_workflow(apps_dir, slug, profile, id, recipe, force). Recipes:minimal(oneagent_write_step, runs to done),review-commit(produce →human_gate→ deterministic commit, runs to awaiting_human),batch(wf.mapoveruploads/*). Writes the annotatedrun.py+ creates / appends the_profile.jsonworkflowsentry withphasesmatching the recipe. Refuses to overwrite an existing id (unless--force) or to target a legacy-singular-workflowprofile (would shadow it).cli.py—main(argv) -> int: dispatchcheck/new, print diagnostics / created files, exit non-zero on any error. (Tested directly.)__main__.py— two lines (from .cli import main; raise SystemExit(main())), added to the coverageomitlist like the top-level__main__.py.
Phases (flat; per CLAUDE.md)¶
- P1
checkcore —authoring.py(Diagnostic + staticcheck_*). TDD. - P2 module CLI —
cli.pymain()(check [slug], exit codes) +__main__.py. TDD. - P3 scaffold
new—scaffold.pyrecipes +_profile.jsonappend; generated output must passcheck. CLInewwired. TDD. - P4 gate test — every bundled app is diagnostic-clean (
check_app(slug) == []), so CI catches drift. TDD. - P5 guide —
docs/workflows-authoring.md(run() contract, full block catalog incl.wf.*methods, conventions, recipe gallery, how to runnew/check) +CLAUDE.mdpointer +workflows.mdcross-link. - P6 live-check (DoD) — scaffold a throwaway workflow into
playgroundand actually run it against the running app + Ollama:minimal→ done,review-commit→ awaiting_human.
Out of scope (explicit)¶
Operator config UI (axis B) · visual / DAG authoring · runtime phase enforcement
(static check only) · input.json schema validation (profile-owned freeform) ·
hot-reload of newly scaffolded workflows (boot-time discovery is fine).