feat(pipeline): multi-model plan → code → review pipeline task type#629
feat(pipeline): multi-model plan → code → review pipeline task type#629bborn wants to merge 7 commits into
Conversation
Borrowed from herdr's herdr-plan-code-review: one goal is split into an ordered chain of phase tasks, each routed to its own executor and model, that hand work forward on one shared git branch and advance automatically. The default `plan-code-review` pipeline runs three phases on one branch: Plan (Claude/Opus, writes PLAN.md) → Code (Claude/Sonnet, implements) → Review (Codex, reviews with fresh eyes and opens the PR). Assembled entirely from existing primitives — no bespoke execution engine: - per-task Executor + Model overrides give each phase a different agent; - task dependencies with auto_queue chain the phases (completing one auto-queues the next via db.ProcessCompletedBlocker); - a pinned BranchName on phase 1 + SourceBranch on the rest keeps every phase on one branch so each sees the previous phase's commits. The normal daemon executor runs each phase task in turn. New: - internal/pipeline: Phase/Definition model, built-in plan-code-review definition, and Create() that builds the dependency chain. - `ty pipeline <goal>` CLI command (+ --list, --definition, --no-execute, --permission-mode, --json). - taskyou_create_pipeline MCP tool. - setupWorktree now honors a caller-pinned BranchName so a pipeline can route several phases onto one shared branch. Tests: pipeline build/chain/auto-queue/validation, branch-name honoring. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the pipeline entry point to the TUI (TaskYou is TUI-first) and make the default pipeline degrade gracefully when an executor isn't installed. TUI: - New "Pipeline" selector in the new-task form (advanced fields), mirroring the existing Executor/Permission selectors: "single task" (default) or a pipeline definition. Selecting one turns submit into pipeline.Create using the form's title/body as the goal and its project/permission for every phase. - The queue confirm reads "Start the pipeline now? / stage all phases" for a pipeline, and a toast reports the created chain + branch. - Hidden when editing an existing task. Executor fallback: - pipeline.Create takes an optional AvailableExecutors set; any phase whose executor isn't installed falls back to Claude (recorded in Result.Fallbacks and surfaced in the CLI/TUI). So a missing Codex no longer strands the Review phase — the pipeline still runs end-to-end. CLI and TUI pass the host's available executors; an empty set disables the check. Tests: form pipeline field (default, cycle, visibility, render); pipeline fallback + no-fallback. QA'd via the ty-qa VHS harness (board, form selector, selected state, confirm, end-to-end TUI creation). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…default
Address review feedback: the default pipeline no longer hardwires Codex with a
Claude fallback. Instead:
- Defaults are all-Claude (Plan=opus, Code=sonnet, Review=opus) — works on any
host, never silently swaps executors.
- Each phase's executor+model is configurable per project and persisted, so you
set it once ("Review runs on codex for this repo") and every pipeline there
defaults to your choices. Stored in settings under pipeline_config:<proj>:<def>.
- New `ty pipeline config` command: view / --set "Phase=executor[/model]" /
--reset. pipeline.Create applies the saved config via EffectivePhases; the
TUI and MCP paths pick it up automatically.
- Removed the AvailableExecutors fallback machinery (no longer needed now that
the default is always-available Claude and executor choice is explicit config).
Tests: config round-trip (save/merge/clear), Create honors saved config, chain
defaults updated to all-Claude. Verified the config CLI end-to-end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d824354 to
ed350ef
Compare
… card)
Reworks the linear pipeline into a proper workflow DAG, addressing review
feedback that a straight chain couldn't express the parallel dual-review that
is the herdr flow's whole point, and that N linked tasks cluttered the board.
Model (internal/pipeline):
- Steps form a DAG: each Step has Deps; sequential where steps depend on each
other, parallel where they don't. Default plan-code-review is now
Plan → Code → [Review A ∥ Review B] → Collect, built on the existing task
dependency graph (fan-out + join via auto_queue; validated for single-root,
acyclic, unique names). Collect opens the PR — the one human gate.
- Parallel reviewers push to their OWN branch (single push, no rebase), and
Collect reads each via an injected {{reviews}} list. This replaces a
shared-branch rebase-push that real-agent QA proved a weak model botches by
clobbering the other reviewer's file.
- Per-project step executor/model config carried over (StepConfig).
Board (internal/ui):
- A workflow's step tasks collapse into ONE lead card showing the goal and
current step + progress ("⇄ goal" / "Review ∥ · 3/5") instead of N cards.
Done via a pre-pass (pipeline.GroupWorkflows) feeding the board; the Kanban
render cache signature includes the workflow badge.
- Form selector renamed Workflow; the confirm drops the confusing "stage all
phases" wording for plain start-now / save-for-later.
CLI/MCP updated for steps + DAG; `ty pipeline config` edits per-step models.
Tests: DAG build/validation, parallel fan-out + join auto-advance, per-branch
review handoff, config round-trip, workflow grouping/lead/progress.
QA: ran the real flow end-to-end with live Claude agents (plan → code → two
parallel reviewers → collect) on a git repo with a remote — which is how the
reviewer-clobber bug was found and fixed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Round 3: rebuilt as a workflow DAG — parallel review, one board card, real-agent QAWent back to how herdr actually works (Plan → Code → two parallel reviewers → collect) and reworked the linear pipeline into a real workflow DAG. Commit What changed
Board: one collapsed card (was 5)QA — actually ran it end-to-end with live agentsRan the real rendered step prompts through live Claude agents on a git repo with a remote — Plan (sonnet) → Code (sonnet) → Review A (haiku) ∥ Review B (sonnet), concurrently → Collect (sonnet), goal: "add fizzbuzz.py + a pytest test". This caught a real bug. With the reviewers pushing to a shared branch, the weaker model botched the rebase-push and clobbered the other reviewer's file. Fixed: each reviewer now pushes to its own branch (single push, no rebase, no race), and Collect reads each explicitly. Re-ran — both reviews survive: Collect read both reviews, applied Review B's All package tests + Follow-ups
|
Configuring a workflow's per-step executor/model was CLI-only; add a TUI editor so it's doable in the board (TaskYou is TUI-first). - Press `W` on the board to open a compact per-project workflow config modal: one row per step (Plan, Code, Review A, Review B, Collect) with a horizontal executor/model selector, showing each step's dependencies (← Code, ← Review A+Review B) so the DAG is visible. ↑/↓ pick a step, ←/→ change, enter saves. - Saves to the same persisted per-project config as `ty pipeline config`, so a change here is what every workflow in the project defaults to (verified: the CLI reads back what the TUI writes, and vice versa). - Prefills from the project's current effective config; project is the selected task's project, else the last-used project. WorkflowConfigModel is a small self-contained bubbletea model (compact one-line selectors, not a tall huh form). Tests cover the executor/model option list and the value round-trip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Full TUI flow for workflows — including in-TUI config (
|
… authoring
Answers "how do I define/configure the steps": custom workflows are now
first-class. You can define a whole new flow (add a QA step, a spike→build→test
shape, extra reviewers) without touching Go.
- **YAML files.** One workflow per file in ~/.config/task/workflows/*.yaml
(override $TY_WORKFLOWS_DIR) and per-project .taskyou/workflows/. Discovered at
runtime and merged with the built-in; a custom name shadows a built-in.
Schema: name/description + steps[{name, executor, model, deps, prompt}].
- **Authoring is just prompts.** You write what each step does + its deps; the
git handoff is DERIVED from the step's DAG position (compose.go): a step with a
parallel sibling pushes to its own branch, a join reads its inputs' branches,
the sink opens the PR. So authors never write commit/push/PR boilerplate — the
same class of bug the earlier real-agent QA caught.
- **Free text → workflow.** `ty pipeline new "<describe it>"` runs the
description through Claude to emit a validated YAML you can edit, with a
self-repair retry when the model violates the single-root rule.
- `ty pipeline --list` marks built-in vs custom; custom workflows appear in the
TUI new-task selector automatically.
Tests: YAML parse/validate/marshal round-trip, registry merge + shadowing,
DAG-derived handoff (parallel/join/sink/linear), Create honoring a custom
workflow. QA'd end-to-end: hand-written YAML + a live LLM-generated 9-step DAG
(plan → 3 parallel spikes → select → build → review∥test → finalize).
Follow-ups: multi-root workflows (true parallel entry points) still need shared-
branch bootstrapping; the TUI `W` model-config modal targets the default
definition (custom workflows configure models in their YAML / via CLI).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
User-defined workflows — text-file first, LLM optional (
|










Workflow task type: one goal → a small DAG of steps
Adds a workflow: a single goal is broken into a small DAG of step tasks that run on one shared git branch, each routed to its own executor and model, advancing automatically. Steps are sequential where they depend on each other and parallel where they don't.
The default
plan-code-reviewworkflow:PLAN.md, push. No code.How it works
Built on primitives TaskYou already has — no bespoke execution engine; the normal daemon runs each step task:
Depsbecomeauto_queuedependencies. Fan-out (two reviewers depending on Code) and join (Collect depending on both reviewers) fall out for free —ProcessCompletedBlockerqueues a step once all its blockers complete.SourceBranch, handing work forward through git. The two reviewers push to their own branches (single push, no rebase) so they can't clobber each other, and Collect reads each explicitly.blockedwhen Collect opens the PR (awaiting a human merge) or when a step callstaskyou_needs_input.⇄ goal/Review ∥ · 3/5) instead of cluttering the board with a card per step.Configurable per project
Each step's executor and model is configurable per project and persisted, so you set it once and every workflow in that project uses your choices:
Steps are data, so a workflow can be extended (add a QA step, a third reviewer, a different flow) without touching the executor.
Entry points
ty pipeline "<goal>"(--definition,--list,--no-execute,--permission-mode,--json) andty pipeline config.taskyou_create_pipelineso an agent can spawn a workflow mid-task.Each step commits and pushes the shared branch, so a workflow needs a git-worktree project with a remote to push to.
Changes
internal/pipeline/(new/reworked): DAG model (Step+Deps, validated for single-root / acyclic / unique names), the built-inplan-code-reviewdefinition,Create()that builds the linked-task DAG, per-project step config, andGroupWorkflowsfor the collapsed board card.internal/ui/: workflow board collapse (kanban.go,app.go), the Workflow form selector, the confirm/toast.cmd/task/main.go:ty pipeline+ty pipeline config.internal/mcp/server.go:taskyou_create_pipeline.internal/executor/executor.go:setupWorktreehonors a caller-pinnedBranchNameso the root step can own the shared branch.Tests & QA
golangci-lintv2.8.0 green.Follow-ups
pipeline config(today it's the CLI; the TUI already honors the saved config).🤖 Generated with Claude Code