Task date marks¶
This guide is the authoritative display contract for task date-family
marks (canonical task dates plus recurrence rules), in the style of
docs/freshness.md §11 and the docs/projects.md "Priority marks"
section. The JavaScript mirror is api.dateMarks (namespace v1,
top-level api v3) in bob-ledger-tools, which stays dates-only; its
tests run the conformance vectors below verbatim.
What you see¶
Every canonical created, scheduled, completion, and cancelled
task date renders as a small monochrome icon plus a calendar label
instead of a KEY | YYYY-MM-DD Dataview pill, and every readable
[repeat:: …] rule renders as a quiet loop plus a spoken cadence:
before: - [ ] Add ability to install agent CLIs CREATED│2026-08-31 SCHEDULED│2026-09-04
after: - [ ] Add ability to install agent CLIs + Aug 31 ⧗ Sep 4
More examples (glyphs approximated in plain text):
- [?] Ship the importer + yesterday ⧗ Fri
- [ ] Rename the queue input + Sep 29 ⧗ today ← scheduled today reads a touch stronger
- [x] Review the /sase_memory_write skill + Aug 29 ✓ Sep 3 ← closed tasks rest (faint)
- [-] Old idea + Mar 2 ⊘ today
- [?] Brush teeth ⟲ daily + today ⧗ tomorrow
- [ ] Pay Kelly salary! ⟲ monthly · 1st + Oct 8 ⧗ Nov 1
Hovering any mark shows the exact date and its distance, for example
Scheduled Fri, Oct 9 · in 2 days followed by
Ctrl+Shift+P to reschedule. Moving the cursor into a mark, or
clicking it, reveals [scheduled:: 2026-10-09] for editing.
Principles¶
Display-only: [key:: YYYY-MM-DD] stays the only stored form;
nothing writes a date mark, and the Rust, Tasks, and Dataview
semantics are unchanged. Store absolute, show relative: near dates
read as words, and the tooltip always has the exact date. Shape
carries meaning; color whispers: each field has its own silhouette,
ink is monochrome, and emphasis comes from weight and opacity, never
hue. Quiet by default, louder only when it matters: created is the
quietest mark, and a scheduled date arriving today is the only
emphasized state. Reversible: the cursor or a click reveals the raw
field, source mode shows raw text, a session toggle restores the
pills, and without bob-ledger-tools the vault looks exactly as it
does today. One glyph definition (CSS masks) shared by every
surface.
Fields and glyphs¶
The four glyphs are refined, monochrome versions of the Tasks emoji
already seen in query results (➕ ⏳ ✅ ❌). The one deliberate
change is cancelled: ⊘ replaces ×, because a bare × beside the
created + reads as a pair of math operators (and as a close
button).
| Stored key | Tooltip verb | Glyph | Tasks emoji it replaces |
|---|---|---|---|
created |
Created |
plus | ➕ |
scheduled |
Scheduled |
hourglass | ⏳ |
completion |
Done |
check | ✅ |
cancelled |
Cancelled |
circle-slash (⊘) | ❌ |
repeat |
— (not a date; see below) | loop (⟲) | 🔁 (Tasks recurrence) |
due and start are out of scope: the vault uses start for clock
times and due only 3 times. Adding one later is a new row here, a
new glyph, and a new key in the repair-flag selector.
Final geometry (viewBox 0 0 16 16, black stroke,
stroke-width 1.9, stroke-linecap/stroke-linejoin round,
fill none; used as CSS masks): plus M8 3.25v9.5 M3.25 8h9.5;
hourglass M4 1.9h8 M4 14.1h8 with bulbs
M5.1 1.9v1.6c0 1.9 1.2 3.1 2.9 4.5c1.7-1.4 2.9-2.6 2.9-4.5V1.9 and
M5.1 14.1v-1.6c0-1.9 1.2-3.1 2.9-4.5c1.7 1.4 2.9 2.6 2.9 4.5v1.6;
check M3.1 8.6l3.1 3.1l6.7-6.9; circle-slash
<circle cx="8" cy="8" r="5.9"/> plus M3.83 3.83l8.34 8.34.
Label grammar¶
Let Δ be whole days from today (local date) to the field's date.
| Δ | Label |
|---|---|
| 0 | today |
| +1 | tomorrow |
| −1 | yesterday |
| +2 … +6 | short weekday of the date: Mon … Sun |
| any other Δ, same year | Oct 22 (short month, day without padding) |
| any other Δ, different year | Oct 22, 2027 |
Weekday names are used only for the coming six days: a past weekday
would make ⧗ Mon ambiguous, so past dates beyond yesterday use
month and day. The weekday rule wins over the year rule (on Dec 30, a
Jan 1 date reads Fri). Words are lowercase; month and weekday
names are capitalized fixed English, matching the freshness mark.
One grammar for all four fields makes a closed task read as a small
timeline (+ Aug 29 ✓ Sep 3); the task's age stays one hover away.
Tooltip¶
The mark carries role="img", aria-label, and
data-tooltip-position="top", lines joined with \n, never
containing ::. Line 1 is {Verb} {short date} · {relative},
where {short date} is the freshness short date (Fri, Oct 9, year
appended across years) and {relative} is today, tomorrow,
yesterday, in N days, or N days ago in exact days. Line 2,
scheduled only, is Ctrl+Shift+P to reschedule. Examples:
Created Tue, Sep 29 · 8 days ago;
Scheduled Fri, Oct 9 · in 2 days + reschedule hint;
Done Mon, Oct 5 · 2 days ago;
Cancelled Tue, Dec 30, 2025 · 281 days ago.
Anatomy and tones¶
A mark is span.bob-date-mark with span.bob-date-mark-glyph (the
mask) and span.bob-date-mark-label (the text), carrying
data-field, data-date, data-when (past | today |
future), and data-fold-space (data-rendered="true" on
rendered-view marks). Metrics match .bob-fresh-mark exactly
(interface font at 0.8em, tabular-nums, weight 550, inline-flex
with a 0.22em gap, pill padding/margin, vertical-align: 0.05em);
the glyph box is 1.08em square; hover is opacity 1 plus a 10%
currentColor capsule; transitions off under
prefers-reduced-motion.
| Situation | Ink | Opacity / weight |
|---|---|---|
| default | --bob-date-color-{field}, else --text-muted |
0.85 |
quiet: any created; past scheduled |
same ink | 0.7 |
emphasis: scheduled with data-when="today" |
--bob-date-color-today, else --text-normal |
1, weight 650 |
resting: inside a closed task (x, X, -) |
--text-faint |
0.75; wins over every other row |
Resting is derived from the nearest li.task-list-item[data-task]
or .HyperMD-task-line[data-task] ancestor, exactly like the
priority mark. Theme hooks
--bob-date-color-{created,scheduled,completion,cancelled,today}
are unset by default. There is no red and no "overdue" state: a past
scheduled date means the task already resurfaced, not that it is
late.
Eligibility and folding¶
For each key: the occurrence gate counts
/(^|[^A-Za-z0-9_-])key\s*::/gi and requires exactly one (so
[rescheduled:: …] never counts, and duplicates get no mark). The
canonical form is [key:: YYYY-MM-DD] or (key:: YYYY-MM-DD) with
a matching bracket pair, a lowercase key touching ::, padding
spaces only, and a strict calendar date. Each key is judged on its
own. Any canonical field outside code gets a mark: task lines,
plain bullets, quotes, continuation lines, paragraphs. Excluded:
source mode and code positions in Live Preview; text under code,
pre, .dataview.inline-field, .bob-date-mark,
.bob-priority-mark, or .bob-fresh-mark in rendered views.
Whitespace-run folding (Live Preview): the decoration starts at the
first space of the U+0020 run directly before the field, and the
widget restores one uniform gap — Tasks-written double-spaced
completion/cancelled fields sit with the same gap as
single-spaced ones. A field beginning the line's content never
folds. A selection endpoint never sits inside a fold. While a cursor or
selection end lies strictly inside the space run, that field's mark folds nothing
and the spaces show as text; the fold returns once the cursor leaves the run.
Folded spaces still never reveal the field.
Repair flag¶
While marks are on, any leftover
created/scheduled/completion/cancelled/repeat Dataview pill
in Live Preview is a field Tasks cannot read (or a guarded repeat):
a bad date, a word, a datetime, a duplicate, mismatched brackets, an
uppercase key, a space before ::, or the checklist guard. CSS flags
it with full opacity and a dashed orange border, matching the
freshness and priority flags. Template placeholders in _templates
are also flagged: the flag truthfully says Tasks cannot read the
value as a date.
Recurrence (not a date)¶
A recurrence mark is span.bob-date-mark[data-field="repeat"] with
data-rule (the rule as written, whitespace-collapsed),
data-when-done (true/false), and data-fold-space
(data-rendered="true" on rendered views). It contains the usual
span.bob-date-mark-glyph + span.bob-date-mark-label. It has no
data-date and no data-when, and keeps role="img",
aria-label, and data-tooltip-position="top".
Glyph: a rectangular two-arrow loop, a refined monochrome 🔁. It
deliberately avoids the circular arrow, which already means ⟳ Review
and due freshness. Geometry (viewBox 0 0 16 16, black stroke,
stroke-width 1.8, round caps and joins): M2.6 9.4V6.6A2.6 2.6 0 0 1
5.2 4h8.2M11 1.6 13.4 4 11 6.4M13.4 6.6v2.8A2.6 2.6 0 0 1 10.8 12H2.6M5
9.6 2.6 12 5 14.4. Defined as --bob-date-glyph-repeat.
Ink is always the quiet tone: --bob-date-color-repeat, else
--text-muted, at opacity 0.7 (like created). There is no emphasis
state and no hue. Closed rows rest faint via explicit
li.task-list-item[data-task=x|X|-] .bob-date-mark[data-field="repeat"]
and .HyperMD-task-line[...] rules, because the existing resting
selector requires [data-when].
Validity gate (all must hold, else the native pill stays): exactly one
/(^|[^A-Za-z0-9_-])repeat\s*::/gi on the line or text node;
[repeat:: …] or (repeat:: …) with matching brackets, a lowercase
key touching ::, and ASCII space padding only; the raw value matches
Tasks' charset ^[a-zA-Z0-9, !]+$ before repeated spaces are collapsed,
and starts with every plus a space and more text (case-insensitive);
tabs, non-breaking spaces, and other whitespace are invalid rather than
normalized; code positions are excluded exactly as for dates; and the
checklist guard below does not fire. Known limit: the charset check is necessary but not sufficient —
every blursday gets a verbatim label, which is still truthful text.
Checklist guard: no mark when the line is a checklist member
(checklistKindForText non-null), the task is open (status not x,
X, -), and the rule lacks when done. This mirrors the
checklist_repeat_not_when_done lint scope (open members), so the
display never hides what the lint flags. Live Preview reads the whole
line plus freshnessTaskStatus; rendered views read the nearest
li.task-list-item ancestor's own a.tag anchors (skipping nested
lists and code) and its data-task, lazily and only for text that
contains a repeat source.
Label grammar ("say it the way a person would"): normalize by
trimming, collapsing whitespace, and stripping a trailing when done
(case-insensitive). Labels are lowercase except weekday and month
names, use · (U+00B7 with spaces) between cadence and detail, and
are never truncated. day/weekday → daily/weekdays;
week/month/year (or 1 week etc.) → weekly/monthly/yearly;
N days/weeks/months/years (N ≥ 2) → every N days (and so on);
<Weekday> or week on <Weekday> → Mondays; week on <Weekday
list> → weekly · Tue, Fri; N weeks on <Weekday list> (N ≥ 2) →
every N weeks · Fri; month on the <ordinal>/last/last
<Weekday>/<ordinal> <Weekday> → monthly · 1st/monthly ·
last/monthly · last Fri/monthly · 2nd Wed; N months on the
<ordinal>[ <Weekday>] (N ≥ 2) → every N months · 1st; <Month> on
the <ordinal> → yearly · Jan 15; anything else stays verbatim
(collapsed, minus when done). Ordinals keep their written token,
lowercased. The grammar covers every rule in the vault today.
Tooltip: two lines, never containing ::. Line 1 is Repeats <rule as
written, collapsed>; line 2 is Next date counts from completion
when whenDone, else Next date follows the schedule.
relabelRenderedDateMarks already skips repeat marks because
dateMarkModel returns null for repeat. api.dateMarks v1 stays
dates-only: fields is unchanged and model("repeat", …) is null.
Surfaces and interaction¶
Live Preview uses a Prec.highest ViewPlugin emitting one
Decoration.replace per eligible field, in line order. The mark
hides while any selection overlaps its own field span, so editing
created never reveals scheduled. A selection endpoint never sits
inside a fold: a cursor resting in the folded spaces unfolds that
field's mark to fold 0. Mousedown places the cursor at
the field start and focuses the editor; it never writes. Widget
equality includes the label, when, and tooltip, so a new day
always re-renders. Rebuilds happen on doc, viewport, or selection
changes, Live Preview or file switches, and the dateMarksRefresh
effect. The rendered-view post-processor (sort order 50, before
Dataview's pass at 100) splits each matching text node into
text / mark / text / mark / … for every eligible field, covering
reading view, embeds, hover previews, Dataview TASK views, and
Tasks descriptions with a non-trailing field. A duplicate split
across separate text nodes is not detected (the accepted priority
limit).
Tasks query results¶
Tasks 8.4.0 always renders query-result date components with its
emoji serializer: span.task-created|task-scheduled|task-done|task-cancelled
wrapping an inner span whose text is " ⏳ 2026-10-09" (full mode)
or " ⏳" (short mode). The DOM contract, confirmed against the
installed obsidian-tasks-plugin/main.js (renderTaskLine,
taskToHtml, tasks-layout-short-mode):
- Each date component is a direct child span of
li.plugin-tasks-list-item > .tasks-list-text, with its text in a single inner span.donemaps totask-done. - The li receives
data-taskonly at the end ofrenderTaskLine, so it is the completion signal. - Short-mode containers carry
tasks-layout-short-mode. - Date spans keep Tasks' click (date editor) and contextmenu (postpone) listeners.
CSS cannot split the emoji from the date, so unlike the priority
mark (whose Tasks host is CSS-only), full mode needs a small, narrow
JS frame pass — the narrowest JS that degrades to Tasks' native
rendering. scheduleTasksResultDateMarks(el) runs at the end of
renderDateMarksIn: Tasks renders every description through
MarkdownRenderer.render, so it fires once per result row. It queues
el when el has a result-row ancestor or is still detached, keeps
at most one pending frame (requestAnimationFrame, falling back to
a 16ms timeout), and schedules nothing when marks are off or for a
connected non-Tasks element. runTasksResultDateMarkFrame resolves
each entry to its row — a still-detached element is retried for up
to 3 frames, a row without data-task for up to 60 — deduplicates
rows with a WeakSet, and decorates complete rows with
decorateTasksResultDates(li, today). Exhausted entries are dropped
silently, leaving Tasks' native emoji dates; in the common case the
pass lands before the next paint, so the emoji dates never flash.
Each task-created, task-scheduled, task-done, and
task-cancelled span without data-bob-date-mark whose inner text
ends in a canonical ISO date gets the same mark
(foldSpace: true, rendered: true, data-host="tasks") appended
inside the span, which is then flagged data-bob-date-mark="true";
short-mode spans (no date), invalid dates, task-due, and
task-start are untouched. The pass is idempotent, clicking a mark
still opens Tasks' own date editor (the click bubbles to Tasks'
span), and right-click postpone still works. relabelRenderedDateMarks
already covers Tasks-host marks through data-rendered="true", so
they roll over at midnight like every other rendered mark. In short
mode (rotten.md, crowded.md), CSS alone turns each date span
into a 1.08em glyph box drawing the shared field mask at the default
ink, resting from the row's data-task.
Recurring Tasks results use span.task-recurring as a fifth Tasks
host. In full mode the frame pass strips the leading 🔁 (with an
optional variation selector), validates the remaining rule with the
shared recurrence grammar, and appends the same loop mark used
elsewhere. The mark carries data-host="tasks"; the native inner span
is clipped while Tasks keeps its event listeners. Unknown shapes,
invalid rules, and open PRE/POST checklist members whose rule lacks
when done keep the native rule visible. Checklist membership comes
only from the row's .task-description tag pills, and the guard applies
only to open rows. In short mode, CSS replaces the recurring component
with the shared loop mask and rests it faintly for closed rows. With
date marks off, the existing Tasks-host cover hides stale marks until
Tasks redraws.
Rollover and toggle¶
The existing minute interval calls
refreshDateMarksForRollover(now): when the local date changed, it
dispatches dateMarksRefresh to every markdown editor and relabels
every .bob-date-mark[data-rendered="true"] in place (label,
aria-label, data-when). Live Preview widget DOM is never edited
in place. The command "Toggle task date marks" (id
toggle-date-marks) is session-only and on by default: it flips
body.bob-date-marks (which also gates the repair flag), dispatches
the refresh effect, triggers the Tasks re-render event, and shows
Date marks on / Date marks off. When off, JS creates no marks:
a Tasks-result frame that runs after toggle-off drops its queue
without writing, and onunload disables marks and clears the
Tasks queue/pending/dedup state so late callbacks cannot decorate
after unload. Re-enabling decorates new rows normally.
api.dateMarks v1¶
Frozen and additive (top-level api stays v3):
{ version: 1, fields: ["created", "scheduled", "completion",
"cancelled"], model(field, dateText), render(host, field, dateText,
options) }. Both are synchronous and never throw. render appends
to host and returns the element, or null for an unknown field or
a non-canonical date. options.decorative renders aria-hidden
with no tooltip; options.inheritColor makes the ink
currentColor. Nothing consumes the namespace yet; it exists so a
later Task Card or notice can show ⧗ Fri with the same glyph.
Rejected alternatives¶
Changing storage to Tasks emoji or relative text breaks the Tasks
Dataview format and Dataview's field index, rewrites thousands of
vault fields plus the bob-cli parsers and writers, and relative text
rots overnight. A CSS-only restyle of the Dataview pill cannot read
the value, so the ISO date would stay with no today/Fri and no
repair semantics. A CSS-only restyle of Tasks query results was
rejected for the same reason in full mode — CSS cannot split Tasks'
emoji from its date — while a global MutationObserver over Tasks'
DOM was rejected as wider than needed: the description
post-processor already fires once per result row, so one bounded
frame pass that degrades to Tasks' native emoji dates is enough, and
short mode stays CSS-only. An age voice for created (5w) adds a second
grammar and breaks the closed-task timeline. Weekday names for past
dates are ambiguous for scheduled. × for cancelled reads as math
next to + and as a close button. Per-field hues clash with the
status colors, and a past scheduled date is not overdue. Hiding
created on closed tasks drops data; the resting tone quiets it
instead. One lifecycle chip per task loses per-field reveal. Click
never opens a card or picker: display surfaces never act. due and
start are out of scope (see above).
Non-goals: storage, parser, Rust CLI/TUI, bob query, Bob Mac
Capture output; Task Card, notice, and picker rows (the api enables
them later); italic dates in Schedule/Work/Cancel Log entries; Tasks
group headings; project-note frontmatter properties; memory notes.
Conformance vectors¶
Today is 2026-10-07 (Wednesday) unless noted. ⏎ separates tooltip
lines. fold N is foldLength in Live Preview.
| # | Input | Expected |
|---|---|---|
| DM1 | - [ ] #task Buy milk [created:: 2026-10-07] |
created · today · when today · Created Wed, Oct 7 · today · fold 1 · quiet tone |
| DM2 | - [ ] #task Call mom [created::2026-10-06] ^call |
created · yesterday · Created Tue, Oct 6 · yesterday |
| DM3 | - [?] #task Ship [scheduled:: 2026-10-08] |
scheduled · tomorrow · Scheduled Thu, Oct 8 · tomorrow⏎Ctrl+Shift+P to reschedule |
| DM4 | [scheduled:: 2026-10-09] |
Fri · Scheduled Fri, Oct 9 · in 2 days⏎Ctrl+Shift+P to reschedule |
| DM5 | [scheduled:: 2026-10-13] |
Tue (Δ 6) · Scheduled Tue, Oct 13 · in 6 days⏎… |
| DM6 | [scheduled:: 2026-10-14] |
Oct 14 (Δ 7) · Scheduled Wed, Oct 14 · in 7 days⏎… |
| DM7 | - [ ] #task Rename [scheduled:: 2026-10-07] |
today · when today (emphasis tone) · Scheduled Wed, Oct 7 · today⏎… |
| DM8 | - [ ] #task Install [scheduled:: 2026-09-04] |
Sep 4 · when past (quiet tone) · Scheduled Fri, Sep 4 · 33 days ago⏎… |
| DM9 | - [x] #task Report [completion:: 2026-10-05] |
completion · Oct 5 (never a past weekday) · Done Mon, Oct 5 · 2 days ago · resting (CSS) |
| DM10 | - [-] #task Old [cancelled:: 2025-12-30] |
cancelled · Dec 30, 2025 · Cancelled Tue, Dec 30, 2025 · 281 days ago |
| DM11 | [scheduled:: 2027-01-02] |
Jan 2, 2027 · Scheduled Sat, Jan 2, 2027 · in 87 days⏎… |
| DM12 | today 2026-12-30, [scheduled:: 2027-01-01] |
Fri (Δ 2 across the year) · Scheduled Fri, Jan 1, 2027 · in 2 days⏎… |
| DM13 | - [x] #task Review skill [created:: 2026-08-29] [completion:: 2026-09-03] ^review |
two marks in order: created Aug 29 fold 1; completion Sep 3 fold 2 |
| DM14 | - [ ] #task A [fresh:: 2026-10-05] [created::2026-09-29] [scheduled:: 2026-10-09] |
created Sep 29, scheduled Fri; both ranges disjoint from the fresh mark's range |
| DM15 | - [ ] #task B (scheduled:: 2026-10-09) |
Fri |
| DM16 | - [x] #task C [ completion:: 2026-10-07 ] |
today |
| DM17 | - Idea for later [created::2026-07-03] |
created Jul 3 (plain bullet) |
| DM18 | > - [ ] #task Quoted [created:: 2026-10-01] |
Oct 1 · fold 1 |
| DM19 | - [ ] #task D x[created:: 2026-10-01] |
Oct 1 · fold 0 |
| DM20 | - [created:: 2026-10-01] starts the bullet |
Oct 1 · fold 0 (the field begins the content) |
| DM21 | Paragraph text [scheduled:: 2026-10-09] |
Fri (non-list line) |
| DM22 | - [ ] #task E `[created:: 2026-10-01]` |
untouched (code) |
| DM23 | - [ ] #task G [rescheduled:: 2026-10-09] [scheduled:: 2026-10-10] |
scheduled Sat; rescheduled untouched and not counted as a duplicate |
| DM24 | - [ ] #task [created:: 2026-10-07], cursor 12 (between the two spaces) |
created today; cursor in the run unfolds to fold 0 ([13, 35)); cursor 11 keeps fold 2; after typing b (cursor 13) fold 1 |
| DM25 | - [x] #task Review skill [created:: 2026-08-29] [completion:: 2026-09-03] ^review, cursor 48 |
completion fold 0 ([49, 74)); created stays fold 1 ([24, 47)) |
| DN1 | [scheduled:: 2026-13-01] |
no mark (repair pill) |
| DN2 | [scheduled:: tomorrow] |
no mark (repair pill) |
| DN3 | - [ ] #task F [scheduled:: 2026-09-10] (scheduled:: 2026-09-11) |
no mark on either (repair pills) |
| DN4 | [Created:: 2026-10-01] |
no mark (key case) |
| DN5 | [created:: 2026-10-01) |
no mark (mismatched brackets) |
| DN6 | [created :: 2026-10-01] |
no mark (key must touch ::) |
| DN7 | [created:: 2026-10-01T09:30] |
no mark |
| DN8 | [due:: 2026-10-09] / [start::1700] |
untouched, and never repair-flagged |
| DN9 | - [ ] #task H [scheduled:: 2026-13-01] [created:: 2026-10-01] |
created Oct 1 still marks; scheduled is a repair pill |
| RO1 | a rendered Fri mark (date 2026-10-09) when the day becomes 2026-10-08, then 2026-10-09 |
relabels in place to tomorrow, then today (data-when="today"); Live Preview editors get the refresh effect |
| T1 | a complete li (data-task="") with span.task-scheduled > span text " ⏳ 2026-10-09" |
a Fri mark appended inside the span, which gets data-bob-date-mark="true" |
| T2 | span.task-done > span text " ✅ 2026-10-05" |
a completion mark Oct 5 |
| T3 | short-mode span.task-created > span text " ➕" |
JS leaves it untouched |
| T4 | an li without data-task |
retried each frame, decorated once the attribute appears, left untouched after 60 frames |
| T5 | a second pass | adds nothing |
| T6 | span.task-due and span.task-start |
untouched |
| T7 | " ⏳ 2026-13-01" |
untouched |
| T8 | marks off; a non-Tasks connected el |
nothing is scheduled |
| T9 | a Tasks-host Fri mark on rollover |
relabels to tomorrow |
| RT1 | complete li with span.task-recurring > span text " 🔁 every day when done" |
a daily mark appended inside the span; span flagged; second pass adds nothing |
| RT2 | " 🔁 every week on Monday when done" / " 🔁 every month on the 1st" |
Mondays / monthly · 1st |
| RT3 | short-mode span.task-recurring > span text " 🔁" |
JS leaves it untouched; CSS draws the loop |
| RT4 | open li whose description has #gtd + #pre pills, rule " 🔁 every day" |
untouched (checklist guard) |
| RT5 | " 🔁 every day; x" / an li without data-task |
untouched / retried, then decorated or dropped as for dates |
| RT6 | marks off | nothing scheduled; a stale Tasks-host repeat mark is hidden by the cover rule |
| RM1 | - [?] #task #gtd #pre Brush teeth [repeat:: every day when done] [created:: 2026-10-21] |
daily, fold 2, quiet; Repeats every day when done⏎Next date counts from completion; created mark unaffected and disjoint |
| RM2 | - [ ] #task Water plants [repeat:: every day] |
daily; …⏎Next date follows the schedule (not a checklist row, so no guard) |
| RM3 | every week on Monday when done / every week on Sunday / every Friday |
Mondays / Sundays / Fridays |
| RM4 | every month on the 1st / every month on the last Friday / every month on the 2nd Wednesday |
monthly · 1st / monthly · last Fri / monthly · 2nd Wed |
| RM5 | every 30 days when done / every 28 days |
every 30 days / every 28 days |
| RM6 | every 1 week / every 3 weeks on Friday / every January on the 15th |
weekly / every 3 weeks · Fri / yearly · Jan 15 |
| RM7 | every week on Tuesday, Friday / every week on Tuesday and Friday / every weekday |
weekly · Tue, Fri (both) / weekdays |
| RM8 | every April and December on the 1st and 24th; every constructor; every week on constructor; every constructor on the 1st |
each unknown valid-charset rule is verbatim; when done is omitted from the label and retained in the tooltip |
| RM9 | (repeat:: every week) / [ repeat:: every day ] |
weekly / daily |
| RM10 | Every Day When Done |
daily; tooltip Repeats Every Day When Done⏎Next date counts from completion |
| RM11 | cursor inside the field / in its folded run | reveals that field only / unfolds to fold 0 |
| RM12 | - [x] #task #gtd #pre Old [repeat:: every day] (closed member) |
mark shown (guard covers open rows only), resting tone |
| RN1 | [repeat:: weekly], [Repeat:: every day], [repeat :: every day], [repeat:: every day; when done], [repeat:: every\tday], [repeat:: every day], tab padding, two repeat:: fields, [repeat:: every day) |
no mark (pill; repair-flag selector covers repeat); repeated ASCII spaces and uppercase cadence remain valid |
| RN2 | - [?] #task #gtd #pre Brush [repeat:: every day] / - [ ] #task Brush #gtd #post [repeat:: every day] |
no mark on either (the guard follows membership, not the glyph slot); the pill keeps the dashed orange flag |
| RN3 | - [ ] `[repeat:: every day]` |
untouched (code) |
| RR1 | reading view postprocessor invoked on a PRE/POST li root or containing wrapper; open li text holds [repeat:: every day] / … when done; closed li holds [repeat:: every day] |
no mark / daily mark for permitted when done and closed rows, regardless of root shape |
| RO2 | rollover over a rendered repeat mark | untouched; no error |
| RA1 | api.dateMarks.fields / api.dateMarks.model("repeat", "every day") |
unchanged four fields / null |
Today for RM/RN/RR/RO vectors is 2026-10-21 unless noted; ⏎ separates tooltip lines.
Live verification (Bryan, in Obsidian)¶
- [ ] All four glyphs and every label form look right in light and dark themes
- [ ] The cursor or a click reveals only that field's raw text
- [ ] Vim
cwon the word before a mark (and Backspacing that word without vim) types in order, before the mark - [ ] Tasks-written double-spaced
[completion:: …]fields sit with the same gap as single-spaced ones - [ ] Created reads quiet, scheduled-today reads stronger, and closed tasks rest
- [ ] A hand-broken
[scheduled:: 2026-13-01]shows the dashed repair pill - [ ] The toggle restores the pills and then turns the marks back on
- [ ] Reading view, embeds, and hover previews show the marks
- [ ] Labels roll over after midnight without a reload
- [ ] Fresh, priority, and date marks sit together cleanly on one line
- [ ] Metadata Menu does not double-decorate
- [ ] Mobile (iOS) renders the glyphs
- [ ]
dash.mdandblocked.mdTasks results show date marks - [ ] Clicking one opens Tasks' date editor, and right-click postpone works
- [ ]
rotten.mdandcrowded.md(short mode) show glyphs instead of emoji - [ ] Toggling off restores Tasks' emoji dates
- [ ]
gtd_daily.md,recur.md, andcash.mdrows showdaily,Mondays,monthly · 1stin Live Preview and reading view - [ ] A hand-typed
#task #gtd #pre … [repeat:: every day]withoutwhen donekeeps the dashed orange repair pill