# todo.parse-repeat Reads what a person types into a todo's Repeat box as a `Recurrence` (todo.item), or null when it is not a repeat. It is the Repeat box's counterpart to todo.parse-date-phrase for the Due box. `every 2 weeks` on a todo due Friday 2 October 2026 is `{frequency: weekly, interval: 2, anchor: 2026-10-02}`. ## What it reads The whole box must be one `every ...` phrase, then optionally a start date: - **The repeat** is todo.parse-quick-add's grammar, exactly (the capability calls it rather than keeping a copy): `every day`, `every weekday`, `every week`, `every monday` (any weekday name), `every month`, `every year`, `every other week`, `every 3 days`, `every ten years` (1 to 999). Case-insensitive, ASCII whitespace between words. - **The start date**, if any, is whatever todo.parse-date-phrase reads as a whole: `tomorrow`, `on fri`, `next week`, `2026-10-15`. - **Anything else is null**: words left over (`every week please`), a date first (`tomorrow every week`), `weekly` on its own (a title word to quick-add), an empty box, `every 1000 days`. A form shows its own "try every week" message for null. ## Where the series starts The anchor is the series' first date, and so the todo's due date from then on (todo.item refuses a due date before the anchor). 1. The date typed in the box, if there is one. 2. Otherwise `due`, the todo's due date. 3. Otherwise quick-add's choice: today; for `every weekday` today if it is Monday to Friday, else next Monday; for `every ` the next such day strictly after today. Then, for steps 1 and 2, the start moves forward to the first day the pattern allows: `every monday` on a todo due Wednesday 30 September starts Monday 5 October (quick-add, by contrast, lets a date phrase in the same line win and repeats weekly on Wednesdays; in a Repeat box the weekday is the point), and `every weekday` from a Saturday starts the Monday after. A start already on an allowed day stays: `every friday` due Friday 2 October starts that day. Month ends and leap days are left to todo.next-occurrence: `every month` from 31 January is anchored on the 31st, so it falls on each month's last day. ## Errors Only a malformed or impossible `today` or `due` throws, with dates.add-days's message (`"28/09/2026" is not an ISO date`). Text that is not a repeat is null, never an error.