# Daily Flow Daily Flow moves physical Markdown tasks between daily notes and a backlog, and materializes scheduled routines when they become due. Everything stays in ordinary Markdown; the plugin does not use a database, network service, or telemetry. ## Features - Move the task under the cursor to tomorrow or back to the backlog. - Select several unfinished tasks and move them to tomorrow. - Pick tasks from the backlog for the active daily note. - Build event-driven calendar chains from composable date conditions. - Manage routines in a visual editor with a live schedule summary and upcoming-date preview. - Preserve task continuation lines when moving a task. - Mark forwarded tasks with the custom `[>]` status and a link to their destination. - Work in source, live preview, and reading modes. - Run on desktop and mobile. ## Expected note format Daily-note filenames must begin with `YYYY.MM.DD`. Text after the date is allowed, so the default generated name is `YYYY.MM.DD WEEKDAY.md`. Tasks live in `todo` callouts whose titles match the configured task groups: ```markdown > [!todo]+ Work > - [ ] Prepare the report > [!todo]+ Personal > - [ ] Call the doctor ``` The built-in defaults are language-neutral English values: | Setting | Default | | --- | --- | | Daily notes folder | `Daily notes` | | Daily-note template | `Templates/Daily note.md` | | Backlog note | `Backlog.md` | | Routines note | `Routines.md` | | Task groups | `Work`, `Personal`, `Shopping` | | Date locale | `auto` | | Weekday label source | `Locale` | | Custom weekday labels | `MON`, `TUE`, `WED`, `THU`, `FRI`, `SAT`, `SUN` | All paths, groups, and weekday labels can be changed under **Settings → Daily Flow**. Locale mode uses the runtime locale through `Intl.DateTimeFormat`; `auto` follows the environment, and any supported BCP 47 tag such as `ru`, `de-CH`, or `eo` can be entered explicitly. Custom mode accepts any seven labels, so languages or naming conventions not covered by `Intl` still work without being hardcoded in the plugin. ## Routines Run **Manage routines** from the command palette or use **Settings → Daily Flow → Routines note → Manage**. The editor is designed for desktop and mobile and supports: - a fixed-date trigger, completion of the same routine, or completion of another routine; - a minimum delay in calendar days, weeks, months, or years; - exact dates and calendar fields such as weekday, date, month, year, ISO week, week of month, and quarter; - every-N cadence relative to the trigger or a separate fixed anchor; - the N-th matching date from the start or end of a week, month, or year; - recursively nested **AND**, **OR**, and **EXCEPT** conditions; - selecting either the first matching date or every matching date; - catch-up after a missed due date and either single-open or overlapping instances. There are no separate calendar and after-completion schedule types. Every schedule uses the same pipeline: ```text trigger event → inclusive not-before boundary → eligible date set → first/all selection → lifecycle ``` A trigger is an event, not a continuously true condition. A completion-triggered occurrence therefore keeps the identity of the completion that produced it. Daily Flow writes hidden `routine`, `routine-occurrence`, and `routine-due` markers into generated Markdown tasks, so moving a task or reopening a note does not duplicate the same occurrence. The configured routines note remains ordinary Markdown with a fenced JSON array. The visual editor is the normal way to change it; **Open source JSON** is available for advanced edits. Each rule needs a stable unique `id`, task `text`, a configured `group`, an `enabled` flag, and a `schedule`. ### Schedule model Every schedule has this top-level shape: ```json { "version": 2, "trigger": { "type": "fixed", "date": "2026-09-01" }, "window": { "notBefore": { "value": 0, "unit": "day" } }, "dates": { "type": "all" }, "select": { "type": "all", "relation": "on-or-after" }, "lifecycle": { "catchUp": false, "overlap": "allow" } } ``` Triggers: | Meaning | Shape | | --- | --- | | Fixed anchor | `{"type":"fixed","date":"2026-09-01"}` | | Completion of this routine | `{"type":"completion","routine":"self","initial":"2026-09-01"}` | | Completion of another routine | `{"type":"completion","routine":"source-routine-id","initial":"2026-09-01"}` | For a completion trigger, `initial` is an optional ready first due date used while there is no source completion. The relative `notBefore` offset begins with subsequent completion events. Its unit is `day`, `week`, `month`, or `year`; month and year arithmetic is calendar arithmetic and clamps nonexistent dates. Date-set expressions: | Expression | Purpose | | --- | --- | | `{"type":"all"}` | Every date | | `{"type":"dates","dates":["2026-09-01"]}` | Exact dates | | `{"type":"field","field":"weekday","values":[1,4]}` | Selected calendar-field values | | `{"type":"cadence","unit":"month","every":2,"anchor":"trigger"}` | Every N calendar units | | `{"type":"ordinal","set":...,"within":"month","ordinal":3,"direction":"from-start"}` | N-th date from the start/end of a period that matches a nested set | | `{"type":"all-of","sets":[...]}` | Intersection: all nested sets must match | | `{"type":"any-of","sets":[...]}` | Union: at least one nested set must match | | `{"type":"except","base":...,"exclude":...}` | Dates in `base`, excluding dates in `exclude` | Supported fields are `weekday` (ISO order: Monday `1` through Sunday `7`), `day-of-month`, `month-of-year`, `year`, `day-of-year`, `iso-week`, `iso-week-year`, `week-of-month`, and `quarter`. ### Examples The first Saturday no earlier than ten days after the previous completion: ```json { "version": 2, "trigger": { "type": "completion", "routine": "self", "initial": "2026-09-01" }, "window": { "notBefore": { "value": 10, "unit": "day" } }, "dates": { "type": "field", "field": "weekday", "values": [6] }, "select": { "type": "first", "relation": "on-or-after" }, "lifecycle": { "catchUp": true, "overlap": "single-open" } } ``` The first third Saturday of a month no earlier than 90 days after completion: ```json { "version": 2, "trigger": { "type": "completion", "routine": "self", "initial": "2026-09-19" }, "window": { "notBefore": { "value": 90, "unit": "day" } }, "dates": { "type": "ordinal", "set": { "type": "field", "field": "weekday", "values": [6] }, "within": "month", "ordinal": 3, "direction": "from-start" }, "select": { "type": "first", "relation": "on-or-after" }, "lifecycle": { "catchUp": true, "overlap": "single-open" } } ``` Changing the offset to `{"value":3,"unit":"month"}` means three calendar months, which can produce a different result from 90 days. The third Saturday of every second month from September 2026 is an intersection of a month cadence and an ordinal weekday: ```json [ { "id": "vacuum", "text": "Vacuum the floor", "group": "Personal", "enabled": true, "schedule": { "version": 2, "trigger": { "type": "fixed", "date": "2026-09-01" }, "window": {}, "dates": { "type": "all-of", "sets": [ { "type": "cadence", "unit": "month", "every": 2, "anchor": "trigger" }, { "type": "ordinal", "set": { "type": "field", "field": "weekday", "values": [6] }, "within": "month", "ordinal": 3, "direction": "from-start" } ] }, "select": { "type": "all", "relation": "on-or-after" }, "lifecycle": { "catchUp": false, "overlap": "allow" } } } ] ``` ## Commands - **Take tasks from backlog** - **Move task under cursor to tomorrow** - **Choose open tasks to move to tomorrow** - **Move task under cursor to backlog** - **Materialize due routines in this daily note** - **Manage routines** The first command is also available from the ribbon. Daily Flow automatically materializes routines when today's daily note opens. ## Installation Once Daily Flow is available in the Obsidian Community directory: 1. Open **Settings → Community plugins → Browse**. 2. Search for **Daily Flow**. 3. Select **Install**, then **Enable**. For manual testing, copy `main.js`, `manifest.json`, and `styles.css` into: ```text /.obsidian/plugins/daily-flow/ ``` Then reload Obsidian and enable Daily Flow under Community plugins. ## Development Requirements: Node.js 18 or newer and npm. ```bash npm install npm run dev npm run check npm run build ``` `npm run build` creates the production `main.js` release artifact. Public releases use the SemVer-compatible calendar format `YY.M.PATCH`, where the patch counter starts at `0` each month. Months `1` through `9` are not zero-padded because SemVer forbids leading zeroes. Releases are tagged with the exact version from `manifest.json`, without a `v` prefix. ## Privacy Daily Flow only reads and writes files inside the current vault through the Obsidian API. It makes no network requests, collects no telemetry, and requires no account. ## License [MIT](LICENSE)