Skip to main content
jg-plans

Create → inspect → update → revise

See a plan evolve.

Follow one plan through actual library operations. Then explore the document cases: a small plan, optional milestones, custom metadata and partial deletion.

Create

Start with one readable file.

Numbered acceptance criteria give every requirement a stable ID from the first draft.

01 Markdown source

plan.md
---
id: 1792612920_search-feedback-criteria
created_at: 2026-10-21T20:02:00Z
updated_at: 2026-10-21T20:02:00Z
revision: 1
status: pending
protocol: "0.2"
priority: medium
repositories:
  - example/search
error_codes:
  - repository: example/search
    registry: docs/errors.md
    codes:
      - 4100
      - SEARCH_FILTER_INVALID
---
# Search feedback

Explain empty search results and give people a useful next action.

## Acceptance criteria

- AC-01: Empty search results explain why nothing matched.
- AC-02: The empty state offers one next action, such as clearing the active filters.
- AC-03: The explanation and the action work with a keyboard and a screen reader.

02 Complete API result

createPlan(options)
JSON · complete result
{
  "directory": "jg-plans/search-feedback",
  "plan": {
    "name": "search-feedback-criteria",
    "source": "---\nid: 1792612920_search-feedback-criteria\ncreated_at: 2026-10-21T20:02:00Z\nupdated_at: 2026-10-21T20:02:00Z\nrevision: 1\nstatus: pending\nprotocol: \"0.2\"\npriority: medium\nrepositories:\n  - example/search\nerror_codes:\n  - repository: example/search\n    registry: docs/errors.md\n    codes:\n      - 4100\n      - SEARCH_FILTER_INVALID\n---\n# Search feedback\n\nExplain empty search results and give people a useful next action.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action, such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n",
    "body": "# Search feedback\n\nExplain empty search results and give people a useful next action.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action, such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n",
    "frontmatter": {
      "start": 0,
      "contentStart": 4,
      "contentEnd": 331,
      "end": 335,
      "closed": true
    },
    "rawMetadata": {
      "id": "1792612920_search-feedback-criteria",
      "created_at": "2026-10-21T20:02:00Z",
      "updated_at": "2026-10-21T20:02:00Z",
      "revision": 1,
      "status": "pending",
      "protocol": "0.2",
      "priority": "medium",
      "repositories": [
        "example/search"
      ],
      "error_codes": [
        {
          "repository": "example/search",
          "registry": "docs/errors.md",
          "codes": [
            4100,
            "SEARCH_FILTER_INVALID"
          ]
        }
      ]
    },
    "metadata": {
      "id": "1792612920_search-feedback-criteria",
      "created_at": "2026-10-21T20:02:00Z",
      "updated_at": "2026-10-21T20:02:00Z",
      "revision": 1,
      "status": "pending",
      "protocol": "0.2",
      "priority": "medium",
      "repositories": [
        "example/search"
      ],
      "error_codes": [
        {
          "repository": "example/search",
          "registry": "docs/errors.md",
          "codes": [
            4100,
            "SEARCH_FILTER_INVALID"
          ]
        }
      ]
    },
    "preamble": {
      "start": 0,
      "end": 422
    },
    "sections": [
      {
        "title": "Acceptance criteria",
        "heading": {
          "start": 422,
          "end": 445
        },
        "body": {
          "start": 445,
          "end": 673
        }
      }
    ],
    "protocol": "0.2",
    "criteria": [
      {
        "id": "AC-01",
        "idText": "AC-01",
        "text": "Empty search results explain why nothing matched.",
        "location": {
          "offset": 448,
          "line": 24,
          "column": 3
        },
        "range": {
          "start": 446,
          "end": 504
        }
      },
      {
        "id": "AC-02",
        "idText": "AC-02",
        "text": "The empty state offers one next action, such as clearing the active filters.",
        "location": {
          "offset": 507,
          "line": 25,
          "column": 3
        },
        "range": {
          "start": 505,
          "end": 590
        }
      },
      {
        "id": "AC-03",
        "idText": "AC-03",
        "text": "The explanation and the action work with a keyboard and a screen reader.",
        "location": {
          "offset": 593,
          "line": 26,
          "column": 3
        },
        "range": {
          "start": 591,
          "end": 672
        }
      }
    ],
    "diagnostics": [],
    "sha256": "946816c6f612bb4f868842168bcfd802637e84a40d77c238904afb0f9ba3cbbf"
  },
  "milestones": null,
  "diagnostics": []
}
Consumer-derived summary
Consumer-derived summary · not an API return
{
  "plan": "readable",
  "milestones": "missing",
  "revision": 1,
  "status": "pending",
  "criteria": [
    "AC-01",
    "AC-02",
    "AC-03"
  ]
}
Public API call · excerpt
Selected API call · inputs from this example
const created = await createPlan({
  root: './jg-plans',
  slug: 'search-feedback',
  body, // the Markdown body shown below
  metadata, // the displayed example metadata, including protocol: '0.2'
});

Inspect

Read what is actually there.

One selected directory returns metadata, criteria and diagnostics without recreating anything.

01 Markdown source

plan.md
---
id: 1792612920_search-feedback-criteria
created_at: 2026-10-21T20:02:00Z
updated_at: 2026-10-21T20:02:00Z
revision: 1
status: pending
protocol: "0.2"
priority: medium
repositories:
  - example/search
error_codes:
  - repository: example/search
    registry: docs/errors.md
    codes:
      - 4100
      - SEARCH_FILTER_INVALID
---
# Search feedback

Explain empty search results and give people a useful next action.

## Acceptance criteria

- AC-01: Empty search results explain why nothing matched.
- AC-02: The empty state offers one next action, such as clearing the active filters.
- AC-03: The explanation and the action work with a keyboard and a screen reader.

02 Complete API result

inspectPlan(directory)
JSON · complete result
{
  "directory": "jg-plans/search-feedback",
  "plan": {
    "state": "readable",
    "path": "jg-plans/search-feedback/plan.md",
    "sha256": "946816c6f612bb4f868842168bcfd802637e84a40d77c238904afb0f9ba3cbbf",
    "value": {
      "name": "search-feedback-criteria",
      "source": "---\nid: 1792612920_search-feedback-criteria\ncreated_at: 2026-10-21T20:02:00Z\nupdated_at: 2026-10-21T20:02:00Z\nrevision: 1\nstatus: pending\nprotocol: \"0.2\"\npriority: medium\nrepositories:\n  - example/search\nerror_codes:\n  - repository: example/search\n    registry: docs/errors.md\n    codes:\n      - 4100\n      - SEARCH_FILTER_INVALID\n---\n# Search feedback\n\nExplain empty search results and give people a useful next action.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action, such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n",
      "body": "# Search feedback\n\nExplain empty search results and give people a useful next action.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action, such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n",
      "frontmatter": {
        "start": 0,
        "contentStart": 4,
        "contentEnd": 331,
        "end": 335,
        "closed": true
      },
      "rawMetadata": {
        "id": "1792612920_search-feedback-criteria",
        "created_at": "2026-10-21T20:02:00Z",
        "updated_at": "2026-10-21T20:02:00Z",
        "revision": 1,
        "status": "pending",
        "protocol": "0.2",
        "priority": "medium",
        "repositories": [
          "example/search"
        ],
        "error_codes": [
          {
            "repository": "example/search",
            "registry": "docs/errors.md",
            "codes": [
              4100,
              "SEARCH_FILTER_INVALID"
            ]
          }
        ]
      },
      "metadata": {
        "id": "1792612920_search-feedback-criteria",
        "created_at": "2026-10-21T20:02:00Z",
        "updated_at": "2026-10-21T20:02:00Z",
        "revision": 1,
        "status": "pending",
        "protocol": "0.2",
        "priority": "medium",
        "repositories": [
          "example/search"
        ],
        "error_codes": [
          {
            "repository": "example/search",
            "registry": "docs/errors.md",
            "codes": [
              4100,
              "SEARCH_FILTER_INVALID"
            ]
          }
        ]
      },
      "preamble": {
        "start": 0,
        "end": 422
      },
      "sections": [
        {
          "title": "Acceptance criteria",
          "heading": {
            "start": 422,
            "end": 445
          },
          "body": {
            "start": 445,
            "end": 673
          }
        }
      ],
      "protocol": "0.2",
      "criteria": [
        {
          "id": "AC-01",
          "idText": "AC-01",
          "text": "Empty search results explain why nothing matched.",
          "location": {
            "offset": 448,
            "line": 24,
            "column": 3
          },
          "range": {
            "start": 446,
            "end": 504
          }
        },
        {
          "id": "AC-02",
          "idText": "AC-02",
          "text": "The empty state offers one next action, such as clearing the active filters.",
          "location": {
            "offset": 507,
            "line": 25,
            "column": 3
          },
          "range": {
            "start": 505,
            "end": 590
          }
        },
        {
          "id": "AC-03",
          "idText": "AC-03",
          "text": "The explanation and the action work with a keyboard and a screen reader.",
          "location": {
            "offset": 593,
            "line": 26,
            "column": 3
          },
          "range": {
            "start": 591,
            "end": 672
          }
        }
      ],
      "diagnostics": []
    }
  },
  "milestones": {
    "state": "missing",
    "path": "jg-plans/search-feedback/milestones.md"
  },
  "criteria": {
    "protocol": "0.2",
    "criteria": [
      {
        "id": "AC-01",
        "text": "Empty search results explain why nothing matched.",
        "location": {
          "offset": 448,
          "line": 24,
          "column": 3
        },
        "milestones": [],
        "progress": "pending"
      },
      {
        "id": "AC-02",
        "text": "The empty state offers one next action, such as clearing the active filters.",
        "location": {
          "offset": 507,
          "line": 25,
          "column": 3
        },
        "milestones": [],
        "progress": "pending"
      },
      {
        "id": "AC-03",
        "text": "The explanation and the action work with a keyboard and a screen reader.",
        "location": {
          "offset": 593,
          "line": 26,
          "column": 3
        },
        "milestones": [],
        "progress": "pending"
      }
    ],
    "diagnostics": []
  },
  "diagnostics": [
    {
      "document": "milestones",
      "code": "MISSING_MILESTONES",
      "severity": "info",
      "message": "The optional milestone file is absent."
    }
  ]
}
Consumer-derived summary
Consumer-derived summary · not an API return
{
  "plan": "readable",
  "milestones": "missing",
  "metadata": {
    "id": "1792612920_search-feedback-criteria",
    "created_at": "2026-10-21T20:02:00Z",
    "updated_at": "2026-10-21T20:02:00Z",
    "revision": 1,
    "status": "pending",
    "protocol": "0.2",
    "priority": "medium",
    "repositories": [
      "example/search"
    ],
    "error_codes": [
      {
        "repository": "example/search",
        "registry": "docs/errors.md",
        "codes": [
          4100,
          "SEARCH_FILTER_INVALID"
        ]
      }
    ]
  },
  "criteria": [
    {
      "id": "AC-01",
      "progress": "pending"
    },
    {
      "id": "AC-02",
      "progress": "pending"
    },
    {
      "id": "AC-03",
      "progress": "pending"
    }
  ]
}
Public API call · excerpt
Selected API call · inputs from this example
const observed = await inspectPlan(created.directory);

Update

Make an explicit, guarded edit.

Milestones name the criteria they deliver, and each criterion's progress follows their status.

01 Markdown source

plan.md
---
id: 1792612920_search-feedback-criteria
created_at: 2026-10-21T20:02:00Z
updated_at: "2026-10-21T20:04:00Z"
revision: 1
status: "in progress"
protocol: "0.2"
priority: medium
repositories:
  - example/search
error_codes:
  - repository: example/search
    registry: docs/errors.md
    codes:
      - 4100
      - SEARCH_FILTER_INVALID
---
# Search feedback

Explain empty search results and give people a useful next action.

## Acceptance criteria

- AC-01: Empty search results explain why nothing matched.
- AC-02: The empty state offers one next action, such as clearing the active filters.
- AC-03: The explanation and the action work with a keyboard and a screen reader.

02 Complete API result

inspectPlan(directory)
JSON · complete result
{
  "directory": "jg-plans/search-feedback",
  "plan": {
    "state": "readable",
    "path": "jg-plans/search-feedback/plan.md",
    "sha256": "98f8d72a31336f3c7f0f98b709f8789d300f9047eb10195beabcbb52d57af116",
    "value": {
      "name": "search-feedback-criteria",
      "source": "---\nid: 1792612920_search-feedback-criteria\ncreated_at: 2026-10-21T20:02:00Z\nupdated_at: \"2026-10-21T20:04:00Z\"\nrevision: 1\nstatus: \"in progress\"\nprotocol: \"0.2\"\npriority: medium\nrepositories:\n  - example/search\nerror_codes:\n  - repository: example/search\n    registry: docs/errors.md\n    codes:\n      - 4100\n      - SEARCH_FILTER_INVALID\n---\n# Search feedback\n\nExplain empty search results and give people a useful next action.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action, such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n",
      "body": "# Search feedback\n\nExplain empty search results and give people a useful next action.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action, such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n",
      "frontmatter": {
        "start": 0,
        "contentStart": 4,
        "contentEnd": 339,
        "end": 343,
        "closed": true
      },
      "rawMetadata": {
        "id": "1792612920_search-feedback-criteria",
        "created_at": "2026-10-21T20:02:00Z",
        "updated_at": "2026-10-21T20:04:00Z",
        "revision": 1,
        "status": "in progress",
        "protocol": "0.2",
        "priority": "medium",
        "repositories": [
          "example/search"
        ],
        "error_codes": [
          {
            "repository": "example/search",
            "registry": "docs/errors.md",
            "codes": [
              4100,
              "SEARCH_FILTER_INVALID"
            ]
          }
        ]
      },
      "metadata": {
        "id": "1792612920_search-feedback-criteria",
        "created_at": "2026-10-21T20:02:00Z",
        "updated_at": "2026-10-21T20:04:00Z",
        "revision": 1,
        "status": "in progress",
        "protocol": "0.2",
        "priority": "medium",
        "repositories": [
          "example/search"
        ],
        "error_codes": [
          {
            "repository": "example/search",
            "registry": "docs/errors.md",
            "codes": [
              4100,
              "SEARCH_FILTER_INVALID"
            ]
          }
        ]
      },
      "preamble": {
        "start": 0,
        "end": 430
      },
      "sections": [
        {
          "title": "Acceptance criteria",
          "heading": {
            "start": 430,
            "end": 453
          },
          "body": {
            "start": 453,
            "end": 681
          }
        }
      ],
      "protocol": "0.2",
      "criteria": [
        {
          "id": "AC-01",
          "idText": "AC-01",
          "text": "Empty search results explain why nothing matched.",
          "location": {
            "offset": 456,
            "line": 24,
            "column": 3
          },
          "range": {
            "start": 454,
            "end": 512
          }
        },
        {
          "id": "AC-02",
          "idText": "AC-02",
          "text": "The empty state offers one next action, such as clearing the active filters.",
          "location": {
            "offset": 515,
            "line": 25,
            "column": 3
          },
          "range": {
            "start": 513,
            "end": 598
          }
        },
        {
          "id": "AC-03",
          "idText": "AC-03",
          "text": "The explanation and the action work with a keyboard and a screen reader.",
          "location": {
            "offset": 601,
            "line": 26,
            "column": 3
          },
          "range": {
            "start": 599,
            "end": 680
          }
        }
      ],
      "diagnostics": []
    }
  },
  "milestones": {
    "state": "readable",
    "path": "jg-plans/search-feedback/milestones.md",
    "sha256": "46d4f0bd33d023830f4b9fc772cdd817b46d239c23166c3016fd0d08294f307a",
    "value": {
      "source": "---\njg_skills:\n  plan_id: \"1792612920_search-feedback-criteria\"\n  plan_revision: 1\n  plan_content_sha256: 21da41286dc3d021cdc6adddef1283d7affe70b92832824bd00244ff1b9058d8\n---\n\n## Milestone 1: Explain empty results\n**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n## Milestone 2: Offer a next action\n**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
      "body": "\n## Milestone 1: Explain empty results\n**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n## Milestone 2: Offer a next action\n**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
      "frontmatter": {
        "start": 0,
        "contentStart": 4,
        "contentEnd": 171,
        "end": 175,
        "closed": true
      },
      "rawMetadata": {
        "jg_skills": {
          "plan_id": "1792612920_search-feedback-criteria",
          "plan_revision": 1,
          "plan_content_sha256": "21da41286dc3d021cdc6adddef1283d7affe70b92832824bd00244ff1b9058d8"
        }
      },
      "preamble": {
        "start": 0,
        "end": 176
      },
      "sections": [
        {
          "title": "Milestone 1: Explain empty results",
          "heading": {
            "start": 176,
            "end": 214
          },
          "body": {
            "start": 214,
            "end": 392
          }
        },
        {
          "title": "Milestone 2: Offer a next action",
          "heading": {
            "start": 392,
            "end": 428
          },
          "body": {
            "start": 428,
            "end": 627
          }
        }
      ],
      "overviewTables": [],
      "milestones": [
        {
          "ordinal": 1,
          "ordinalText": "1",
          "title": "Explain empty results",
          "status": "done",
          "id": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34",
          "location": {
            "offset": 176,
            "line": 8,
            "column": 1
          },
          "headingEnd": 214,
          "end": 392,
          "body": "**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n",
          "statusMarkers": [
            {
              "value": "done",
              "location": {
                "offset": 214,
                "line": 9,
                "column": 1
              },
              "valueStart": 226,
              "valueEnd": 230,
              "lineStart": 214,
              "lineEnd": 231
            }
          ],
          "idMarkers": [
            {
              "value": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34",
              "location": {
                "offset": 231,
                "line": 10,
                "column": 1
              },
              "valueStart": 249,
              "valueEnd": 285,
              "lineStart": 231,
              "lineEnd": 286
            }
          ],
          "criteria": [
            "AC-01"
          ],
          "criteriaMarkers": [
            {
              "value": "AC-01",
              "location": {
                "offset": 286,
                "line": 11,
                "column": 1
              },
              "valueStart": 311,
              "valueEnd": 316,
              "lineStart": 286,
              "lineEnd": 317
            }
          ]
        },
        {
          "ordinal": 2,
          "ordinalText": "2",
          "title": "Offer a next action",
          "status": "in progress",
          "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15",
          "location": {
            "offset": 392,
            "line": 15,
            "column": 1
          },
          "headingEnd": 428,
          "end": 627,
          "body": "**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
          "statusMarkers": [
            {
              "value": "in progress",
              "location": {
                "offset": 428,
                "line": 16,
                "column": 1
              },
              "valueStart": 440,
              "valueEnd": 451,
              "lineStart": 428,
              "lineEnd": 452
            }
          ],
          "idMarkers": [
            {
              "value": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15",
              "location": {
                "offset": 452,
                "line": 17,
                "column": 1
              },
              "valueStart": 470,
              "valueEnd": 506,
              "lineStart": 452,
              "lineEnd": 507
            }
          ],
          "criteria": [
            "AC-02",
            "AC-03"
          ],
          "criteriaMarkers": [
            {
              "value": "AC-02, AC-03",
              "location": {
                "offset": 507,
                "line": 18,
                "column": 1
              },
              "valueStart": 532,
              "valueEnd": 544,
              "lineStart": 507,
              "lineEnd": 545
            }
          ]
        }
      ],
      "overview": [],
      "overviewPresent": false,
      "diagnostics": []
    }
  },
  "criteria": {
    "protocol": "0.2",
    "criteria": [
      {
        "id": "AC-01",
        "text": "Empty search results explain why nothing matched.",
        "location": {
          "offset": 456,
          "line": 24,
          "column": 3
        },
        "milestones": [
          {
            "ordinal": 1,
            "id": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34"
          }
        ],
        "progress": "done"
      },
      {
        "id": "AC-02",
        "text": "The empty state offers one next action, such as clearing the active filters.",
        "location": {
          "offset": 515,
          "line": 25,
          "column": 3
        },
        "milestones": [
          {
            "ordinal": 2,
            "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15"
          }
        ],
        "progress": "in progress"
      },
      {
        "id": "AC-03",
        "text": "The explanation and the action work with a keyboard and a screen reader.",
        "location": {
          "offset": 601,
          "line": 26,
          "column": 3
        },
        "milestones": [
          {
            "ordinal": 2,
            "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15"
          }
        ],
        "progress": "in progress"
      }
    ],
    "diagnostics": []
  },
  "diagnostics": []
}
  • AC-01done
  • AC-02in progress
  • AC-03in progress
Mutation and check results
updatePlan(directory, patch) · complete result
{
  "directory": "jg-plans/search-feedback",
  "document": "plan",
  "changed": true,
  "sha256": "98f8d72a31336f3c7f0f98b709f8789d300f9047eb10195beabcbb52d57af116",
  "diagnostics": [],
  "assignedMilestoneIds": []
}
writePlanDocument(directory, input) · complete result
{
  "directory": "jg-plans/search-feedback",
  "document": "milestones",
  "changed": true,
  "sha256": "46d4f0bd33d023830f4b9fc772cdd817b46d239c23166c3016fd0d08294f307a",
  "diagnostics": [],
  "assignedMilestoneIds": []
}
Consumer-derived summary
Consumer-derived summary · not an API return
{
  "revision": 1,
  "status": "in progress",
  "milestones": [
    {
      "id": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34",
      "title": "Explain empty results",
      "status": "done"
    },
    {
      "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15",
      "title": "Offer a next action",
      "status": "in progress"
    }
  ],
  "criteria": [
    {
      "id": "AC-01",
      "milestones": [
        1
      ],
      "progress": "done"
    },
    {
      "id": "AC-02",
      "milestones": [
        2
      ],
      "progress": "in progress"
    },
    {
      "id": "AC-03",
      "milestones": [
        2
      ],
      "progress": "in progress"
    }
  ],
  "binding": "current"
}
Public API call · excerpt
Selected API call · inputs from this example
if (observed.plan.state === 'readable') {
  await updatePlan(directory, {
    document: 'plan',
    expectedSha256: observed.plan.sha256,
    set: { status: 'in progress', updated_at },
  });
}
// Add the explicitly prepared milestone source as a separate guarded write.
await writePlanDocument(directory, {
  document: 'milestones',
  expectedSha256: null,
  source: milestoneSource,
});
const current = await inspectPlan(directory);

Revise

Change the intent. Keep the context.

A new criterion stays flagged by check until a milestone delivers it; existing IDs stay byte-for-byte.

Before · revision 1After · revision 2
---id: 1792612920_search-feedback-criteriacreated_at: 2026-10-21T20:02:00Zupdated_at: "2026-10-21T20:04:00Z"Removed line: revision: 1Added line: revision: 2status: "in progress"protocol: "0.2"priority: mediumrepositories:  - example/searcherror_codes:  - repository: example/search    registry: docs/errors.md    codes:      - 4100      - SEARCH_FILTER_INVALID---# Search feedback Explain empty search results and give people a useful next action. ## Acceptance criteria - AC-01: Empty search results explain why nothing matched.- AC-02: The empty state offers one next action, such as clearing the active filters.- AC-03: The explanation and the action work with a keyboard and a screen reader.Added line: - AC-04: Search suggests spelling corrections.

check · plan.md line 27

UNASSIGNED_CRITERIONAC-04

No milestone delivers AC-04 until the next breakdown.

Milestones · exact original bytes

  • Explain empty resultsdone

    3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34

  • Offer a next actionin progress

    8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15

Skills binding · stale after revision

Done markers stay; skills wait for a fresh breakdown before executing.

Actual revision observation
Complete revised plan.md
---
id: 1792612920_search-feedback-criteria
created_at: 2026-10-21T20:02:00Z
updated_at: "2026-10-21T20:04:00Z"
revision: 2
status: "in progress"
protocol: "0.2"
priority: medium
repositories:
  - example/search
error_codes:
  - repository: example/search
    registry: docs/errors.md
    codes:
      - 4100
      - SEARCH_FILTER_INVALID
---
# Search feedback

Explain empty search results and give people a useful next action.

## Acceptance criteria

- AC-01: Empty search results explain why nothing matched.
- AC-02: The empty state offers one next action, such as clearing the active filters.
- AC-03: The explanation and the action work with a keyboard and a screen reader.
- AC-04: Search suggests spelling corrections.

inspectPlan(directory) · complete result

JSON · complete result
{
  "directory": "jg-plans/search-feedback",
  "plan": {
    "state": "readable",
    "path": "jg-plans/search-feedback/plan.md",
    "sha256": "99cbfac6e98dcfe04052fef6a5031e586464f8be578d0a491691158b8c5beb4a",
    "value": {
      "name": "search-feedback-criteria",
      "source": "---\nid: 1792612920_search-feedback-criteria\ncreated_at: 2026-10-21T20:02:00Z\nupdated_at: \"2026-10-21T20:04:00Z\"\nrevision: 2\nstatus: \"in progress\"\nprotocol: \"0.2\"\npriority: medium\nrepositories:\n  - example/search\nerror_codes:\n  - repository: example/search\n    registry: docs/errors.md\n    codes:\n      - 4100\n      - SEARCH_FILTER_INVALID\n---\n# Search feedback\n\nExplain empty search results and give people a useful next action.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action, such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n- AC-04: Search suggests spelling corrections.\n",
      "body": "# Search feedback\n\nExplain empty search results and give people a useful next action.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action, such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n- AC-04: Search suggests spelling corrections.\n",
      "frontmatter": {
        "start": 0,
        "contentStart": 4,
        "contentEnd": 339,
        "end": 343,
        "closed": true
      },
      "rawMetadata": {
        "id": "1792612920_search-feedback-criteria",
        "created_at": "2026-10-21T20:02:00Z",
        "updated_at": "2026-10-21T20:04:00Z",
        "revision": 2,
        "status": "in progress",
        "protocol": "0.2",
        "priority": "medium",
        "repositories": [
          "example/search"
        ],
        "error_codes": [
          {
            "repository": "example/search",
            "registry": "docs/errors.md",
            "codes": [
              4100,
              "SEARCH_FILTER_INVALID"
            ]
          }
        ]
      },
      "metadata": {
        "id": "1792612920_search-feedback-criteria",
        "created_at": "2026-10-21T20:02:00Z",
        "updated_at": "2026-10-21T20:04:00Z",
        "revision": 2,
        "status": "in progress",
        "protocol": "0.2",
        "priority": "medium",
        "repositories": [
          "example/search"
        ],
        "error_codes": [
          {
            "repository": "example/search",
            "registry": "docs/errors.md",
            "codes": [
              4100,
              "SEARCH_FILTER_INVALID"
            ]
          }
        ]
      },
      "preamble": {
        "start": 0,
        "end": 430
      },
      "sections": [
        {
          "title": "Acceptance criteria",
          "heading": {
            "start": 430,
            "end": 453
          },
          "body": {
            "start": 453,
            "end": 728
          }
        }
      ],
      "protocol": "0.2",
      "criteria": [
        {
          "id": "AC-01",
          "idText": "AC-01",
          "text": "Empty search results explain why nothing matched.",
          "location": {
            "offset": 456,
            "line": 24,
            "column": 3
          },
          "range": {
            "start": 454,
            "end": 512
          }
        },
        {
          "id": "AC-02",
          "idText": "AC-02",
          "text": "The empty state offers one next action, such as clearing the active filters.",
          "location": {
            "offset": 515,
            "line": 25,
            "column": 3
          },
          "range": {
            "start": 513,
            "end": 598
          }
        },
        {
          "id": "AC-03",
          "idText": "AC-03",
          "text": "The explanation and the action work with a keyboard and a screen reader.",
          "location": {
            "offset": 601,
            "line": 26,
            "column": 3
          },
          "range": {
            "start": 599,
            "end": 680
          }
        },
        {
          "id": "AC-04",
          "idText": "AC-04",
          "text": "Search suggests spelling corrections.",
          "location": {
            "offset": 683,
            "line": 27,
            "column": 3
          },
          "range": {
            "start": 681,
            "end": 727
          }
        }
      ],
      "diagnostics": []
    }
  },
  "milestones": {
    "state": "readable",
    "path": "jg-plans/search-feedback/milestones.md",
    "sha256": "46d4f0bd33d023830f4b9fc772cdd817b46d239c23166c3016fd0d08294f307a",
    "value": {
      "source": "---\njg_skills:\n  plan_id: \"1792612920_search-feedback-criteria\"\n  plan_revision: 1\n  plan_content_sha256: 21da41286dc3d021cdc6adddef1283d7affe70b92832824bd00244ff1b9058d8\n---\n\n## Milestone 1: Explain empty results\n**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n## Milestone 2: Offer a next action\n**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
      "body": "\n## Milestone 1: Explain empty results\n**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n## Milestone 2: Offer a next action\n**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
      "frontmatter": {
        "start": 0,
        "contentStart": 4,
        "contentEnd": 171,
        "end": 175,
        "closed": true
      },
      "rawMetadata": {
        "jg_skills": {
          "plan_id": "1792612920_search-feedback-criteria",
          "plan_revision": 1,
          "plan_content_sha256": "21da41286dc3d021cdc6adddef1283d7affe70b92832824bd00244ff1b9058d8"
        }
      },
      "preamble": {
        "start": 0,
        "end": 176
      },
      "sections": [
        {
          "title": "Milestone 1: Explain empty results",
          "heading": {
            "start": 176,
            "end": 214
          },
          "body": {
            "start": 214,
            "end": 392
          }
        },
        {
          "title": "Milestone 2: Offer a next action",
          "heading": {
            "start": 392,
            "end": 428
          },
          "body": {
            "start": 428,
            "end": 627
          }
        }
      ],
      "overviewTables": [],
      "milestones": [
        {
          "ordinal": 1,
          "ordinalText": "1",
          "title": "Explain empty results",
          "status": "done",
          "id": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34",
          "location": {
            "offset": 176,
            "line": 8,
            "column": 1
          },
          "headingEnd": 214,
          "end": 392,
          "body": "**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n",
          "statusMarkers": [
            {
              "value": "done",
              "location": {
                "offset": 214,
                "line": 9,
                "column": 1
              },
              "valueStart": 226,
              "valueEnd": 230,
              "lineStart": 214,
              "lineEnd": 231
            }
          ],
          "idMarkers": [
            {
              "value": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34",
              "location": {
                "offset": 231,
                "line": 10,
                "column": 1
              },
              "valueStart": 249,
              "valueEnd": 285,
              "lineStart": 231,
              "lineEnd": 286
            }
          ],
          "criteria": [
            "AC-01"
          ],
          "criteriaMarkers": [
            {
              "value": "AC-01",
              "location": {
                "offset": 286,
                "line": 11,
                "column": 1
              },
              "valueStart": 311,
              "valueEnd": 316,
              "lineStart": 286,
              "lineEnd": 317
            }
          ]
        },
        {
          "ordinal": 2,
          "ordinalText": "2",
          "title": "Offer a next action",
          "status": "in progress",
          "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15",
          "location": {
            "offset": 392,
            "line": 15,
            "column": 1
          },
          "headingEnd": 428,
          "end": 627,
          "body": "**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
          "statusMarkers": [
            {
              "value": "in progress",
              "location": {
                "offset": 428,
                "line": 16,
                "column": 1
              },
              "valueStart": 440,
              "valueEnd": 451,
              "lineStart": 428,
              "lineEnd": 452
            }
          ],
          "idMarkers": [
            {
              "value": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15",
              "location": {
                "offset": 452,
                "line": 17,
                "column": 1
              },
              "valueStart": 470,
              "valueEnd": 506,
              "lineStart": 452,
              "lineEnd": 507
            }
          ],
          "criteria": [
            "AC-02",
            "AC-03"
          ],
          "criteriaMarkers": [
            {
              "value": "AC-02, AC-03",
              "location": {
                "offset": 507,
                "line": 18,
                "column": 1
              },
              "valueStart": 532,
              "valueEnd": 544,
              "lineStart": 507,
              "lineEnd": 545
            }
          ]
        }
      ],
      "overview": [],
      "overviewPresent": false,
      "diagnostics": []
    }
  },
  "criteria": {
    "protocol": "0.2",
    "criteria": [
      {
        "id": "AC-01",
        "text": "Empty search results explain why nothing matched.",
        "location": {
          "offset": 456,
          "line": 24,
          "column": 3
        },
        "milestones": [
          {
            "ordinal": 1,
            "id": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34"
          }
        ],
        "progress": "done"
      },
      {
        "id": "AC-02",
        "text": "The empty state offers one next action, such as clearing the active filters.",
        "location": {
          "offset": 515,
          "line": 25,
          "column": 3
        },
        "milestones": [
          {
            "ordinal": 2,
            "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15"
          }
        ],
        "progress": "in progress"
      },
      {
        "id": "AC-03",
        "text": "The explanation and the action work with a keyboard and a screen reader.",
        "location": {
          "offset": 601,
          "line": 26,
          "column": 3
        },
        "milestones": [
          {
            "ordinal": 2,
            "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15"
          }
        ],
        "progress": "in progress"
      },
      {
        "id": "AC-04",
        "text": "Search suggests spelling corrections.",
        "location": {
          "offset": 683,
          "line": 27,
          "column": 3
        },
        "milestones": [],
        "progress": null
      }
    ],
    "diagnostics": [
      {
        "document": "plan",
        "code": "UNASSIGNED_CRITERION",
        "message": "No milestone covers this criterion.",
        "severity": "error",
        "location": {
          "offset": 683,
          "line": 27,
          "column": 3
        }
      }
    ]
  },
  "diagnostics": [
    {
      "document": "plan",
      "code": "UNASSIGNED_CRITERION",
      "message": "No milestone covers this criterion.",
      "severity": "error",
      "location": {
        "offset": 683,
        "line": 27,
        "column": 3
      }
    }
  ]
}
Mutation and check results
writePlanDocument(directory, input) · complete result
{
  "directory": "jg-plans/search-feedback",
  "document": "plan",
  "changed": true,
  "sha256": "99cbfac6e98dcfe04052fef6a5031e586464f8be578d0a491691158b8c5beb4a",
  "diagnostics": [],
  "assignedMilestoneIds": []
}
checkPlan(documents) · complete result
{
  "conforms": false,
  "diagnostics": [
    {
      "document": "plan",
      "code": "UNASSIGNED_CRITERION",
      "message": "No milestone covers this criterion.",
      "severity": "error",
      "location": {
        "offset": 683,
        "line": 27,
        "column": 3
      }
    }
  ]
}
Consumer-derived summary
Consumer-derived summary · not an API return
{
  "revision": 2,
  "status": "in progress",
  "milestones": [
    {
      "id": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34",
      "title": "Explain empty results",
      "status": "done"
    },
    {
      "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15",
      "title": "Offer a next action",
      "status": "in progress"
    }
  ],
  "criteria": [
    {
      "id": "AC-01",
      "milestones": [
        1
      ],
      "progress": "done"
    },
    {
      "id": "AC-02",
      "milestones": [
        2
      ],
      "progress": "in progress"
    },
    {
      "id": "AC-03",
      "milestones": [
        2
      ],
      "progress": "in progress"
    },
    {
      "id": "AC-04",
      "milestones": [],
      "progress": null
    }
  ],
  "binding": "stale",
  "check": {
    "conforms": false,
    "findings": [
      {
        "code": "UNASSIGNED_CRITERION",
        "criterion": "AC-04",
        "line": 27
      }
    ]
  }
}
Public API call · excerpt
Selected API call · inputs from this example
if (current.plan.state === 'readable') {
  await writePlanDocument(directory, {
    document: 'plan',
    expectedSha256: current.plan.sha256,
    body: revisedBody,
    set: { revision: 2 },
  });
}
const revised = await inspectPlan(directory);
if (revised.plan.state === 'readable' && revised.milestones.state === 'readable') {
  const check = checkPlan({
    plan: revised.plan.value.source,
    milestones: revised.milestones.value.source,
  });
}

Complete reference-library results. Runtime directory and document-path fields are shown as jg-plans/search-feedback and its document paths. Source, body, metadata, diagnostics, IDs, and hashes are unchanged. Summaries, criterion progress, and the skills binding are consumer-derived views.

Explore the document cases.

Small plan

Small plan

Core metadata, a protocol marker, and one criterion.

Conforming example

plan.md

01 Markdown source

plan.md
---
id: 1792612800_search-feedback
created_at: 2026-10-21T20:00:00Z
updated_at: 2026-10-21T20:00:00Z
revision: 1
status: pending
protocol: "0.2"
---

# Search feedback

Explain an empty search result and suggest removing filters.

## Scope

Update the empty-state message and add a clear reset action.

## Validation

Check keyboard access, narrow layouts, and search with no matching results.

## Acceptance criteria

- AC-01: Empty search results explain the filters and offer a keyboard-accessible reset action.

02 Complete API result

parsePlan(source)
JSON · complete result
{
  "name": "search-feedback",
  "source": "---\nid: 1792612800_search-feedback\ncreated_at: 2026-10-21T20:00:00Z\nupdated_at: 2026-10-21T20:00:00Z\nrevision: 1\nstatus: pending\nprotocol: \"0.2\"\n---\n\n# Search feedback\n\nExplain an empty search result and suggest removing filters.\n\n## Scope\n\nUpdate the empty-state message and add a clear reset action.\n\n## Validation\n\nCheck keyboard access, narrow layouts, and search with no matching results.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain the filters and offer a keyboard-accessible reset action.\n",
  "body": "\n# Search feedback\n\nExplain an empty search result and suggest removing filters.\n\n## Scope\n\nUpdate the empty-state message and add a clear reset action.\n\n## Validation\n\nCheck keyboard access, narrow layouts, and search with no matching results.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain the filters and offer a keyboard-accessible reset action.\n",
  "frontmatter": {
    "start": 0,
    "contentStart": 4,
    "contentEnd": 145,
    "end": 149,
    "closed": true
  },
  "rawMetadata": {
    "id": "1792612800_search-feedback",
    "created_at": "2026-10-21T20:00:00Z",
    "updated_at": "2026-10-21T20:00:00Z",
    "revision": 1,
    "status": "pending",
    "protocol": "0.2"
  },
  "metadata": {
    "id": "1792612800_search-feedback",
    "created_at": "2026-10-21T20:00:00Z",
    "updated_at": "2026-10-21T20:00:00Z",
    "revision": 1,
    "status": "pending",
    "protocol": "0.2"
  },
  "preamble": {
    "start": 0,
    "end": 231
  },
  "sections": [
    {
      "title": "Scope",
      "heading": {
        "start": 231,
        "end": 240
      },
      "body": {
        "start": 240,
        "end": 303
      }
    },
    {
      "title": "Validation",
      "heading": {
        "start": 303,
        "end": 317
      },
      "body": {
        "start": 317,
        "end": 395
      }
    },
    {
      "title": "Acceptance criteria",
      "heading": {
        "start": 395,
        "end": 418
      },
      "body": {
        "start": 418,
        "end": 515
      }
    }
  ],
  "protocol": "0.2",
  "criteria": [
    {
      "id": "AC-01",
      "idText": "AC-01",
      "text": "Empty search results explain the filters and offer a keyboard-accessible reset action.",
      "location": {
        "offset": 421,
        "line": 24,
        "column": 3
      },
      "range": {
        "start": 419,
        "end": 514
      }
    }
  ],
  "diagnostics": []
}

With milestones

With milestones

Separate units when they make the work easier to review.

Conforming example

plan.md

01 Markdown source

plan.md
---
id: 1792612860_example-gallery
created_at: 2026-10-21T20:01:00Z
updated_at: 2026-10-21T20:02:00Z
revision: 2
status: in progress
protocol: "0.2"
---

# Example gallery

Make a small set of public examples easy to read and download.

## Approach

Start with accessible document cards, then add copy/download controls.

## Acceptance

The source remains readable without JavaScript, with keyboard-accessible controls.

## Revision history

- Revision 1: establish the gallery and its two reviewable units.
- Revision 2: record the finished cards while keeping controls pending.

## Acceptance criteria

- AC-01: Every example has a readable document card and source link.
- AC-02: Copy and download controls work with a keyboard and report success or failure.

02 Complete API result

parsePlan(source)
JSON · complete result
{
  "name": "example-gallery",
  "source": "---\nid: 1792612860_example-gallery\ncreated_at: 2026-10-21T20:01:00Z\nupdated_at: 2026-10-21T20:02:00Z\nrevision: 2\nstatus: in progress\nprotocol: \"0.2\"\n---\n\n# Example gallery\n\nMake a small set of public examples easy to read and download.\n\n## Approach\n\nStart with accessible document cards, then add copy/download controls.\n\n## Acceptance\n\nThe source remains readable without JavaScript, with keyboard-accessible controls.\n\n## Revision history\n\n- Revision 1: establish the gallery and its two reviewable units.\n- Revision 2: record the finished cards while keeping controls pending.\n\n## Acceptance criteria\n\n- AC-01: Every example has a readable document card and source link.\n- AC-02: Copy and download controls work with a keyboard and report success or failure.\n",
  "body": "\n# Example gallery\n\nMake a small set of public examples easy to read and download.\n\n## Approach\n\nStart with accessible document cards, then add copy/download controls.\n\n## Acceptance\n\nThe source remains readable without JavaScript, with keyboard-accessible controls.\n\n## Revision history\n\n- Revision 1: establish the gallery and its two reviewable units.\n- Revision 2: record the finished cards while keeping controls pending.\n\n## Acceptance criteria\n\n- AC-01: Every example has a readable document card and source link.\n- AC-02: Copy and download controls work with a keyboard and report success or failure.\n",
  "frontmatter": {
    "start": 0,
    "contentStart": 4,
    "contentEnd": 149,
    "end": 153,
    "closed": true
  },
  "rawMetadata": {
    "id": "1792612860_example-gallery",
    "created_at": "2026-10-21T20:01:00Z",
    "updated_at": "2026-10-21T20:02:00Z",
    "revision": 2,
    "status": "in progress",
    "protocol": "0.2"
  },
  "metadata": {
    "id": "1792612860_example-gallery",
    "created_at": "2026-10-21T20:01:00Z",
    "updated_at": "2026-10-21T20:02:00Z",
    "revision": 2,
    "status": "in progress",
    "protocol": "0.2"
  },
  "preamble": {
    "start": 0,
    "end": 237
  },
  "sections": [
    {
      "title": "Approach",
      "heading": {
        "start": 237,
        "end": 249
      },
      "body": {
        "start": 249,
        "end": 322
      }
    },
    {
      "title": "Acceptance",
      "heading": {
        "start": 322,
        "end": 336
      },
      "body": {
        "start": 336,
        "end": 421
      }
    },
    {
      "title": "Revision history",
      "heading": {
        "start": 421,
        "end": 441
      },
      "body": {
        "start": 441,
        "end": 581
      }
    },
    {
      "title": "Acceptance criteria",
      "heading": {
        "start": 581,
        "end": 604
      },
      "body": {
        "start": 604,
        "end": 762
      }
    }
  ],
  "protocol": "0.2",
  "criteria": [
    {
      "id": "AC-01",
      "idText": "AC-01",
      "text": "Every example has a readable document card and source link.",
      "location": {
        "offset": 607,
        "line": 29,
        "column": 3
      },
      "range": {
        "start": 605,
        "end": 673
      }
    },
    {
      "id": "AC-02",
      "idText": "AC-02",
      "text": "Copy and download controls work with a keyboard and report success or failure.",
      "location": {
        "offset": 676,
        "line": 30,
        "column": 3
      },
      "range": {
        "start": 674,
        "end": 761
      }
    }
  ],
  "diagnostics": []
}

milestones.md

01 Markdown source

milestones.md
# Example gallery milestones

## Overview

| Milestone | Name | Status |
| --- | --- | --- |
| 1 | [Document cards](#milestone-1-document-cards) | done |
| 2 | [Copy and download](#milestone-2-copy-and-download) | pending |

## Milestone 1: Document cards
**Status:** done
**Milestone ID:** 5a148c73-7d38-4a2f-9c0f-903d93b9b764
**Acceptance criteria:** AC-01

Show each example with a meaningful title and source link. Review the cards in both themes and at narrow widths.

## Milestone 2: Copy and download
**Status:** pending
**Milestone ID:** d7f04e92-61a7-4caf-8ab2-64c2b9f787e1
**Acceptance criteria:** AC-02

Add keyboard-accessible controls with success/failure feedback. Review actual copied and downloaded bytes.

02 Complete API result

parseMilestones(source)
JSON · complete result
{
  "source": "# Example gallery milestones\n\n## Overview\n\n| Milestone | Name | Status |\n| --- | --- | --- |\n| 1 | [Document cards](#milestone-1-document-cards) | done |\n| 2 | [Copy and download](#milestone-2-copy-and-download) | pending |\n\n## Milestone 1: Document cards\n**Status:** done\n**Milestone ID:** 5a148c73-7d38-4a2f-9c0f-903d93b9b764\n**Acceptance criteria:** AC-01\n\nShow each example with a meaningful title and source link. Review the cards in both themes and at narrow widths.\n\n## Milestone 2: Copy and download\n**Status:** pending\n**Milestone ID:** d7f04e92-61a7-4caf-8ab2-64c2b9f787e1\n**Acceptance criteria:** AC-02\n\nAdd keyboard-accessible controls with success/failure feedback. Review actual copied and downloaded bytes.\n",
  "body": "# Example gallery milestones\n\n## Overview\n\n| Milestone | Name | Status |\n| --- | --- | --- |\n| 1 | [Document cards](#milestone-1-document-cards) | done |\n| 2 | [Copy and download](#milestone-2-copy-and-download) | pending |\n\n## Milestone 1: Document cards\n**Status:** done\n**Milestone ID:** 5a148c73-7d38-4a2f-9c0f-903d93b9b764\n**Acceptance criteria:** AC-01\n\nShow each example with a meaningful title and source link. Review the cards in both themes and at narrow widths.\n\n## Milestone 2: Copy and download\n**Status:** pending\n**Milestone ID:** d7f04e92-61a7-4caf-8ab2-64c2b9f787e1\n**Acceptance criteria:** AC-02\n\nAdd keyboard-accessible controls with success/failure feedback. Review actual copied and downloaded bytes.\n",
  "frontmatter": null,
  "rawMetadata": null,
  "preamble": {
    "start": 0,
    "end": 30
  },
  "sections": [
    {
      "title": "Overview",
      "heading": {
        "start": 30,
        "end": 42
      },
      "body": {
        "start": 42,
        "end": 225
      }
    },
    {
      "title": "Milestone 1: Document cards",
      "heading": {
        "start": 225,
        "end": 256
      },
      "body": {
        "start": 256,
        "end": 474
      }
    },
    {
      "title": "Milestone 2: Copy and download",
      "heading": {
        "start": 474,
        "end": 508
      },
      "body": {
        "start": 508,
        "end": 722
      }
    }
  ],
  "overviewTables": [
    {
      "start": 43,
      "end": 224
    }
  ],
  "milestones": [
    {
      "ordinal": 1,
      "ordinalText": "1",
      "title": "Document cards",
      "status": "done",
      "id": "5a148c73-7d38-4a2f-9c0f-903d93b9b764",
      "location": {
        "offset": 225,
        "line": 10,
        "column": 1
      },
      "headingEnd": 256,
      "end": 474,
      "body": "**Status:** done\n**Milestone ID:** 5a148c73-7d38-4a2f-9c0f-903d93b9b764\n**Acceptance criteria:** AC-01\n\nShow each example with a meaningful title and source link. Review the cards in both themes and at narrow widths.\n\n",
      "statusMarkers": [
        {
          "value": "done",
          "location": {
            "offset": 256,
            "line": 11,
            "column": 1
          },
          "valueStart": 268,
          "valueEnd": 272,
          "lineStart": 256,
          "lineEnd": 273
        }
      ],
      "idMarkers": [
        {
          "value": "5a148c73-7d38-4a2f-9c0f-903d93b9b764",
          "location": {
            "offset": 273,
            "line": 12,
            "column": 1
          },
          "valueStart": 291,
          "valueEnd": 327,
          "lineStart": 273,
          "lineEnd": 328
        }
      ],
      "criteria": [
        "AC-01"
      ],
      "criteriaMarkers": [
        {
          "value": "AC-01",
          "location": {
            "offset": 328,
            "line": 13,
            "column": 1
          },
          "valueStart": 353,
          "valueEnd": 358,
          "lineStart": 328,
          "lineEnd": 359
        }
      ]
    },
    {
      "ordinal": 2,
      "ordinalText": "2",
      "title": "Copy and download",
      "status": "pending",
      "id": "d7f04e92-61a7-4caf-8ab2-64c2b9f787e1",
      "location": {
        "offset": 474,
        "line": 17,
        "column": 1
      },
      "headingEnd": 508,
      "end": 722,
      "body": "**Status:** pending\n**Milestone ID:** d7f04e92-61a7-4caf-8ab2-64c2b9f787e1\n**Acceptance criteria:** AC-02\n\nAdd keyboard-accessible controls with success/failure feedback. Review actual copied and downloaded bytes.\n",
      "statusMarkers": [
        {
          "value": "pending",
          "location": {
            "offset": 508,
            "line": 18,
            "column": 1
          },
          "valueStart": 520,
          "valueEnd": 527,
          "lineStart": 508,
          "lineEnd": 528
        }
      ],
      "idMarkers": [
        {
          "value": "d7f04e92-61a7-4caf-8ab2-64c2b9f787e1",
          "location": {
            "offset": 528,
            "line": 19,
            "column": 1
          },
          "valueStart": 546,
          "valueEnd": 582,
          "lineStart": 528,
          "lineEnd": 583
        }
      ],
      "criteria": [
        "AC-02"
      ],
      "criteriaMarkers": [
        {
          "value": "AC-02",
          "location": {
            "offset": 583,
            "line": 20,
            "column": 1
          },
          "valueStart": 608,
          "valueEnd": 613,
          "lineStart": 583,
          "lineEnd": 614
        }
      ]
    }
  ],
  "overview": [
    {
      "ordinal": 1,
      "ordinalText": "1",
      "name": "[Document cards](#milestone-1-document-cards)",
      "status": "done",
      "location": {
        "offset": 93,
        "line": 7,
        "column": 1
      }
    },
    {
      "ordinal": 2,
      "ordinalText": "2",
      "name": "[Copy and download](#milestone-2-copy-and-download)",
      "status": "pending",
      "location": {
        "offset": 154,
        "line": 8,
        "column": 1
      }
    }
  ],
  "overviewPresent": true,
  "diagnostics": []
}

Project extensions

Project extensions

Your own metadata and workflow vocabulary remain yours.

Tolerant reading

plan.md

01 Markdown source

plan.md
---
id: gallery-accessibility
created_at: 2026-10-21T20:03:00Z
updated_at: 2026-10-21T20:04:00Z
revision: 3
status: waiting-for-feedback
protocol: "0.2"
project:
  owner: example-team
  labels:
    - accessibility
    - documentation
---

# Gallery accessibility review

Collect feedback on keyboard focus and readable source panels.

The project field belongs to this example consumer. A stricter project profile may validate it, while a general reader retains it without adopting that policy.

## Acceptance criteria

- AC-01: Reviewers can inspect keyboard focus and readable source panels.

02 Complete API result

parsePlan(source)
JSON · complete result
{
  "name": "gallery-accessibility",
  "source": "---\nid: gallery-accessibility\ncreated_at: 2026-10-21T20:03:00Z\nupdated_at: 2026-10-21T20:04:00Z\nrevision: 3\nstatus: waiting-for-feedback\nprotocol: \"0.2\"\nproject:\n  owner: example-team\n  labels:\n    - accessibility\n    - documentation\n---\n\n# Gallery accessibility review\n\nCollect feedback on keyboard focus and readable source panels.\n\nThe project field belongs to this example consumer. A stricter project profile may validate it, while a general reader retains it without adopting that policy.\n\n## Acceptance criteria\n\n- AC-01: Reviewers can inspect keyboard focus and readable source panels.\n",
  "body": "\n# Gallery accessibility review\n\nCollect feedback on keyboard focus and readable source panels.\n\nThe project field belongs to this example consumer. A stricter project profile may validate it, while a general reader retains it without adopting that policy.\n\n## Acceptance criteria\n\n- AC-01: Reviewers can inspect keyboard focus and readable source panels.\n",
  "frontmatter": {
    "start": 0,
    "contentStart": 4,
    "contentEnd": 234,
    "end": 238,
    "closed": true
  },
  "rawMetadata": {
    "id": "gallery-accessibility",
    "created_at": "2026-10-21T20:03:00Z",
    "updated_at": "2026-10-21T20:04:00Z",
    "revision": 3,
    "status": "waiting-for-feedback",
    "protocol": "0.2",
    "project": {
      "owner": "example-team",
      "labels": [
        "accessibility",
        "documentation"
      ]
    }
  },
  "metadata": {
    "id": "gallery-accessibility",
    "created_at": "2026-10-21T20:03:00Z",
    "updated_at": "2026-10-21T20:04:00Z",
    "revision": 3,
    "status": "waiting-for-feedback",
    "protocol": "0.2"
  },
  "preamble": {
    "start": 0,
    "end": 496
  },
  "sections": [
    {
      "title": "Acceptance criteria",
      "heading": {
        "start": 496,
        "end": 519
      },
      "body": {
        "start": 519,
        "end": 594
      }
    }
  ],
  "protocol": "0.2",
  "criteria": [
    {
      "id": "AC-01",
      "idText": "AC-01",
      "text": "Reviewers can inspect keyboard focus and readable source panels.",
      "location": {
        "offset": 522,
        "line": 23,
        "column": 3
      },
      "range": {
        "start": 520,
        "end": 593
      }
    }
  ],
  "diagnostics": [
    {
      "document": "plan",
      "code": "INVALID_STATUS",
      "message": "The plan status is not pending, in progress, or done.",
      "severity": "error",
      "location": {
        "offset": 116,
        "line": 6,
        "column": 9
      }
    }
  ]
}

Partly deleted

Partly deleted

Useful Markdown remains useful after metadata is removed.

Tolerant reading

plan.md

01 Markdown source

plan.md
# A shortened plan

The user removed the metadata and earlier discussion. Keep this remaining objective useful: improve the text shown when a search has no matches.

## Remaining validation

Read the message with a screen reader and check its reset action from the keyboard.

The missing fields do not establish when this document was created, whether work was approved, or whether anything finished.

02 Complete API result

parsePlan(source)
JSON · complete result
{
  "name": null,
  "source": "# A shortened plan\n\nThe user removed the metadata and earlier discussion. Keep this remaining objective useful: improve the text shown when a search has no matches.\n\n## Remaining validation\n\nRead the message with a screen reader and check its reset action from the keyboard.\n\nThe missing fields do not establish when this document was created, whether work was approved, or whether anything finished.\n",
  "body": "# A shortened plan\n\nThe user removed the metadata and earlier discussion. Keep this remaining objective useful: improve the text shown when a search has no matches.\n\n## Remaining validation\n\nRead the message with a screen reader and check its reset action from the keyboard.\n\nThe missing fields do not establish when this document was created, whether work was approved, or whether anything finished.\n",
  "frontmatter": null,
  "rawMetadata": null,
  "metadata": {},
  "preamble": {
    "start": 0,
    "end": 166
  },
  "sections": [
    {
      "title": "Remaining validation",
      "heading": {
        "start": 166,
        "end": 190
      },
      "body": {
        "start": 190,
        "end": 401
      }
    }
  ],
  "protocol": "0.2",
  "criteria": [],
  "diagnostics": [
    {
      "document": "plan",
      "code": "MISSING_FRONTMATTER",
      "message": "Preferred plan metadata is absent.",
      "severity": "error"
    },
    {
      "document": "plan",
      "code": "MISSING_METADATA_FIELD",
      "message": "Preferred metadata field 'id' is absent.",
      "severity": "error"
    },
    {
      "document": "plan",
      "code": "MISSING_METADATA_FIELD",
      "message": "Preferred metadata field 'created_at' is absent.",
      "severity": "error"
    },
    {
      "document": "plan",
      "code": "MISSING_METADATA_FIELD",
      "message": "Preferred metadata field 'updated_at' is absent.",
      "severity": "error"
    },
    {
      "document": "plan",
      "code": "MISSING_METADATA_FIELD",
      "message": "Preferred metadata field 'revision' is absent.",
      "severity": "error"
    },
    {
      "document": "plan",
      "code": "MISSING_METADATA_FIELD",
      "message": "Preferred metadata field 'status' is absent.",
      "severity": "error"
    },
    {
      "document": "plan",
      "code": "NO_CRITERIA",
      "message": "A protocol 0.2 plan defines no acceptance criterion.",
      "severity": "error"
    }
  ]
}

Plan removed

Plan removed

Observe the milestones that remain without recreating a plan.

Tolerant reading

milestones.md

01 Markdown source

milestones.md
# Remaining milestone notes

The user deleted plan.md and earlier milestones. This file is useful on its own.

## Milestone 3: Check the remaining action
**Status:** pending

Verify that the reset action clears the filters. The gap in numbering does not recreate earlier work or imply that it completed.

02 Complete API result

parseMilestones(source)
JSON · complete result
{
  "source": "# Remaining milestone notes\n\nThe user deleted plan.md and earlier milestones. This file is useful on its own.\n\n## Milestone 3: Check the remaining action\n**Status:** pending\n\nVerify that the reset action clears the filters. The gap in numbering does not recreate earlier work or imply that it completed.\n",
  "body": "# Remaining milestone notes\n\nThe user deleted plan.md and earlier milestones. This file is useful on its own.\n\n## Milestone 3: Check the remaining action\n**Status:** pending\n\nVerify that the reset action clears the filters. The gap in numbering does not recreate earlier work or imply that it completed.\n",
  "frontmatter": null,
  "rawMetadata": null,
  "preamble": {
    "start": 0,
    "end": 111
  },
  "sections": [
    {
      "title": "Milestone 3: Check the remaining action",
      "heading": {
        "start": 111,
        "end": 154
      },
      "body": {
        "start": 154,
        "end": 304
      }
    }
  ],
  "overviewTables": [],
  "milestones": [
    {
      "ordinal": 3,
      "ordinalText": "3",
      "title": "Check the remaining action",
      "status": "pending",
      "id": null,
      "location": {
        "offset": 111,
        "line": 5,
        "column": 1
      },
      "headingEnd": 154,
      "end": 304,
      "body": "**Status:** pending\n\nVerify that the reset action clears the filters. The gap in numbering does not recreate earlier work or imply that it completed.\n",
      "statusMarkers": [
        {
          "value": "pending",
          "location": {
            "offset": 154,
            "line": 6,
            "column": 1
          },
          "valueStart": 166,
          "valueEnd": 173,
          "lineStart": 154,
          "lineEnd": 174
        }
      ],
      "idMarkers": [],
      "criteria": null,
      "criteriaMarkers": []
    }
  ],
  "overview": [],
  "overviewPresent": false,
  "diagnostics": [
    {
      "document": "milestones",
      "code": "NONSEQUENTIAL_ORDINAL",
      "message": "The observed sequence has a gap; no missing entries are inferred.",
      "severity": "warning",
      "location": {
        "offset": 111,
        "line": 5,
        "column": 1
      }
    }
  ]
}

Acceptance criteria

Acceptance criteria

Requirements with stable IDs, the milestones that deliver them, and progress.

Conforming example

plan.md

01 Markdown source

plan.md
---
id: 1792612920_search-feedback-criteria
created_at: 2026-10-21T20:02:00Z
updated_at: 2026-10-21T20:04:00Z
revision: 2
status: in progress
protocol: "0.2"
priority: medium
repositories: [example/search]
error_codes: [{ repository: example/search, registry: docs/errors.md, codes: [4100, "SEARCH_FILTER_INVALID"] }]
---

# Search feedback

Explain empty search results and give people a useful next action. Milestone 1 delivers AC-01.

## Acceptance criteria

- AC-01: Empty search results explain why nothing matched.
- AC-02: The empty state offers one next action,
  such as clearing the active filters.
- AC-03: The explanation and the action work with a keyboard and a screen reader.

## Notes for reviewers

This sample shows the format; it is not a criterion of this plan:

```markdown
- AC-09: Search suggests spelling corrections.
```

## Revision history

- Revision 1: define the three criteria.
- Revision 2: record the finished explanation.

02 Complete API result

parsePlan(source)
JSON · complete result
{
  "name": "search-feedback-criteria",
  "source": "---\nid: 1792612920_search-feedback-criteria\ncreated_at: 2026-10-21T20:02:00Z\nupdated_at: 2026-10-21T20:04:00Z\nrevision: 2\nstatus: in progress\nprotocol: \"0.2\"\npriority: medium\nrepositories: [example/search]\nerror_codes: [{ repository: example/search, registry: docs/errors.md, codes: [4100, \"SEARCH_FILTER_INVALID\"] }]\n---\n\n# Search feedback\n\nExplain empty search results and give people a useful next action. Milestone 1 delivers AC-01.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action,\n  such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n\n## Notes for reviewers\n\nThis sample shows the format; it is not a criterion of this plan:\n\n```markdown\n- AC-09: Search suggests spelling corrections.\n```\n\n## Revision history\n\n- Revision 1: define the three criteria.\n- Revision 2: record the finished explanation.\n",
  "body": "\n# Search feedback\n\nExplain empty search results and give people a useful next action. Milestone 1 delivers AC-01.\n\n## Acceptance criteria\n\n- AC-01: Empty search results explain why nothing matched.\n- AC-02: The empty state offers one next action,\n  such as clearing the active filters.\n- AC-03: The explanation and the action work with a keyboard and a screen reader.\n\n## Notes for reviewers\n\nThis sample shows the format; it is not a criterion of this plan:\n\n```markdown\n- AC-09: Search suggests spelling corrections.\n```\n\n## Revision history\n\n- Revision 1: define the three criteria.\n- Revision 2: record the finished explanation.\n",
  "frontmatter": {
    "start": 0,
    "contentStart": 4,
    "contentEnd": 318,
    "end": 322,
    "closed": true
  },
  "rawMetadata": {
    "id": "1792612920_search-feedback-criteria",
    "created_at": "2026-10-21T20:02:00Z",
    "updated_at": "2026-10-21T20:04:00Z",
    "revision": 2,
    "status": "in progress",
    "protocol": "0.2",
    "priority": "medium",
    "repositories": [
      "example/search"
    ],
    "error_codes": [
      {
        "repository": "example/search",
        "registry": "docs/errors.md",
        "codes": [
          4100,
          "SEARCH_FILTER_INVALID"
        ]
      }
    ]
  },
  "metadata": {
    "id": "1792612920_search-feedback-criteria",
    "created_at": "2026-10-21T20:02:00Z",
    "updated_at": "2026-10-21T20:04:00Z",
    "revision": 2,
    "status": "in progress",
    "protocol": "0.2",
    "priority": "medium",
    "repositories": [
      "example/search"
    ],
    "error_codes": [
      {
        "repository": "example/search",
        "registry": "docs/errors.md",
        "codes": [
          4100,
          "SEARCH_FILTER_INVALID"
        ]
      }
    ]
  },
  "preamble": {
    "start": 0,
    "end": 438
  },
  "sections": [
    {
      "title": "Acceptance criteria",
      "heading": {
        "start": 438,
        "end": 461
      },
      "body": {
        "start": 461,
        "end": 692
      }
    },
    {
      "title": "Notes for reviewers",
      "heading": {
        "start": 692,
        "end": 715
      },
      "body": {
        "start": 715,
        "end": 847
      }
    },
    {
      "title": "Revision history",
      "heading": {
        "start": 847,
        "end": 867
      },
      "body": {
        "start": 867,
        "end": 956
      }
    }
  ],
  "protocol": "0.2",
  "criteria": [
    {
      "id": "AC-01",
      "idText": "AC-01",
      "text": "Empty search results explain why nothing matched.",
      "location": {
        "offset": 464,
        "line": 19,
        "column": 3
      },
      "range": {
        "start": 462,
        "end": 520
      }
    },
    {
      "id": "AC-02",
      "idText": "AC-02",
      "text": "The empty state offers one next action, such as clearing the active filters.",
      "location": {
        "offset": 523,
        "line": 20,
        "column": 3
      },
      "range": {
        "start": 521,
        "end": 608
      }
    },
    {
      "id": "AC-03",
      "idText": "AC-03",
      "text": "The explanation and the action work with a keyboard and a screen reader.",
      "location": {
        "offset": 611,
        "line": 22,
        "column": 3
      },
      "range": {
        "start": 609,
        "end": 690
      }
    }
  ],
  "diagnostics": []
}

milestones.md

01 Markdown source

milestones.md
## Milestone 1: Explain empty results
**Status:** done
**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34
**Acceptance criteria:** AC-01

Add the explanation to the empty results view. Review it in both themes.

## Milestone 2: Offer a next action
**Status:** in progress
**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15
**Acceptance criteria:** AC-02, AC-03

Add the clear-filters action, then check it with a keyboard and a screen reader.

02 Complete API result

parseMilestones(source)
JSON · complete result
{
  "source": "## Milestone 1: Explain empty results\n**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n## Milestone 2: Offer a next action\n**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
  "body": "## Milestone 1: Explain empty results\n**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n## Milestone 2: Offer a next action\n**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
  "frontmatter": null,
  "rawMetadata": null,
  "preamble": {
    "start": 0,
    "end": 0
  },
  "sections": [
    {
      "title": "Milestone 1: Explain empty results",
      "heading": {
        "start": 0,
        "end": 38
      },
      "body": {
        "start": 38,
        "end": 216
      }
    },
    {
      "title": "Milestone 2: Offer a next action",
      "heading": {
        "start": 216,
        "end": 252
      },
      "body": {
        "start": 252,
        "end": 451
      }
    }
  ],
  "overviewTables": [],
  "milestones": [
    {
      "ordinal": 1,
      "ordinalText": "1",
      "title": "Explain empty results",
      "status": "done",
      "id": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34",
      "location": {
        "offset": 0,
        "line": 1,
        "column": 1
      },
      "headingEnd": 38,
      "end": 216,
      "body": "**Status:** done\n**Milestone ID:** 3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34\n**Acceptance criteria:** AC-01\n\nAdd the explanation to the empty results view. Review it in both themes.\n\n",
      "statusMarkers": [
        {
          "value": "done",
          "location": {
            "offset": 38,
            "line": 2,
            "column": 1
          },
          "valueStart": 50,
          "valueEnd": 54,
          "lineStart": 38,
          "lineEnd": 55
        }
      ],
      "idMarkers": [
        {
          "value": "3c7a2f1e-9b4d-4e8a-a6f2-1d5c7e9b0a34",
          "location": {
            "offset": 55,
            "line": 3,
            "column": 1
          },
          "valueStart": 73,
          "valueEnd": 109,
          "lineStart": 55,
          "lineEnd": 110
        }
      ],
      "criteria": [
        "AC-01"
      ],
      "criteriaMarkers": [
        {
          "value": "AC-01",
          "location": {
            "offset": 110,
            "line": 4,
            "column": 1
          },
          "valueStart": 135,
          "valueEnd": 140,
          "lineStart": 110,
          "lineEnd": 141
        }
      ]
    },
    {
      "ordinal": 2,
      "ordinalText": "2",
      "title": "Offer a next action",
      "status": "in progress",
      "id": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15",
      "location": {
        "offset": 216,
        "line": 8,
        "column": 1
      },
      "headingEnd": 252,
      "end": 451,
      "body": "**Status:** in progress\n**Milestone ID:** 8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15\n**Acceptance criteria:** AC-02, AC-03\n\nAdd the clear-filters action, then check it with a keyboard and a screen reader.\n",
      "statusMarkers": [
        {
          "value": "in progress",
          "location": {
            "offset": 252,
            "line": 9,
            "column": 1
          },
          "valueStart": 264,
          "valueEnd": 275,
          "lineStart": 252,
          "lineEnd": 276
        }
      ],
      "idMarkers": [
        {
          "value": "8e1d6b2a-4f7c-4a3e-b9d1-6c2e8f4a7b15",
          "location": {
            "offset": 276,
            "line": 10,
            "column": 1
          },
          "valueStart": 294,
          "valueEnd": 330,
          "lineStart": 276,
          "lineEnd": 331
        }
      ],
      "criteria": [
        "AC-02",
        "AC-03"
      ],
      "criteriaMarkers": [
        {
          "value": "AC-02, AC-03",
          "location": {
            "offset": 331,
            "line": 11,
            "column": 1
          },
          "valueStart": 356,
          "valueEnd": 368,
          "lineStart": 331,
          "lineEnd": 369
        }
      ]
    }
  ],
  "overview": [],
  "overviewPresent": false,
  "diagnostics": []
}
About these examples and their expected results

Examples

These examples use invented prose, identifiers, names, and paths. They are public protocol examples and synthetic conformance inputs, not copied project plans. Expected observations below are specified independently of the reference parser.

Example Source Expected observations
Small plan plan.md Core fields and protocol 0.2, pending, revision 1, derived name search-feedback; AC-01 needs no milestones.
Optional milestones plan.md, milestones.md Two UUID-identified milestones: first done, second pending; overview agrees with markers; AC-01 is done and AC-02 pending.
Consumer extensions plan.md Custom waiting-for-feedback status and nested project metadata remain intact; INVALID_STATUS diagnoses that custom status and criterion progress is null.
Partly deleted metadata plan.md Markdown body remains useful; core metadata is absent, so preferred-writer conformance has findings.
Orphan milestones milestones.md plan.md is deliberately absent; the remaining milestone is observable without recreating a plan or inferring permission.
Acceptance criteria plan.md, milestones.md, expected.json (opens in a new tab) A protocol 0.2 plan with three criteria, a medium priority, the one repository it changes, and the explicit codes 4100 and SEARCH_FILTER_INVALID it adds; derived name search-feedback-criteria. AC-01 is done through milestone 1; AC-02 and AC-03 are in progress through milestone 2. The fenced sample and the prose mention of AC-01 define nothing. The documents conform.
Invalid criteria plan.md, milestones.md, expected.json (opens in a new tab) A protocol 0.2 plan with five findings: the status “blocked”, a second AC-01, the invalid ID AC-2, AC-03 covered by no milestone, and milestone 1 naming the undefined AC-07. AC-01 stays pending and AC-03 has no progress. The documents don’t conform.

Readers do not require every example to conform. The extensions example deliberately has a nonconforming custom status. The incomplete and orphan cases demonstrate useful inspection after ordinary user edits/deletion. The overview is optional and never the source of authority over marker status.

The two criteria examples also state their expected results as expected.json: whether the documents conform, the derived name, the priority, repositories, and error codes a plan declares, each criterion’s ID, text, covering milestones and progress, and each diagnostic’s code, document and line. Diagnostics are listed by document and line; readers may report them in another order.

The protocol owns the format. These files can be read, copied, and edited directly. The API and CLI explain reference operations.

Runnable library example

library.mjs (opens in a new tab) creates a plan with optional milestones, awaits a targeted update, inspects it, and performs an optional check. It prints a small JSON summary and removes only its own temporary root in finally. Run it with Node.js from a built checkout, or from its physical location inside an installed jg-plans package. The packed-consumer test executes this exact shipped file.

Read the example guide as Markdown