Ilya Partanskiy67 downloadsMove daily tasks between notes and a backlog, and materialize scheduled routines.
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.
[>] status and a link to their destination.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:
> [!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.
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:
There are no separate calendar and after-completion schedule types. Every schedule uses the same pipeline:
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.
Every schedule has this top-level shape:
{
"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.
The first Saturday no earlier than ten days after the previous completion:
{
"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:
{
"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:
[
{
"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" }
}
}
]
The first command is also available from the ribbon. Daily Flow automatically materializes routines when today's daily note opens.
Once Daily Flow is available in the Obsidian Community directory:
For manual testing, copy main.js, manifest.json, and styles.css into:
<vault>/.obsidian/plugins/daily-flow/
Then reload Obsidian and enable Daily Flow under Community plugins.
Requirements: Node.js 18 or newer and npm.
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.
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.