feat: phases + tasks — per-task execution with phase directories

- A phase is now a directory: 00_phase.md (overview + task index) plus
  small, quick NN_task.md task files; complete/ mirrors todo/
- Task is the unit of execution: run-task.sh (one unit), run-phase.sh
  (phase to completion incl. 00_phase.md final pass), auto-phase.sh
  (all units in order); validate.sh gate runs after every task
- PHASE_COMMIT commits at phase boundaries (00_phase.md / legacy file moves)
- Legacy flat todo/NN_name.md files still execute as a single unit;
  new migrate-phases-to-tasks.sh converts them to the directory layout
- phase-status.sh reports per-task state and the next unit
- New task-template.md; phase templates now carry a Tasks index
This commit is contained in:
2026-08-23 19:28:01 -04:00
parent b4eb89a677
commit 85ac0d61b9
17 changed files with 696 additions and 223 deletions
+55 -34
View File
@@ -1,25 +1,33 @@
---
name: phase-authoring
description: The required entry point for ANY new work on a .agent/phases/ project. Whenever the user requests a new feature, a bug fix, a refactor, or any other code change to a project that has the .agent/phases/ structure, call this skill FIRST to capture the work as a phase file — never implement the change directly in code. Also use it when the user explicitly asks to add, write, or draft a phase, extend the phase roadmap, or start a new phased-execution project (Protocol B scaffolds fresh projects). Uses the Phase Architect protocol (the /new-phase and /new-project prompts, as a skill); scopes the phase from the user's chat context first and only interviews for information that is genuinely missing. This skill writes phase files; the phased-execution skill runs them.
description: The required entry point for ANY new work on a .agent/phases/ project. Whenever the user requests a new feature, a bug fix, a refactor, or any other code change to a project that has the .agent/phases/ structure, call this skill FIRST to capture the work as a phase directory with task files — never implement the change directly in code. Also use it when the user explicitly asks to add, write, or draft a phase, extend the phase roadmap, or start a new phased-execution project (Protocol B scaffolds fresh projects). Uses the Phase Architect protocol (the /new-phase and /new-project prompts, as a skill); scopes the phase from the user's chat context first and only interviews for information that is genuinely missing. This skill writes phase directories (a 00_phase.md overview plus task files); the phased-execution skill runs them, task by task.
---
# Phase Authoring
You are the **Phase Architect** — a senior engineer responsible for
extending a phased-execution project with new, independently-executable
phases. You design and write phase files; the `phased-execution` skill
executes them. You never implement phase code yourself, and you never
modify the master plan.
phases. You design and write phase directories — a `00_phase.md` overview
plus small task files; the `phased-execution` skill executes them, task by
task. You never implement phase code yourself, and you never modify the
master plan.
Phase state lives in files, not chat:
- `.agent/PLAN.md` — master plan; **LOCKED DECISIONS** are binding
- `.agent/phases/todo/NN_name.md` — pending phases (sort order = execution order)
- `.agent/phases/complete/` — finished phases (read-only history)
- `.agent/phases/todo/NN_name/` — a pending phase: `00_phase.md` overview + `NN_task.md` task files (task sort order = execution order)
- `.agent/phases/todo/NN_name.md` — legacy single-file phase (still valid; migrate or split it)
- `.agent/phases/complete/` — finished phases, mirroring the todo/ layout (read-only history)
Legacy flat phases (`todo/NN_name.md`) are still executed as a single unit.
`bash scripts/migrate-phases-to-tasks.sh [project-root]` (resolve `scripts/`
against this skill's directory) converts them to the directory layout —
mechanical, safe mid-pipeline; splitting a wrapped phase's inline task list
into real task files is this skill's job.
## When to invoke this skill
This skill is the **first stop** for any request to do work on a phased project. If the user asks for a new feature, bug fix, improvement, refactor, or any other code change — regardless of phrasing ("add X", "fix Y", "update Z", "it's broken when…", "make it so that…") — do **not** start editing application code. Convert the request into a phase file with this skill; the `phased-execution` skill is the only path from a phase to code (it runs in a fresh subprocess behind the validation gate).
This skill is the **first stop** for any request to do work on a phased project. If the user asks for a new feature, bug fix, improvement, refactor, or any other code change — regardless of phrasing ("add X", "fix Y", "update Z", "it's broken when…", "make it so that…") — do **not** start editing application code. Convert the request into a phase directory (overview + task files) with this skill; the `phased-execution` skill is the only path from a phase to code (it runs each task in a fresh subprocess behind the validation gate).
- **Phased project** (`.agent/phases/todo/` exists) → **Protocol A**: create the phase for the requested work. This is the default path for feature, bug, and change requests — the user does not need to mention "phase" at all.
- **Fresh project** (no `.agent/` structure) and the user wants a phased project (asks for it explicitly, or the chat context makes clear the phased workflow is wanted) → **Protocol B**: scaffold the project and its phase roadmap.
@@ -53,8 +61,8 @@ Before writing anything, you must:
1. Read `.agent/PLAN.md` — project goals, architecture, and **LOCKED DECISIONS**.
2. Read `AGENTS.md` if present — project rules may add requirements (e.g. one user story per phase with a dedicated E2E suite per story, mandatory commit conventions, or a `validate.sh` gate).
3. Run `bash scripts/phase-status.sh` (resolve `scripts/` against this skill's directory) to list `todo/` and `complete/` and compute the next free number `NN`.
4. Read every file in `.agent/phases/complete/` to understand what has already been built, and review the remaining `todo/` files to avoid overlap. Read the most recent completed phase file(s) and match their **local formatting conventions** (section names, story-mapping lines, E2E/commit blocks) while keeping the required sections below.
3. Run `bash scripts/phase-status.sh` (resolve `scripts/` against this skill's directory) to list the phases and their per-task state, and compute the next free number `NN`.
4. Read the `00_phase.md` files in `.agent/phases/complete/*/` to understand what has already been built, and review the remaining `todo/` phase directories to avoid overlap. Read the most recent completed phase files and match their **local formatting conventions** (section names, story-mapping lines, E2E/commit blocks) while keeping the required sections below.
### Phase 2: Scope the New Phase (context first, interview only if needed)
@@ -68,43 +76,56 @@ Derive from the chat context (see "Scoping from chat context" above):
- If the chat context answers all four, **do not interview** — proceed
straight to Phase 3 and report the derived scope in the final summary.
- If some are missing or ambiguous, ask **only those** — in one message —
and **stop and wait** for the answers before writing the file. Never
and **stop and wait** for the answers before writing the phase. Never
re-ask what the chat already settled.
- New technology: if the user already proposed or approved it in chat, that
**is** explicit permission — record it in the phase file and note that
**is** explicit permission — record it in the phase overview (`00_phase.md`) and note that
`PLAN.md`'s anchor table needs their sign-off (this skill never edits
`PLAN.md`). If it was not discussed in chat, you must ask for — and
receive — explicit permission before proceeding.
### Phase 3: Design & Create the Phase File
### Phase 3: Design & Create the Phase
Create **exactly one** new file at `.agent/phases/todo/NN_name.md`, where
`NN` comes from Phase 1 (next free number, counting `todo/` and
`complete/` together) and `name` is a short `snake_case` description. Use
`assets/phase-template.md` as the skeleton. The file must contain:
Create **exactly one** new phase directory at `.agent/phases/todo/NN_name/`,
where `NN` comes from Phase 1 (next free number, counting `todo/` and
`complete/` together) and `name` is a short `snake_case` description. It
contains the phase overview and the phase's task files:
1. **Objective** — a 1–3 sentence statement of what the phase delivers.
2. **Dependencies** — the phases (by file name) that must be completed first.
3. **Tasks** — specific, granular, ordered steps with file-level detail where applicable.
4. **Testing & Quality (mandatory)** — requires unit and integration tests for all new logic, and states the success criterion: the phase is "Complete" only when the test suite runs successfully and achieves **>90% code coverage** on new/modified code.
5. **Completion Criteria** — observable checks (commands to run, endpoints to hit, artifacts to exist) that tell the next agent the phase is done.
1. **`00_phase.md`** — use `assets/phase-template.md` as the skeleton. It must contain:
- **Objective** — a 1–3 sentence statement of what the phase delivers.
- **Dependencies** — the phases (by directory name) that must be completed first.
- **Tasks** — the ordered index of this phase's task files (one line each).
- **Testing & Quality (mandatory)** — requires unit and integration tests for all new logic, and states the success criterion: the phase is "Complete" only when the test suite runs successfully and achieves **>90% code coverage** on new/modified code.
- **Completion Criteria** — observable checks (commands to run, endpoints to hit, artifacts to exist) that the phase's final pass verifies; include any phase-level verification blocks (e.g. a dedicated E2E or contract suite).
2. **Task files `01_…`, `02_…`, …** — use `assets/task-template.md` as the skeleton. Each must contain:
- **Objective** — 1–2 sentences on what the task delivers.
- **Work** — specific, ordered steps with file-level detail where applicable.
- **Testing & Quality** — the unit/integration tests this task's logic requires; coverage >90% on its new/modified code.
- **Completion Criteria** — observable checks that tell the next agent the task is done.
**Task sizing:** each task must be small and quick — one focused change, a
small file set, roughly ≤30 minutes of executor work; a phase typically holds
2–8 tasks. Tasks execute in file-name order, each in its own fresh subprocess
with the validation gate after every task, so later tasks may build on
earlier ones within the phase.
**Design Mandates:**
- **Independent Viability:** the phase must leave the project functional and launchable on its own once complete.
- **Architectural Anchors:** use only the technologies in the LOCKED DECISIONS of `.agent/PLAN.md`. Never introduce new technology without explicit permission.
- **No Regressions:** the phase must not alter the behavior of completed phases.
- **Executable in isolation:** an agent that sees only the repository and this file — no chat history, no follow-ups — must be able to finish the phase. No hidden assumptions.
- **Executable in isolation:** an agent that sees only the repository, the phase overview, the completed task files, and one task file — no chat history, no follow-ups — must be able to finish that task. No hidden assumptions.
### Final Output
Confirm the path and number of the created file, and summarize its
objective, dependencies, and completion criteria. If you skipped the
interview, open the summary with the scope you derived from the chat
context (intent, dependencies, boundaries, and any new technology with its
permission source) so the user can correct it. Remind the user it can be
executed with the `phased-execution` skill (`run-phase.sh NN_name.md` for a
single phase, `auto-phase.sh` for the full pipeline).
Confirm the path and number of the created phase directory and its task
list, and summarize the phase's objective, dependencies, and completion
criteria. If you skipped the interview, open the summary with the scope you
derived from the chat context (intent, dependencies, boundaries, and any new
technology with its permission source) so the user can correct it. Remind the
user it can be executed with the `phased-execution` skill (`run-task.sh
NN_name/01_…` for a single task, `run-phase.sh NN_name` for the phase,
`auto-phase.sh` for the full pipeline).
## Protocol B — New project with a phased roadmap
@@ -155,7 +176,7 @@ Use file tools to create (not just describe):
- **`.agent/PLAN.md`** — the master design from Phase 3 (architecture, locked decisions, high-level roadmap).
- **`AGENTS.md`** — initialized with: always read `.agent/PLAN.md` first; follow the phased protocol in `.agent/phases/`; never modify `.agent/PLAN.md` or anything in `.agent/phases/complete/`; ask the user before editing files in `.agent/phases/todo/`; strictly adhere to the **LOCKED DECISIONS**.
- **`.agent/phases/todo/`** — sequential, granular phase files (`01_…`, `02_…`, …) that each contain the sections and design mandates from Protocol A, Phase 3, and each leaves the project launchable on its own.
- **`.agent/phases/todo/`** — sequential phase directories (`01_…/`, `02_…/`, …), each with a `00_phase.md` overview and its task files per Protocol A, Phase 3, and each leaving the project launchable on its own.
- **`.agent/phases/complete/`** — create the directory, leave it empty.
Do **not** create `.agent/validate.sh` — the `phased-execution` skill
@@ -167,8 +188,8 @@ execution with `phased-execution` (`auto-phase.sh`).
## Strict Operational Rules
- **Work requests become phase files.** When this skill was invoked because of a feature, bug, or change request, the deliverable is the phase file — not code. Do not edit application code during this invocation; the `phased-execution` skill does that from the phase file.
- **Work requests become phase directories.** When this skill was invoked because of a feature, bug, or change request, the deliverable is the phase directory (overview + task files) — not code. Do not edit application code during this invocation; the `phased-execution` skill does that from the task files.
- **Never** modify `.agent/PLAN.md`, `AGENTS.md`, or any file in `.agent/phases/complete/`.
- **Never** modify existing files in `.agent/phases/todo/`; if one needs updating, ask the user for permission first.
- Create exactly **one** phase file per invocation in Protocol A. If the request covers multiple phases, propose the ordered split and ask the user to confirm it, then create only the first — the rest follow in later invocations (or a Protocol B roadmap pass if the project is new).
- Numbering: `NN` is the next free number after the highest existing file, counting `todo/` and `complete/` together. Never reuse or collide a number.
- **Never** modify existing phase directories or their files in `.agent/phases/todo/`; if one needs updating, ask the user for permission first.
- Create exactly **one** phase directory (overview + task files) per invocation in Protocol A. If the request covers multiple phases, propose the ordered split and ask the user to confirm it, then create only the first — the rest follow in later invocations (or a Protocol B roadmap pass if the project is new).
- Numbering: phase `NN` is the next free number after the highest existing entry (directory or legacy file), counting `todo/` and `complete/` together; task `NN` is per-phase (`01`…). Never reuse or collide a number.
+3 -3
View File
@@ -11,13 +11,13 @@
{{or "— (none)"}}
## Tasks
1. `{{path/to/file}}` — {{specific change, file-level detail}}
2. `{{path/to/file}}` — {{specific change}}
1. `01_{{short_name}}.md` — {{one-line summary}}
2. `02_{{short_name}}.md` — {{one-line summary}}
## Testing & Quality
- Unit/integration: {{tests required for all new logic — name the behaviors to cover}}
- Coverage: **>90%** on new/modified code
{{project additions, e.g. a dedicated Playwright E2E suite run in isolation}}
{{project additions, e.g. a dedicated Playwright E2E suite run in isolation by this phase's final pass}}
## Completion Criteria
- [ ] {{observable check: command to run / endpoint to hit / artifact to exist}}
+19
View File
@@ -0,0 +1,19 @@
# Task {{NN}} — {{Short Title}}
**Phase:** `{{NN_phase}}` · **Story:** `{{.agent/user_stories/<story>.md or "n/a"}}`
## Objective
{{1–2 sentences: what this task delivers}}
## Work
1. `{{path/to/file}}` — {{specific change, file-level detail}}
2. `{{path/to/file}}` — {{specific change}}
## Testing & Quality
- Unit/integration: {{tests required for this task's logic}}
- Coverage: **>90%** on this task's new/modified code
## Completion Criteria
- [ ] {{observable check: command to run / endpoint to hit / artifact to exist}}
- [ ] full test suite green
- [ ] no behavior change in completed work
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# migrate-phases-to-tasks.sh — convert the flat phase-file layout to the
# phase-directory + task-file layout.
#
# Each numeric-prefixed flat phase file in {todo,complete}/ is wrapped into a
# directory of the same name with the file renamed to 00_phase.md:
#
# todo/03_api.md → todo/03_api/00_phase.md
# complete/01_init.md → complete/01_init/00_phase.md
#
# The harness still executes wrapped phases: their inline task lists are
# picked up by the phase's 00_phase.md final pass, so this is safe
# mid-pipeline. Splitting a wrapped todo phase into real task files is the
# phase-authoring skill's job, not this script's. Already-migrated phases are
# left alone; a flat file colliding with an existing same-name directory is
# reported and skipped.
#
# Usage: bash migrate-phases-to-tasks.sh [project-root]
# project-root defaults to the nearest ancestor containing
# .agent/phases/todo or agent/phases/todo (older projects).
set -euo pipefail
root="${1:-}"
if [[ -n "$root" ]]; then
[[ -d "$root" ]] || { echo "✗ ERROR: $root is not a directory" >&2; exit 1; }
else
root="$(pwd)"
while :; do
if [[ -d "$root/.agent/phases/todo" || -d "$root/agent/phases/todo" ]]; then break; fi
[[ "$root" == "/" ]] && { echo "✗ ERROR: no phases/todo found at or above $(pwd)" >&2; exit 1; }
root="$(dirname "$root")"
done
fi
if [[ -d "$root/.agent/phases" ]]; then
phases="$root/.agent/phases"
elif [[ -d "$root/agent/phases" ]]; then
phases="$root/agent/phases"
else
echo "✗ ERROR: no phases directory under $root" >&2
exit 1
fi
echo "project root: $root"
echo "phases: $phases"
echo
moved=0 skipped=0
for d in todo complete; do
[[ -d "$phases/$d" ]] || continue
for f in "$phases/$d"/*.md; do
[[ -e "$f" ]] || continue
base="$(basename "$f" .md)"
[[ "$base" =~ ^[0-9] ]] || continue
if [[ -d "$phases/$d/$base" ]]; then
echo "⚠ skip: $d/$base.md — directory $d/$base/ already exists (conflict)" >&2
skipped=$((skipped + 1))
continue
fi
mkdir -p "$phases/$d/$base"
mv -f "$f" "$phases/$d/$base/00_phase.md"
echo " $d/$base.md → $d/$base/00_phase.md"
moved=$((moved + 1))
done
done
echo
echo "migrated: $moved phase file(s) → 00_phase.md directory layout; skipped: $skipped"
if (( moved > 0 )); then
echo "wrapped todo phases now run as a single final pass; use the phase-authoring"
echo "skill to split their inline task lists into real task files."
fi
+103 -23
View File
@@ -1,9 +1,13 @@
#!/usr/bin/env bash
# phase-status.sh — phase pipeline state for the Phase Architect.
# phase-status.sh — phase/task pipeline state for the Phase Architect.
#
# Finds the project root (nearest ancestor with .agent/phases/todo), prints
# the todo/ and complete/ phase listings, and computes the next free phase
# number NN (counting both directories together, zero-padded to 2 digits).
# the todo/ and complete/ phase listings with per-task state, the next free
# phase number NN (counting both directories together, zero-padded to 2
# digits), and the next pending unit in pipeline order.
#
# Phase layout: todo/NN_name/ holds 00_phase.md (overview) + NN_task.md task
# files; a legacy flat todo/NN_name.md is a single-unit phase.
#
# Usage: bash phase-status.sh # from anywhere in the project tree
@@ -16,31 +20,107 @@ while :; do
root="$(dirname "$root")"
done
list() {
local d="$root/.agent/phases/$1" f found=0
for f in "$d"/*.md; do
[[ -e "$f" ]] || continue
found=1
printf ' %s\n' "$(basename "$f")"
done
if (( ! found )); then printf ' (empty)\n'; fi
}
phases="$root/.agent/phases"
# --- todo: per-task state ------------------------------------------------------
echo "todo:"
found=0
for entry in "$phases/todo/"*; do
[[ -e "$entry" ]] || continue
name="$(basename "$entry")"
[[ "$name" =~ ^[0-9] ]] || continue
found=1
if [[ -d "$entry" ]]; then
# union of this phase's files across todo/ and complete/ (completed units
# move to complete/, so pending = present in todo/, done = in complete/)
comp_dir="$phases/complete/$name"
comp_files=""
if [[ -d "$comp_dir" ]]; then comp_files="$(ls -1 "$comp_dir" 2>/dev/null || true)"; fi
names="$( { ls -1 "$entry" 2>/dev/null || true; printf '%s\n' "$comp_files"; } | grep -E '\.md$' | sort -u || true)"
total=0 done_n=0
while IFS= read -r t; do
[[ -n "$t" ]] || continue
total=$((total + 1))
[[ -f "$phases/complete/$name/$t" ]] && done_n=$((done_n + 1))
done <<< "$names"
printf ' %s/ (%s of %s done)\n' "$name" "$done_n" "$total"
# tasks first (sorted), then 00_phase.md as the final pass
while IFS= read -r t; do
[[ -n "$t" ]] || continue
[[ "$t" == 00_phase.md ]] && continue
if [[ -f "$phases/complete/$name/$t" ]]; then
printf ' [x] %s\n' "$t"
else
printf ' [ ] %s\n' "$t"
fi
done <<< "$names"
if grep -qxF '00_phase.md' <<< "$names"; then
if [[ -f "$phases/complete/$name/00_phase.md" ]]; then
printf ' [x] 00_phase.md (final pass)\n'
else
printf ' [ ] 00_phase.md (final pass)\n'
fi
fi
else
printf ' %s (legacy single-file phase)\n' "$name"
fi
done
(( found )) || echo " (empty)"
# --- complete -------------------------------------------------------------------
echo "complete:"
found=0
for entry in "$phases/complete/"*; do
[[ -e "$entry" ]] || continue
name="$(basename "$entry")"
[[ "$name" =~ ^[0-9] ]] || continue
found=1
if [[ -d "$entry" ]]; then
n=0
for f in "$entry"/*.md; do [[ -e "$f" ]] && n=$((n + 1)); done
printf ' %s/ (%s files)\n' "$name" "$n"
else
printf ' %s (legacy single-file phase)\n' "$name"
fi
done
(( found )) || echo " (empty)"
# --- next free phase number -----------------------------------------------------
max=0
for d in todo complete; do
for f in "$root/.agent/phases/$d"/*.md; do
[[ -e "$f" ]] || continue
n="$(basename "$f" .md)"
if [[ "$n" =~ ^([0-9]+) ]]; then
for entry in "$phases/$d/"*; do
[[ -e "$entry" ]] || continue
name="$(basename "$entry" .md)"
if [[ "$name" =~ ^([0-9]+) ]]; then
n=$((10#${BASH_REMATCH[1]}))
if (( n > max )); then max=$n; fi
(( n > max )) && max=$n
fi
done
done
echo "next phase number: $(printf '%02d' $((max + 1)))"
echo "project root: $root"
echo "todo:"
list todo
echo "complete:"
list complete
echo "next number: $(printf '%02d' $((max + 1)))"
# --- next pending unit -----------------------------------------------------------
next=""
for entry in "$phases/todo/"*; do
[[ -e "$entry" ]] || continue
name="$(basename "$entry")"
[[ "$name" =~ ^[0-9] ]] || continue
if [[ -d "$entry" ]]; then
# first task present in todo/ and not yet in complete/ (mirrors the harness)
t=""
while IFS= read -r f; do
[[ -n "$f" ]] || continue
[[ "$f" =~ ^[0-9] && "$f" == *.md ]] || continue
[[ "$f" == 00_phase.md ]] && continue
[[ -f "$phases/complete/$name/$f" ]] && continue
t="$f"; break
done < <(ls -1 "$entry" 2>/dev/null || true)
if [[ -n "$t" ]]; then next="$name/$t"; break; fi
if [[ -f "$entry/00_phase.md" && ! -f "$phases/complete/$name/00_phase.md" ]]; then
next="$name/00_phase.md"; break
fi
elif [[ -f "$entry" ]]; then
next="$name"; break
fi
done
echo "next unit: ${next:-(none — pipeline complete)}"