skip to content

The milestone pattern

One milestone: brief the environment, plan the brief into task files under `sprints/`, author and ground the gate, build each task through the included `sprint` pipeline, then review the milestone as a whole. Called by `build` once per milestone brief.

milestone — one milestone, planned, gated, built, and reviewed

build's for body build_milestone calls this once per milestone brief; it is not run on its own.

Every step's outputs resolve under this invocation's own state root, so two milestones cannot collide on the path sprints.

milestone
[header]
pattern_language_compatibility = "3"
entry = "milestone"
include = ["sprint.toml", "troubleshoot.toml", "merge.toml"]
merge = "merge"
on_stop = "write_handover"
description = """
One milestone: brief the environment, plan the brief into task files under `sprints/`, author and ground the gate, build
each task through the included `sprint` pipeline, then review the milestone as a whole. Called by
`build` once per milestone brief.
"""

[patterns.milestone]

[[patterns.milestone.parameters]]
name = "plan_source"
kind = "path"
description = "The milestone brief the environment briefer, the task planner, and the gate author read."

All three are passed whole into sprint; review_prompt also runs milestone_review and troubleshoot_prompt the troubleshoot pass below. A caller that wants its own names each in full.

milestone
[[patterns.milestone.parameters]]
name = "execute_prompt"
kind = "prompt-id"
default = "execute"
description = "The task executor's prompt."

[[patterns.milestone.parameters]]
name = "review_prompt"
kind = "prompt-id"
default = "review"
description = "The task reviewer's prompt."

[[patterns.milestone.parameters]]
name = "troubleshoot_prompt"
kind = "prompt-id"
default = "troubleshoot"
description = "The troubleshoot pass's prompt."

[[patterns.milestone.parameters]]
name = "merge_attempt_ceiling"
kind = "text"
default = "2"
description = "The finish-time merge repair ceiling passed to the bundled merge pattern."

[[patterns.milestone.parameters]]
name = "protected_check"
kind = "path"
default = ".gantry/no-protected-check"
description = "An optional record-path check an enclosing recursive goal run freezes."

[[patterns.milestone.parameters]]
name = "attempt_ceiling"
kind = "text"
default = "unbounded"
description = "The attempt ceiling passed to each sprint task."

Planning the milestone

environment.md is prepended to every later agent's prompt, so a missing one costs facts rather than correctness: a failed session routes to nothing, the engine-provided identity pattern, and the milestone carries on.

milestone
[[patterns.milestone.steps]]
name = "brief_environment"
title = "Write Environment Brief"
type = "agent"
stage = "environment-build"
prompt = "write-environment"
inputs = ["{{plan_source}}"]
protected = ["{{protected_check}}"]
on_plan_change = "review_plan_change"

[[patterns.milestone.steps]]
if = { brief_environment = "failed" }
then = "nothing"

The ordered task files the for below iterates. An empty list runs no iterations and falls through to the milestone review. The task briefs are this step's product rather than an edit to plan files someone else owns, so an observed plan change routes to nothing.

milestone
[[patterns.milestone.steps]]
name = "plan_sprints"
title = "Decompose Milestone Brief Into Task Briefs"
type = "agent"
stage = "plan"
prompt = "write-sprints"
inputs = ["{{plan_source}}"]
protected = ["{{protected_check}}"]
on_plan_change = "nothing"
outputs = [
  { name = "sprints", path = "sprints/" },
]

The gate every task in this milestone must pass. An agent that writes no bin/gate leaves gate_script unbound, and baseline below fails resolving its command and stops the run.

milestone
[[patterns.milestone.steps]]
name = "author_gate"
title = "Write Task Gate Command"
type = "agent"
stage = "gate-build"
prompt = "write-milestone-gate"
inputs = ["{{plan_source}}"]
read_only = true
outputs = [
  { name = "gate_script", path = "bin/gate" },
]

The fresh gate proved on the clean tree. Red means the gate is wrong or the tree was already broken, and no task may build on either; a caller that wants no baseline declares its own milestone-level pattern without this step.

milestone
[[patterns.milestone.steps]]
name = "baseline"
title = "Testing"
type = "gate"
command = "{{gate_script}}"

[[patterns.milestone.steps]]
if = { baseline = "red" }
then = "stop_baseline_red"

The tasks

The inner of the two nested fors; build.toml holds the outer one. The list is re-enumerated before every iteration, so a task brief a review inserted is built too; done-ness comes from the ledger, so a finished task is not retaken.

milestone
[[patterns.milestone.steps]]
name = "run_sprints"
type = "for"
list = { directory = "{{sprints}}" }
body = "sprint"

[patterns.milestone.steps.parameters]
execute_prompt = "{{execute_prompt}}"
review_prompt = "{{review_prompt}}"
troubleshoot_prompt = "{{troubleshoot_prompt}}"
declared_gate_command = "{{gate_script}}"
protected_check = "{{protected_check}}"
attempt_ceiling = "{{attempt_ceiling}}"

[[patterns.milestone.steps]]
if = { run_sprints = "failed" }
then = "stop_sprints_absent"

The milestone review

The reviewer judges the built milestone and may edit the tree. The for above has ended, so diff = "iteration-start" resolves to the start of build's iteration: the reviewer reads the whole milestone rather than the last task's changes.

milestone
[[patterns.milestone.steps]]
name = "milestone_review"
title = "Review Built Milestone"
type = "agent"
stage = "review"
summarize = true
prompt = "{{review_prompt}}"
diff = "iteration-start"
protected = ["PROGRESS.md", ".preamble.sys.md", "bin", "{{protected_check}}"]
confine = true
on_plan_change = "review_plan_change"
outputs = [
  { name = "milestone_verdict", path = "state/milestone-verdict.txt", values = ["complete", "blocked"] },
  { name = "milestone_note", path = "state/milestone-note.md" },
]

The one thing a milestone review judges that a task review does not.

milestone
[patterns.milestone.steps.text]
REVIEW_SUBJECT = "whole milestone"
EXTRA_JUDGMENT = """
Beyond correctness, judge the architecture: responsibilities and interfaces, dependencies,
maintainability, and whether the structure will suffice for the later, not-yet-built milestone
briefs.
"""

[[patterns.milestone.steps]]
if = "milestone_verdict"
then = { complete = "verify_milestone_review_edits", blocked = "stop_milestone_blocked" }
else = "stop_milestone_verdict_absent"

The reviewer's own edits

Every task passed this gate before the reviewer touched the tree, so this gate asks only about the review's own edits. One troubleshoot pass repairs and the gate decides again; a troubleshoot pass that cannot verify a repair ends the milestone.

milestone
[[patterns.verify_milestone_review_edits.steps]]
name = "milestone_review_gate"
title = "Testing"
type = "gate"
command = "{{gate_script}}"

[[patterns.verify_milestone_review_edits.steps]]
if = { milestone_review_gate = "red" }
then = "route_milestone_review_red_gate"

[[patterns.route_milestone_review_red_gate.steps]]
name = "milestone_review_gate_recovery"
type = "call"
pattern = "troubleshoot"

[patterns.route_milestone_review_red_gate.steps.parameters]
troubleshoot_prompt = "{{troubleshoot_prompt}}"
declared_gate_command = "{{gate_script}}"
protected_check = "{{protected_check}}"
position = """
You are repairing a red gate that a milestone review caused. Every task in this milestone passed
this gate before the reviewer edited the tree, so the reviewer's own edits are the sole cause. Fix
them forward if the edits carry a genuine finding — a strengthened check, a corrected assertion, a
real defect surfaced. If they are cosmetic and you cannot verify a repair, say so and stop rather
than half-fixing: this milestone ends either way, and the handover is what the next session reads.
"""

[[patterns.route_milestone_review_red_gate.steps]]
name = "repaired_milestone_review_gate"
title = "Testing"
type = "gate"
command = "{{gate_script}}"

[[patterns.route_milestone_review_red_gate.steps]]
if = { repaired_milestone_review_gate = "red" }
then = "stop_repaired_milestone_review_gate"

[[patterns.stop_repaired_milestone_review_gate.steps]]
type = "stop"
note = "The milestone reviewer's own edits left the gate red and the troubleshoot pass could not verify a fix; the reviewer's note is at state/milestone-note.md and the troubleshoot pass's is at state/troubleshoot-note.md."

The endings

A completed milestone falls off the end of this pattern and the enclosing for records it done. Everything else is a routed stop carrying one note.

milestone
[[patterns.stop_baseline_red.steps]]
type = "stop"
note = "The milestone's declared gate is red on a clean tree, so either the gate is wrong or the tree was already broken."

[[patterns.stop_milestone_blocked.steps]]
type = "stop"
note = "The milestone reviewer's verdict was blocked; its note is at state/milestone-note.md."

[[patterns.stop_milestone_verdict_absent.steps]]
type = "stop"
note = "The milestone reviewer did not write state/milestone-verdict.txt, so the milestone cannot be accepted."

[[patterns.stop_sprints_absent.steps]]
type = "stop"
note = "The task planner did not write the sprints directory, so the milestone cannot enumerate work."