Comparison: Spec Engine vs alternatives

Context

The spec engine exposes two distinct layers for running spec-driven workflows: a high-level interactive layer (spec.*) and a low-level pipeline layer (pipeline.*). Both execute the same underlying tasks with quality gates, but they differ significantly in who controls the approval loop, what state they manage, and how much flexibility you get over execution.

Feature comparison

Capability spec layer (execute_with_approval) pipeline layer (PipelineOrchestrator)
Import path from spec.runner import execute_with_approval from pipeline import PipelineOrchestrator
Approval loop Per-task, interactive — pauses after each task for user sign-off Batch — runs all tasks unless you pass skip_task_ids
Resume support Yes — load_state / save_state / find_resumable_plans persist SpecState between sessions No built-in state persistence; caller owns resumability
Progress feedback format_progress_bar, present_task_result, present_tasks render live output Callback only — wire on_task_complete: TaskCallback yourself
Skip gates / tests / simplify skip_gates, skip_tests, skip_simplify keyword args Same flags on PipelineOrchestrator.__init__
Task filtering get_pending_tasks filters against persisted SpecState.completed Pass skip_task_ids: set[str] to run_all directly
Result model PipelineResult (shared) — success, summary, total_cost, duration_ms PipelineResult (shared)
Per-task result present_task_result(task, gate_result) formats for display run_gates_for_task(task) returns raw TaskResult
State file format HTML comment embedded in the plan file, managed by save_state / clear_state Not managed
Typical caller Conversational CLI / interactive session Automated scripts, CI pipelines

Key tradeoffs

spec layer: structured interaction, built-in state

execute_with_approval is the right entry point when you want the engine to handle the approval ceremony for you. It persists a SpecState (tracking completed, current, and auto_run fields) directly in the plan file, so an interrupted run is always resumable via find_resumable_plans. The presenter functions — present_tasks, present_task_detail, present_task_result, and format_progress_bar — are wired in automatically, so you get human-readable output without extra plumbing.

The tradeoff: the approval loop is opinionated. You accept the per-task pause-and-confirm pattern or you set SpecState.auto_run = True to skip it. If you need finer-grained control over which tasks run or in what order, you are working against the layer, not with it.

pipeline layer: explicit control, no ceremony

PipelineOrchestrator gives you the same quality-gate execution but none of the interactive scaffolding. You call run_all with an optional skip_task_ids set and an on_task_complete callback, and you receive a PipelineResult. State, display, and approval are entirely your responsibility. run_gates_for_task lets you evaluate a single DecomposedTask in isolation, which is useful for testing gate logic without running the full plan.

The tradeoff: you write more glue code. If you need to resume a run, you must track completed task IDs yourself.

Decision guide

Use execute_with_approval (spec layer) when:

Use PipelineOrchestrator (pipeline layer) when:

When in doubt, start with the spec layer. The pipeline layer is the better fit only when you are certain you do not need state persistence or interactive approval — and are prepared to manage both yourself.

Source files

Tags: spec, planning