Repository navigation
Feature request: first-class milestone support (opt-in, backward-compatible) #8
Description
Summary
Add a first-class milestone dimension to tasks, so work rolls up to "how close is milestone M<n>". Requested + co-sponsored by two downstream projects independently adopting a "milestone-as-contract" process (a milestone = a north-star persona + goal + feature gates + exit criteria, in docs/milestone/M<n>.md; tasks tag their milestone and roll up). Today the only option is to overload @system= / @tags=.
Hard requirement — backward compatibility
- An existing
TASKS.mdwith no milestone data parses + behaves exactly as today (zero migration). - A task without a milestone is valid → resolves to a
defaultsentinel. Milestones are strictly opt-in; the sentinel is implicit (never written into a task line). - The sentinel name must not match an
M<n>ID (a sentinel namedm1would makeset --milestone m1ambiguous between "assign to M1" and "clear to sentinel") — the tool must reject that.
Data model
- Optional
@milestone=<id-or-alias>tag on a task line (mirrors@branch=/@pr=/@deps=). Absent ⇒ sentinel. - ID vs alias: the value may be a canonical ID (
m1) or an alias (alpha); the tool resolves aliases → IDs. Case-insensitive. - Optional
# Milestonesregistry (a section inTASKS.md) mappingID → alias → title → status— powers alias resolution + rollups + validation. Absent ⇒ freeform (any string accepted, no aliasing) — still fully backward-compatible. - Orthogonal to
@system=phase-*/sprint-*and@tags=— do not overload@system.
CLI surface
| Command | Behavior |
|---|---|
new task "…" --milestone m1 |
Assign on create. Omitted ⇒ sentinel (no tag written). |
set T-N --milestone m1 |
Assign/change. --milestone "" clears back to the sentinel. |
list --milestone m1 |
Filter (alias-resolved). --milestone default ⇒ the unassigned. No flag ⇒ all (today's behavior). |
milestone |
Rollup: per-milestone counts by status + % done (+ the milestone's own status if a registry exists). Shows default as its own bucket. |
milestone <M> |
Detail: tasks under <M> grouped by status. |
next --milestone m1 |
(optional) next actionable within a milestone. Default next unchanged. |
validate |
WARN (exit 0) on a @milestone= value not in the registry (when one exists); never hard-fail existing files. |
Acceptance criteria
- An existing
TASKS.md(no milestone data) round-trips byte-for-byte through any non-milestone command. - With a registry mapping
alpha→M1,new task --milestone alphais listed by bothlist --milestone m1andlist --milestone alpha. - A task with no
@milestone=appears underlist --milestone default+ thedefaultrollup bucket. set T-N --milestone ""removes the tag; the task returns to the sentinel bucket.milestonerollup sums correctly across ID+alias and includesdefault.- With no registry,
@milestone=anythingis accepted (freeform) and grouped by raw value. validatewarns (exit 0) on an unknown milestone when a registry exists; errors only on structural problems.
Co-sponsor deltas (from the second project's spec review — all nice-to-have)
milestone <M> --format=json— programmatic consumption (CI / agents parse rollups). ~small; worth folding into the initial impl.--milestone-registry-path <file>— some projects prefer the registry in a separate file, notTASKS.md. Marginal; can defer.- Warn on
@tags=<id>when the registry hasM<id>— a mechanical drift guard for the interim@tags=m1→ first-class@milestone=m1migration path ("no task silently orphaned").
Non-goals (this iteration)
Milestone dependencies/ordering, dates, or burndown. Auto-deriving milestone status from task completion (the milestone doc's exit criteria are authoritative; the rollup is informational).
Co-sponsored feature request; two downstream projects have a full requirements spec + a reconciliation behind this. Happy to open a PR against a chosen design.
Activity
budhash commentedon Jul 13, 2026
Shipped in v1.1.0 (PR #7), with parse hardening in v1.1.1 (#9/#10):
@milestone=tag, optional# Milestonesregistry with alias resolution,new/set/list/next --milestone,milestonerollup/detail/--table,migrate-tags-to-milestone, and validate warnings. See https://github.com/budhash/tasks/releases/tag/v1.1.0 — closing. (The shadow-line tagging bug found in the field is tracked separately in #17.)