A task graph for building cockpit with the architect → coder → tester → reviewer pipeline.
Source of truth: SPEC.md (what) and CLAUDE.md (how). This file decomposes the SPEC's
phases into tasks sized at roughly one stacked PR each.
For every task:
- architect drafts the approach against
SPEC.md+CLAUDE.md(files, order, risks). This is the plan-gate step — get it approved before code. - coder implements only the approved task. No drive-by refactors, no scope creep.
- tester writes/extends tests; for state-machine tasks, tests come first.
- reviewer checks the diff against
CLAUDE.md§6 (Definition of Done) and §0 (Invariants). Advisory only; a human approves.
Tasks are stacked in dependency order (the same DAG model cockpit itself manages). A task is mergeable only when its acceptance criteria pass. Build in validation order, not runtime order — the shared loop is proven on the diff gate (Phase 1) before the plan gate reuses it.
Legend: [deps: …] lists prerequisite task IDs. Each task names its primary subagent owner.
Goal: cockpit project <id> reads issues, builds the DAG, prints the frontier;
cockpit ingest lists existing PRs. No loop yet.
Create the Cargo workspace (cockpit-core, cockpit-cli), rust-toolchain.toml (edition
2024), CI running fmt, clippy -D warnings, test.
Done when: empty crates build and CI is green on all three checks.
Implement model.rs: ReviewId/IssueRef/PrRef newtypes, Review, ProjectPlan,
GateState, Artifact, PlanDoc, Comment, Anchor, AgentRun/AgentMode per SPEC.md
§6. Derive the required traits; comments ephemeral (no resolved, no durable sha).
Done when: types compile; a unit test constructs a small DAG of Reviews and asserts the
parent/child edges.
Implement gate.rs: the Gated trait and every transition in SPEC.md §7 as explicit
functions, plus the stale flag logic. Tests first.
Done when: a test exercises every transition including failure edges (agent-failed →
InReview) and stale set/clear; illegal transitions are rejected.
adapters/linear.rs: read a project's issues + dependency relations via GraphQL; build the
DAG. thiserror error type.
Done when: given a project id, returns issues + edges; integration test against a fixture.
adapters/github.rs: pr list --json, pr diff, pr checks via gh. Parse the Linear
issue id out of each PR head branch to link PR → issue (per SPEC.md §16, settled).
Done when: lists PRs with diffs; branch→issue parsing covered by unit tests incl. edge
cases (no id, malformed).
adapters/git.rs with git2: ensure_worktree (stacked base = parent branch),
reconcile, prune_worktree. Restack stubbed (Phase 3).
Done when: can create/reconcile/prune a worktree against a scratch repo in tests.
Wire the CLI to build the DAG, compute the frontier (SPEC.md §5/§8), and print it.
Done when: both commands produce correct frontier/PR output against a real test project.
Phase 0 exit: the frontier prints correctly from real data; all adapters tested.
Goal: prove the shared loop round-trips end to end from the CLI. This is the product in miniature; everything after is leverage on top.
prompt.rs: build the rework prompt per SPEC.md §9 — intent, approved plan (diff gate),
current artifact, anchored comments, scope guard incl. the test-weakening clause. Hash + log
the assembled prompt.
Done when: golden-file tests assert exact prompt structure for a sample review.
adapters/agent.rs: spawn claude in a worktree via PTY (reuse Plannotator's PTY),
AgentMode::Fix, capture logs, track pid, map session_id → (object, mode).
Done when: spawns a process in a worktree and records the session mapping; covered by a
test with a stub command.
hook_server.rs: axum server on a fixed localhost port; /hook/stop maps session → object,
calls reconcile (re-read git, rerun ci/test deltas), clears ephemeral comments, →
Reworked, emits a completion signal.
Done when: a simulated POST drives a Dispatched review to Reworked and clears its
comments.
CLI verbs: add an anchored comment; request-changes <pr> gathers open comments → assembles
prompt → spawns fixer → Dispatched.
Done when: the full verb set works on a real PR.
The reliability bar: comment → request-changes → agent fixes → pushes → Stop hook → state
flips to Reworked, comments cleared, ready for re-review — no manual terminal step.
Done when: this runs green against a real (small) PR + agent.
Phase 1 exit: the loop round-trips reliably. If it does, the rest is presentation and reuse; if it doesn't, fix it here before anything else.
Goal: originate work from a Linear project; reuse the Phase-1 loop on a ProjectPlan.
Decide and pin a structured plan-output format via the planner subagent's instructions
(resolve SPEC.md §16 open item), parse it into PlanDoc (steps + files + risks as
anchors).
Done when: parser round-trips the pinned format; anchors resolve to steps/files.
Run the loop on ProjectPlan with AgentMode::Plan; reconcile re-parses the plan doc.
Done when: a plan can be commented on and re-planned through the same transitions as a
diff review.
Kick off: optionally produce a plan (→ plan gate) or skip; on approval/skip, spawn the
implementer for every issue, establishing stacked worktrees (base = parent branch). Each
build opens a PR → a Review at the diff gate.
Done when: a project goes plan→approved→batch-of-PRs (and skip→PRs) with no manual steps.
Phase 2 exit: a project can be taken from issues to a batch of diff-gate reviews.
Base Reworked marks descendants stale at dispatch; rebase each descendant in dependency
order via git2; clean rebases are pure git.
Done when: a 3-PR stack reworked at the base auto-restacks the upper two cleanly.
On rebase conflict, spawn the conflict-resolver subagent (AgentMode::Restack); on success
clear stale.
Done when: an induced conflict is resolved via agent and the stack settles.
Phase 3 exit: stacked rework is hands-off except for genuine conflicts.
Goal: wrap the proven core. The shell is presentation over working logic.
app/src-tauri with AppState holding core handles (Arc), generate_handler!
registration, CommandError (Serialize) mapping from core errors, ts-rs codegen for
domain types with a CI staleness check. Least-privilege capabilities.
Done when: a trivial command round-trips and generated TS types are committed + checked.
React + Zustand: the frontier list, per-object agent status, gate controls; subscribe to the Stop-hook completion event to flip state live. Done when: the morning frontier renders and updates on agent completion.
Monaco diff editor with inline comment threads + the ci_delta/test_count_delta flags;
request changes calls the command. Do not hand-roll the diff viewer.
Done when: a real PR is reviewed and reworked entirely from the desktop app.
Render PlanDoc as a commentable document (Plannotator annotation port); approve → build.
Done when: a plan is reviewed and approved from the app, triggering the batch.
Phase 4 exit: the full loop is usable from the desktop app, both gates.
- T5.1 Batch-approve the clean frontier (size/CI/test-delta heuristics, advisory).
- T5.2 Optional GitHub comment mirror (confirmed side effect).
- T5.3 Multi-stack view.
- Critical path: T0.1 → T0.2 → T0.3 → (T1.1,T1.2,T1.3) → T1.4 → T1.5. Everything downstream assumes the loop proven at T1.5.
- Top risk: the Stop-hook → reconcile round-trip (T1.3). It's the difference between a loop and babysitting. De-risk it first inside Phase 1; reuse the Plannotator interceptor.
- Second risk: plan-doc parsing (T2.1). Pin the format or anchors will be flaky. Doesn't block Phase 1.
- Do not start Phase 4 (Tauri) before T1.5 is green. Building UI over an unproven loop is the main way this project would waste a week.