The tagwerk file format
tagwerk keeps one Markdown file per day and nothing else. This page documents that format
completely: the folder conventions, every line rule the parser applies, and what the app
writes back into a file. It exists so your notes never depend on this app. Everything
described here can be written and read with an editor, a script or
grep.
1Scope and status
A tagwerk note is a plain CommonMark/GFM text file. Everything the format adds is written into the text of a line, in characters that stay readable when nothing knows what they mean. An editor that has never heard of tagwerk shows a note as ordinary Markdown with a handful of markers sitting in it as literal text.
The app is the reference implementation, and this page is written from its parser rather than from a plan for one. Where the two disagree, the app is wrong and we want to hear about it: .
You do not need permission or a library to write these files. The rules below are all there is. There is no index, no database and no hidden state that a note depends on.
2Files and folders
One file per day. The date lives in the file name and never in the content, so nothing inside a note can contradict the day it belongs to. The folder holding the notes is called the vault; it is a folder you choose.
Notes/ ← the vault root ├─ templates/ ← what a new day starts with (§15) │ ├─ template.md │ └─ template-monday.md ├─ settings/ ← everything that is not a note (§21) │ ├─ tagwerk.colors │ └─ tagwerk.license └─ 2026/ └─ 08/ ├─ 2026-08-08.md ├─ 2026-08-09.md └─ 2026-08-10.md
Names and paths
- A day note is named
YYYY-MM-DD.md. The extension is matched without regard to case. - Every date in this format — in a file name, in a forward marker, in a repeat's
anchor — is a Gregorian date, whatever calendar the device it was
written on prefers. A note written on a phone set to Thailand says
2026-08-13, not2569-08-13. - Files the app creates itself go to
<root>/YYYY/MM/YYYY-MM-DD.md. - Reading is layout-agnostic. A file named
YYYY-MM-DD.mdcounts as that day wherever it sits below the root, including flat in a single folder, which is how Obsidian and Markor write daily notes. An existing folder of notes is read as it is. - A save goes back into the file the note was loaded from, not into the canonical path. Pointing tagwerk at an existing folder never produces a second file for a day you were already keeping.
- If a day somehow exists twice, the canonical path wins; failing that, the alphabetically first full path does. The app logs which file it is ignoring.
Files that are not day notes
| Name | Meaning |
|---|---|
templates/ |
The day templates (§15): template.md,
template-monday.md, template-day23.md. Their
own folder, deliberately outside the day layout, so nothing that scans
for days reads one as a day. |
settings/ |
Everything in the vault that is not a note: the tag colours
(tagwerk.colors, §21) and the licence
(tagwerk.license). Its own folder for the same reason the
templates have one, and visible rather than hidden — the licence is a
file people are asked to find. A licence lying loose in the vault root is
still read; that was where it used to go. |
*.sync-conflict-tagwerk.md*.sync-conflict-tagwerk-2.md |
Written whenever a day ends up in two versions: the app's own sync found both sides changed, or another program wrote the file while tagwerk had that day open. It holds the version tagwerk did not write; the day file keeps the one it did. Numbered upwards and not overwritten. |
*.sync-conflict-*.md*(conflicted copy*.md |
Conflict copies from Syncthing and the Nextcloud desktop client. Also recognized: left out of the day listing and offered for review instead of being read as days. |
*.md.tmp |
Scratch file of an in-progress write (see below). Short-lived, and deleted when a write fails. Worth adding to a sync tool's ignore patterns. |
<file>.md.tmp and then moved over the original.
A sync tool watching the folder never picks up a half-written file, and an interrupted
process never leaves a truncated one behind.
Nothing else in the vault belongs to the app. History, sync bookkeeping and settings live in the app's own storage, not in your notes folder. A vault is notes, templates and whatever else you put there.
3Text conventions
- Encoding: UTF-8. The app writes no byte order mark. A file that has one is read correctly, but the mark is gone once the app rewrites that file. A byte that is not part of valid UTF-8 is read as Windows-1252, the code page older Windows editors save in, and the file is UTF-8 once the app rewrites it.
- Line endings: LF or CRLF. Whichever a file already uses is kept: if any line ends in CRLF, lines the app appends do too. A file with neither gets LF.
- Indentation: spaces or tabs. A tab counts as four columns wherever depth is compared (§6).
- Line by line: the parser never joins lines. A line's first characters decide what it is, and no line changes the meaning of the next. The one exception is a code fence, which suspends parsing until it closes (§4).
- Minimal writes: an edit rewrites the lines it changes and leaves every other line byte for byte as it was. The file is the source of truth; every view in the app is a view of it.
- An empty day: a file holding nothing but whitespace counts as a day with nothing on it. A day nobody has written on has no file at all.
- Inline Markdown is drawn, never rewritten:
**bold**,`code`and~~struck through~~are styled wherever they stand in a line — inside a task, inside an appointment, in prose. The characters stay in the file; the editor only steps them back, and shows them again on the line the cursor is on. Strikethrough follows GFM's flanking rule: no space after the opening tildes and none before the closing ones, so~~ nein ~~is text. On an appointment line struck from end to end the same characters also mean something (§8); everywhere else they are appearance and nothing more.
4Line types and precedence
Each line is tested in this order, and the first rule that matches decides. Anything that matches none is ordinary Markdown and passes through untouched.
| # | Line | Recognized as |
|---|---|---|
| 1 | ``` or ~~~, optionally indented — a run of
backticks only when no backtick follows it on the line, so
```npm install``` is inline code, not a fence |
Code fence delimiter. It toggles fenced mode: the delimiter and every line up to the closing delimiter are verbatim text. No tasks, no appointments, and no tags or contacts are found in them. |
| 2 | - [ ] … |
Task line (§5) |
| 3 | 13:00 … |
Appointment line (§8) |
| 4 | anything else | Text line. Headings, dividers, prose, lists, tables: Markdown. Tags and contacts are still found in it (§11). |
A fence that is never closed leaves the rest of the file verbatim, which is CommonMark's
behaviour too. It means a note can hold a code sample containing
- [ ] … without the app acting on it.
5Tasks
A task is a GFM task list item: optional indentation, a hyphen, one whitespace character, a bracketed state, then the text.
indent bullet state text
- [ ] Write the invoice @paul #office
| Marker | State | Meaning |
|---|---|---|
- [ ] | open | Still to do. Together with [/] the only state that counts as open anywhere in the app. |
- [/] | in progress | Begun and not finished. Open in every sense the app asks about — it is in the task list, it goes overdue, it is ticked off and forwarded like an open task — and drawn as begun. |
- [x] | done | Finished. [X] is accepted as well. |
- [>] | forwarded | Moved to another day. The copy lives there and the trail stays here (§7). |
- [-] | dropped | Given up on without doing it. |
Exact shape
- The bullet is a hyphen.
* [ ]and+ [ ]are Markdown lists, not tasks. - Exactly one whitespace character sits between the bullet and the bracket, a space or a tab.
- One optional whitespace character follows the closing bracket, so
- [x]doneis a valid done task. Phone keyboards produce lines like that, and losing them would be worse than accepting them. - The state character is one of
space,x,X,>,/,-. Anything else is not a task line.
- [ ]
with nothing written after it is a line somebody is in the middle of typing. It has no
tap target, does not appear in the task list, and does not count towards a day's open
tasks.
What the editor normalizes
While you type, the app rewrites a checkbox that is nearly right into the canonical form. The bullet may be missing or stuck to the bracket, and the box may be empty:
[ ] Water the plants → - [ ] Water the plants [x] Call the landlord → - [x] Call the landlord -[ ] Book the train → - [ ] Book the train - [] → - [ ]
Never inside a code fence. And never when the text is stuck to the bracket
and begins with (, which is what keeps a
Markdown link like [](https://…) from being turned
into a checkbox — nor when it begins with : or
[, Markdown's reference links:
[x]: https://… and [x][1]
stay as they are. With a space between them the bracket is a checkbox again, so
[ ] (later) call back normalizes like any other
line.
A checkbox another app drew as a character
A task list exported as plain text writes its boxes as characters rather than as brackets, and those are rewritten the same way:
☐ Clean the dishwasher → - [ ] Clean the dishwasher ☑ Called the landlord → - [x] Called the landlord ☒ Gave up on it → - [x] Gave up on it
The three characters are U+2610 BALLOT BOX, U+2611 WITH CHECK and U+2612 WITH X. Both ticked boxes arrive as done: this format tells “done” from “given up on”, and no exporting app means that difference by the character it picked — what both certainly mean is that the task is no longer open.
The box has to open the line and be followed by whitespace, so
Status: ☐ and a sentence mentioning the character stay
what they are. This rule runs where the bracket rule runs — while the note is
saved, and on a paste, so a list pasted in is a list on screen straight away rather than
the next time the day is opened. It is a translation into this format and not part of
it: nothing in tagwerk ever writes one of these characters.
In progress
- [/] is the spelling Obsidian themes, the Obsidian
Tasks plugin, Logseq and Bike use for a task somebody has started, and a vault coming
from one of them carries it. Ticking a begun task off makes it
[x]; taking the tick back makes it
[ ], not [/] — nothing
in the file says it had been begun. A forwarded copy of a begun task arrives begun
(§7); the next occurrence of a repeating one arrives open, with its sub-tasks open
(§10), because it is a new task.
Settling a task with sub-tasks
Ticking a task off, or dropping it, applies the same state to the still-open tasks — open or in progress — indented under it. A parent marked done with an open child underneath says two contradictory things. Sub-tasks that already carry a state (done, dropped, forwarded) keep it, and re-opening a parent leaves its block alone, because nothing in the file records which of them had been ticked before.
6Sub-tasks and descriptions
Indentation is the only thing that says “this belongs to that”. The lines directly below a task that are indented deeper than it are its block, up to the first blank line or the first line at the same depth or shallower.
- [ ] Weekly shop #errands Cash only, the card reader is broken. ← description - [x] Fruit ← sub-task - [ ] Bread ← sub-task - [ ] Something else ← blank line ended the block
- A task line in the block is a sub-task. Anything else is the task's description.
- Depth is counted in columns, a tab counting as four.
- A blank line ends a block whatever the indentation of what follows.
- When a task is moved to another day (§7) or handed out again by a repeat rule (§10), its whole block goes with it. The block is shifted left so it keeps the same depth relative to the copy.
- Nesting has no depth limit; a sub-task can have a block of its own.
7Forwarding to another day
Moving a task writes two lines in two files. The source day keeps a readable trail, the target day gets an ordinary open task.
2026-08-10.md - [>] Review the offer @paul >2026-08-12 2026-08-12.md - [ ] Review the offer @paul
- The marker is
>directly followed by an ISO date:>YYYY-MM-DD. That is the whole spelling — there is no second one, and a reader that accepts anything else accepts something this format does not define. - Nothing fences the sign off, so
-->2026-08-12carries a marker as well. A date the calendar does not have is not one:>2026-02-30is text. The one shape that could collide does not — markdown writes a quote as>with a space, and a marker never has one. - A marker may stand anywhere in any line, not only in a task: in
a sentence, under an appointment, in a heading. Wherever it stands it is a link to
that day, and an editor is expected to make it one. What is specific to a task is
only what the rest of this section describes — the state
[>]and the copy on the other day. When a line carries several markers, the first names the target. - The copy is written without any forward marker, and without the readings its tags
carried (§12). It is open, except where the task was in progress: a begun task
arrives as
- [/], because moving it says when, not that the work so far is undone. - Copies are independent lines of text. There are no IDs and no back-references anywhere in the format. Editing the copy never reaches back into the line that forwarded it, and deleting either leaves the other intact.
- The block under the task moves with it and is removed from the source day. A checklist left behind on the old day is a checklist nobody will look at.
- If the target day holds nothing yet, the day’s template is applied first (§15). The copy then lands under the same heading it sat under on the source day (§13).
- Since a copy has no identity of its own, an action that can be repeated checks the text instead: a line the target day already holds verbatim is not appended again. That keeps a checkbox ticked, unticked and ticked again from putting three copies on the same future day.
A date on its own
A date written without any marker — Rechnung vom
2026-01-01 prüfen — names that day and nothing more. It is not a
forward marker: no task is moved, no copy is written, and nothing reads it into a model.
An editor may offer it as a link to the day, and tagwerk’s does — except for the date
the note itself is, which leads where the reader already is and stays plain. A reader
that only parses the format ignores all of it, and both are correct.
- The shape is the same ISO date as everywhere else, fenced against digits and
hyphens on both sides: the middle of
4711-2026-01-01-99is not a day, and neither half of a range written2026-01-01-2026-01-05is. - A date the calendar does not have is text, exactly as with the marker.
- Where something else already owns the date, it keeps it: a web address (§14), a repeat rule’s anchor (§10), a tag’s reading (§12) — and a forward marker, which is the trail and stays it.
- This is a rule about presentation, not about meaning. The state
[>], the target of a moved task and everything in the rest of this section come from the marker alone. An implementation that draws no links has nothing to do here.
8Appointments and “not before”
Appointments
A line that begins with a clock is an appointment. No sigil, no keyword, because a clock is what people write anyway.
09:30-11:00 Sprint review @team
13:00 Dentist
9:00 - 9:30 Standup single spaces around the dash are allowed
- The time must start at the very beginning of the line. An indented time is not an appointment.
- One or two digits for the hour, exactly two for the minute. Hour 0 to 23, minute 0
to 59, so
25:00 Callis ordinary text. - An optional end time after a hyphen, with at most one space on either side. An invalid end time makes the whole line text; a half-read appointment is worse than none.
- Text has to follow the time.
13:00alone is a text line. - An end time before the start time is not rejected. The format does not know about appointments crossing midnight and does not pretend to.
- An appointment may carry a recurrence marker (§10) —
19:00 Mastermind R/2026-09-04/P4W. Its line stays where it was written; the rule says which further days it falls on, and those are drawn rather than stored. - An appointment whose whole text is struck through was called off —
19:00 ~~Mastermind~~. It is still drawn, struck: an hour that has come free is what a calendar is read for. On a day a rule falls on, it is also what takes the occurrence off that day, which is how one occurrence of a series is cancelled without touching the line that carries the rule.- Only the whole of it.
19:00 Mastermind mit ~~Paul~~is a meeting happening without Paul, and two runs with words between them are two struck words. - The words without the tildes are what the app compares — a cancelled occurrence has to be the same appointment as the one it cancels.
- Tokens on it still count, and a cancelled occurrence is reported apart from the rest (§17). It happened to be written; it did not happen.
- Tasks have their own states for this:
- [-]is a task given up on (§5), and a struck task is ordinary markdown.
- Only the whole of it.
“Not before” on a task
A single time directly after a task's checkbox says when the task starts being worth showing outside the note:
- [ ] 19:00 Omega 3 #health
- Same shape as an appointment's start time, because it is the same thing written by the same person. One time only, no range: a task becomes due at a moment and does not occupy a span.
- Whitespace or the end of the line must follow it, so
19:00Uhrstays a word. - Out-of-range times stay part of the title.
- The gate applies only on the day the task sits on, and only while that day is today. A day still ahead is its own gate, and on a day gone by every hour has passed. The day note always shows the task. The cross-day task list and the home screen widgets are what leave it out until the time comes.
- Held back, not hidden. The task list says underneath how many it is holding and from when — “one task from 19:00” — and that line unfolds on a tap into the tasks themselves, with their ordinary actions. Nothing is left out silently, and nobody has to open the note to reach an evening task.
9Priority
One character, standing alone: ! for important,
~ for “whenever”. Nothing between them means normal,
which is what almost every task is.
- [ ] Finish the report ! - [ ] Watch the next episode ~
- The marker has to stand alone. What may precede it: the start of the line,
whitespace,
(or[. What may follow: the end of the line, whitespace,),]or one of. , ; : ! ?. - So “Great news!” keeps its exclamation mark and
~~struck through~~keeps both tildes. They keep them everywhere; on an appointment line struck from end to end they also mean something (§8). - The first marker in a line decides. Position does not matter; by convention it goes at the end, and that is where the app writes it.
- Priority orders the cross-day task list (important first, “whenever” last) and colours the checkbox. Within a priority, tasks without a time (§8) come first and timed ones follow by their time; otherwise the order of the note holds. It never reorders lines in the file.
10Recurrence
How often something comes back is written into the line as an ISO 8601 repeating interval. The syntax is the standard's rather than one invented here, because a note is a text file other people read in other editors, and a syntax you can look up beats one only this app explains.
A task and an appointment both carry it, and it means two different things. A task is handed out: finishing with one writes the next copy into the day it is next due on, and the marker travels with that copy. An appointment is projected: the line stays on the day it was written on, and the rule says which other days it also falls on — the calendar draws those, including on days whose notes do not exist yet (§17). Nothing is written for them until somebody writes it.
19:00 Mastermind R/2026-09-04/P4W every four weeks, from the 4th 09:30-11:00 Standup R/P1W weekly, with an end time
- [ ] Take out the bins R/P1W every week - [ ] Water the plants R/P3D every three days - [ ] Meter reading R/P1M every month - [ ] Physio R5/P1W five more times, weekly - [ ] Team lunch R/2026-08-12/P1W every Wednesday
A length cannot say “every third Tuesday of the month”, so where a length will not do,
a calendar rule stands in the same place — RFC 5545's
RRULE, restricted to whole days. It is the other half
of the same bargain: still a standard you can look up, still readable by a calendar
application, and reached for only when the short form has nothing to offer.
- [ ] Jour fixe R/FREQ=MONTHLY;BYDAY=3TU every third Tuesday - [ ] Invoices R/FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1 the last working day - [ ] Standup R/FREQ=WEEKLY;BYDAY=MO,TH Mondays and Thursdays - [ ] Course R/2026-09-15/FREQ=MONTHLY;BYDAY=3TU;UNTIL=20270630 and then it stops
Grammar
R [count] "/" [ anchor "/" ] ( "P" duration | rule ) count digits; how many more occurrences the line is responsible for. Absent = forever. anchor YYYY-MM-DD; the interval's start date, and a rule's DTSTART. duration date-only ISO duration: nY nM nW nD, at least one number. rule RFC 5545 recurrence rule, date-only; FREQ first, parts separated by ";".
- Case-insensitive, because phones capitalize the first letter of a line for you.
- Boundaries as for priority (§9), so the letters inside a word or a URL are never read as a rule.
- Only the date part of a duration. A note is a day, so an interval measured in hours
would have nothing to land on and
PT2His plain text. - Rules with no meaning stay plain text; nothing is silently corrected. That covers
R0/P1D(fires never),R/P0D(never advances), an impossible anchor such asR/2026-02-31/P1M, and any calendar rule the standard does not allow —R/FREQ=WEEKLY;BYDAY=3TUasks for the third Tuesday of a week. - The duration is the preferred spelling, and it is enforced rather than
recommended. A calendar rule that a duration says just as well is written
back as the duration:
R/FREQ=WEEKLYlands in the file asR/P1W. Only a rhythm no length can express stays a rule.
Calendar rules
The whole date-level vocabulary of RFC 5545 §3.3.10 is read:
FREQ (DAILY,
WEEKLY, MONTHLY,
YEARLY), INTERVAL,
UNTIL, WKST,
BYMONTH, BYWEEKNO,
BYYEARDAY, BYMONTHDAY,
BYDAY and BYSETPOS,
with the standard's own restrictions on which may stand beside which frequency. The
anchor is DTSTART; without one, the day the line sits
on is. Where a part is left out that the frequency would otherwise expand over, its
value comes from that start date, exactly as the standard says.
Two parts are deliberately refused, and a rule carrying either is plain text:
COUNT, because the marker already has one and it does not mean the same thing. RFC's counts every occurrence from the start date;R3/counts how many hand-outs are left, which is what survives the task walking forward. WriteR3/FREQ=MONTHLY;BYDAY=3TU.BYHOUR,BYMINUTE,BYSECOND, for the reasonPT2His refused. For the same reasonUNTILtakes the date form (UNTIL=20270630) and not the date-time one.
UNTIL is the one thing in the format that can end a
rhythm by date: past it the task is settled and no copy is handed out at all, which is
not the same as a count running out — there the last copy still arrives, it simply
carries no marker.
Anchored or floating
Without an anchor, the next date is measured from the day the task is on — not from the day it is ticked off. A bin task on Wednesday that is ticked off on Thursday still comes back on a Wednesday; one that is moved to Thursday first comes back on a Thursday, and walks a day forward every week it is moved. With an anchor, the dates are the anchor plus whole intervals, wherever the task is moved and whenever you happen to tick it off, and that is what turns “every seven days” into “every Wednesday”. An anchored monthly rule starting on the 31st stays on the 31st in the months that have one, because each occurrence is counted from the anchor and not from the occurrence before it.
What happens when the task is settled
Finishing a repeating task appends the next occurrence to the day it is next due. Ticking it off and dropping it both settle it. The line you settled stays as it is, so the day keeps its record.
- The next date is the first occurrence after the day the task sits on that is not before today. Today itself counts: a daily task left on yesterday and ticked off this morning is due today, not tomorrow. A weekly task ticked off three weeks late skips the dates that went by and comes back on the next one of its rhythm, so it does not land straight back in the overdue list it just came out of — a repeat count tracks how often the task is handed out, not how many dates the calendar passed while it sat there.
- The copy carries the rule one step down: unchanged when it repeats
forever, one fewer when it is counted, and no marker at all on the last of a counted
run. Leaving
R1/P1Won that copy would promise a repeat that never comes. - Sub-tasks arrive re-opened and the readings on its tags are left behind (§12). A sub-task that carries a rule of its own hands out no copy while a task above it repeats and holds it in its block: that task's copy is where it comes back. Under a task that does not repeat it hands out its own.
- There is no series object. Each occurrence is an independent line of text. Editing one never reaches into the others, and deleting a line ends the series.
R/2026-09-15/P4W starts on the third
Tuesday of September 2026 and is a week early by October, two weeks by January and four
by July — thirteen dates a year where the calendar has twelve. That was the honest
approximation while the format had only lengths in it; it is not one any more.
11Tags and contacts
Two inline tokens, valid anywhere in a line and on every kind of line:
#tag and @name.
- [ ] Write the invoice @paul #office 09:30 Sprint review @team #project/api Called @mira about the move. #family
| Token | Characters | Boundary rule |
|---|---|---|
#tag |
Unicode letters and digits, _, -. Nesting with
/: #project/api/docs. |
A word character must follow the # immediately, and the
# must not be preceded by a word character or another
#. |
@name |
Unicode letters and digits, _, -. No nesting:
@paul/pm is the contact paul followed by
text. |
The @ must not be preceded by a word character. |
What the boundaries buy:
# Officeis a Markdown heading,#officea tag. The space is the whole distinction.mail@example.comstays an e-mail address. There is no contact called example in it.##somethingis neither a tag nor a heading.- Nothing inside an
http(s)://address counts. The#equipmentat the end of a configurator link and the@52.5200,13.4in a map link are part of the address (§14). - Lines inside a code fence carry no tokens at all (§4). An inline code span is not
excluded: a
#tagbetween backticks still counts.
How tokens compare
- Case-insensitively.
#Büroand#büroare one tag everywhere in the app. - In the statistics a nested tag counts towards its parent: asking
about
#projectincludes#project/api, and the figures say how many of the mentions came from a child.#projectoris a different tag — the boundary is the slash, not the prefix. - The filters do not. A chip matches the token as it is written, so
filtering by
#projectshows the lines carrying exactly that and not the ones carrying#project/api. The two rules differ on purpose in the app as it stands; a filter is a question about one token, a statistic a question about a subject. - The tag catalogue lists literal names, so
#projectand#project/apiare two entries in it — and two chips to filter by. - A sub-task is filtered with its parents. For the task list and the
widget a sub-task counts with its own tags and contacts and those of every task
whose block it stands in (§6), so excluding
#projectremoves the task and its checklist, and asking for it brings the checklist along. The row still shows only what is written on its own line. A nested tag on a parent is passed down as it is written — the rule above, one level further.
@anna-lena and
#one-on-one possible — so it can never also end one. A
compound whose first half happens to be a contact is therefore not a mention of that
contact: @Trelleborg-Drillmodul is the contact
Trelleborg-Drillmodul, written once and never again, and
@Trelleborg is not in that line at all. Nothing about it
reads as wrong — the whole compound is coloured as a token, the search finds it, the
catalogue lists it — which is why it is only noticed weeks later, when the person's own
lines are missing from their statistics.
Where the grammar wants the hyphen, the token has to do without it. Write
@Trelleborg Drillmodul, or turn the phrase around and
put the token last: Drillmodul von @Trelleborg. German
is where this bites, because a compound there is one word by default and the hyphenated
spelling is the correct one; in a note it names somebody who does not exist. The same
holds for a tag — #Angebot-Trelleborg is one tag, not
#Angebot with a word behind it.
12Readings on a tag
A tag can carry a value after a colon. The tag itself stays the tag, so filtering and
the catalogue still see one #weight and not one tag per
measurement.
Weighed myself #weight:81.4 #habits Electricity meter #power:473574 - [ ] Evening walk #feeling:good Two meters in one line: #power:8651 #power:8700
- The value takes Unicode letters and digits,
_,%,+,-, and.or,inside it. That keeps a sentence's full stop out of the number:#mood:7.is seven, and#pace:5.5is five and a half. - A second colon ends the value.
#time:09:00holds the reading09with:00behind it as ordinary text. - A line may carry the same tag more than once with different readings.
Numbers and words
A reading is a number when it parses as one with at most one separator
and an optional leading sign, and nothing else. No exponents, no currency symbols. Both
separators are accepted because both get typed:
12,5 and 12.5 are the
same value. Two separators make it a word, because
1.234,56 is a thousands separator somewhere and a
decimal point somewhere else depending on who wrote it, and guessing wrong turns twelve
hundred into one point two.
Numbers get minimum, maximum, sum, average, median and standard deviation, plus a chart over time. The standard deviation is the population form, since these are all the readings there are and not a sample drawn from more. Anything that is not a number is a word and gets counted instead.
#weight:81.4 arrives on the next day as
#weight:. The tag says what the task is about; the
number was an observation of the day it was written on. The line that stays keeps
everything.
A tag waiting for a reading
A tag written with a colon and nothing behind it —
- [ ] Cold shower #coldshower: — is a line waiting for a
value. It parses as the tag alone: the colon is not part of the token, and the tag counts
towards the same #coldshower as any other mention. What
it says is that a reading is expected and has not been written yet, which is exactly the
state the copy above arrives in.
The app asks for one when such a task is ticked off, and writes what is typed behind the colon. Dropping a task asks nothing — a task that did not happen has nothing to have measured — and a value left blank leaves the tag waiting. A tag with no colon is never asked about.
The colon only means this where a reading could stand behind it. In
#weight:.5 the text .5
is not a reading (a separator may only stand inside one, see above), so that tag is not
waiting for anything — writing a value in front of it would change what the line says.
13Headings and dividers
People group their days, and a task that moves to Friday should land under the same heading there. Three kinds of line separate a note:
| Line | Kind | Strength |
|---|---|---|
# … ###### |
ATX heading, CommonMark's rule: up to three leading spaces, one to six hashes, a space, then text. | 1–6 by hash count |
--- Habits --- |
Named divider. Not CommonMark, but it is what people write for a labelled break, and it reads as one in any editor. Hyphens only, at least three a side, whitespace around the title. | 2 |
--- *** ___ |
Thematic break. Ends a section without naming a new one. | 2 |
A section runs from its heading to the next line that separates at least as strongly, or to the end of the file. A blank line does not end a section. Blank lines are how people breathe in a text, and treating one as an end would file tomorrow's task above the tasks it belongs with.
Where a travelling task lands
A task moved to another day, or handed out again by a repeat rule, keeps the section it sat in:
- The heading is matched against the target day's lines, trimmed and compared literally. Found: the task is appended after the section's last non-blank line.
- Not found: the heading itself is appended to the note, and the task under it, so the day it arrives on is as tidy as the one it left.
- The task sat under no heading: it is written before the target day's first heading (after the lines that stand above it, before the blank lines that set the first section apart), so it stands where the day begins, as it did on the day it came from. A day without headings gets it at the end. Appended to the end, a task would land inside the last section of any day that ends in a heading — and the next move would carry it along as one of that section's tasks.
A plain divider between a line and the heading above it means that line belongs to no section, because the divider ended whatever was above it.
A task written from the task list is filed by the same three rules. The difference is only where the heading comes from: it is chosen rather than inherited — from the headings the target day names, or from the ones its template names while the day is still empty. Choosing none is the one difference: a new task is a new line, and a new line without a heading goes to the end of the note.
14Web addresses
A written-out http:// or
https:// address is recognized in any line. The editor
underlines it and offers to open it, and nothing inside it counts as a tag or a contact.
The address stays ordinary editable text in the file: there is no link syntax of
tagwerk's own.
- Only http and https, only written out in full (in any case:
HTTPS://counts too). - Nothing else. No “www.” guessing,
no bare domains, and above all no other schemes. A
file:orjavascript:that the app opens on a tap would be a hole, not a feature. - Trailing sentence punctuation is not part of the address:
. , ; : ! ? … * _ ~at the end are trimmed off. - A closing bracket is dropped only when it is unbalanced, so
(see https://…)loses its bracket and…/wiki/Auto_(disambiguation)keeps it. - A scheme with no host,
https://on its own, is somebody typing rather than a link.
Markdown links
The Markdown spelling [title](https://…) is read as one
link over the whole markup — not as an address with brackets around it. What that
changes is what a surface shows: the title is what a reader sees, so tagwerk’s editor
draws it as the link and folds the brackets and the address away until the cursor
touches them, and a narrow row or a widget card shows the title where it would
otherwise show the site. The file keeps every character either way.
- Only an
httporhttpstarget, by the same rule as above.[Note](2026-08-10.md)and[File](file:///…)are text. - The title has to say something.
[](https://…)and[ ](https://…)would leave nothing to read or to aim at, so they stay text — and the address inside them is found the way any written-out address is. - The closing bracket ends the address, so nothing is trimmed off it:
[Page](https://example.com/a.)points at…/a., full stop included. Parentheses inside the address are counted instead, one level deep — which is what keeps…/wiki/Auto_(disambiguation)whole and keeps([Offer](https://…))from swallowing the bracket that is not its own. - Nothing inside the markup is a tag or a contact, the title included: it is the link’s label, and a tag picked out of it would file the note under something nobody wrote.
- No square brackets in the title, and no line break anywhere in the link.
Every other Markdown link form is markup nothing here reads — reference links
([title][ref]), angle-bracket targets
((<https://…>)), a title inside the parentheses
((https://… "Title")) — and stands in the note as the
characters it is, with whatever written-out address it contains found as usual. An
image is the one that looks different and is not: in
 the
! is ordinary text in front of an ordinary link, so
the line reads !alt and the tap opens the image.
Nothing is embedded — see §20.
15The day templates
The files in templates/ below the vault root hold what
a new day starts with. A template is plain note text, so whatever the format allows is
allowed in it, headings and recurring tasks included, and it is as readable and as
syncable as the notes beside it.
Notes/templates/ ├─ template.md ← the default: any day ├─ template-monday.md ← Mondays └─ template-day23.md ← the 23rd of each month
templates/template.md
## Morning
## Work
--- Habits ---
- [ ] 07:00 Run #sport
- [ ] Weigh myself #weight
Names
template.mdis the default.template-<weekday>.mdis one weekday, every week. The weekday is its English name (monday…sunday) whatever language the app runs in — file names sync between devices whose languages need not agree. The UI shows localized labels.template-day<n>.mdis one day of the month, every month, withnfrom 1 to 31. Atemplate-day31.mdsimply never matches in a shorter month.- Reading is forgiving: case does not matter, and a missing leading zero
(
template-day5.md) counts. Writing is strict — the app writes lower case with the day always two digits (template-day03.md), so two devices never sync two files for the same day and the folder sorts by day in any client that lists it alphabetically. Files in the folder whose names are neither of these are yours and are left alone. - A
template.mdloose in the vault root is the pre-folder location from earlier versions and is ignored.
Which template a day takes
- The most specific one that exists: its day of the month first,
then its weekday, then the default. On a Monday
the 23rd,
template-day23.mdwins overtemplate-monday.md, which wins overtemplate.md. - The winner is taken whole — templates are never merged, so what a day starts with is always one file you can read. A template holding only whitespace counts as absent, and the next in line answers.
How it behaves
- A template is applied wherever a day is first written to: when a day holding nothing is opened, and when a moved or repeating task lands on one. That second case is what makes the headings worth anything, because the arriving task sorts itself under the matching heading instead of landing at the end of an empty file.
- A day nobody touches stays a day without a file. Applying a template writes nothing on its own.
- A file holding only whitespace counts as holding nothing, so a day that was opened and left still gets its template next time.
- The templates are carried by the built-in sync, so every device builds its days the
same way. A conflicting copy is kept beside its template as
template-monday.sync-conflict-tagwerk.mdand stays a file. It is not a day and never appears in the conflict review for one. - Removing a template is the one deletion the built-in sync carries to the other side — day notes are only ever restored, never deleted (§17). The removal only wins while the server still holds exactly the version this device last synced; anything newer there is somebody's edit and comes back instead.
16A complete example
One file, using everything above.
Notes/2026/08/2026-08-10.md
# Work
07:00 Run #sport
09:30-11:00 Sprint review @team #project/api
- [ ] Finish the offer @paul ! #office
- [x] Check the numbers
- [ ] Have it proofread @mira
Send as PDF, they cannot open .docx.
- [>] Verify the backups >2026-08-12
- [ ] Take out the bins R/2026-08-12/P1W
- [ ] 19:00 Omega 3 #health
- [-] Prepare the meeting
--- Private ---
- [ ] Get a gift for @mira #family ~
- [x] Weighed myself #weight:81.4 #habits
Everything else is **Markdown**: headings, lists, code.
Notes on the release: https://example.org/notes#changelog
What the app reads out of it:
- Two appointments (07:00, 09:30 to 11:00) and nine task lines, five of them open.
- “Finish the offer” is important and has one done sub-task, one open sub-task and a description. The open sub-task counts as its own task in the cross-day list, one level indented.
- “Verify the backups” is a trail. The live copy is on 2026-08-12.
- “Take out the bins” comes back every Wednesday. Ticking it off on any day appends
- [ ] Take out the bins R/2026-08-12/P1Wto the next Wednesday, under a# Workheading there. The section a task sits in travels with it, and is written out if the target day has none. - “Omega 3” is hidden from the task list and the widgets until 19:00, on this day only. The note shows it all day.
- “Get a gift” sits in the
--- Private ---section and is marked “whenever”. Moved to another day, it lands under a--- Private ---there. - One reading:
#weight= 81.4 on 2026-08-10. - Tags
#sport,#project/api,#office,#health,#family,#weight,#habits; contacts@team,@paul,@mira. The#changelogin the last line is part of the address and is neither.
17What the app derives from a note
Everything below is a view of the files. None of it is stored in them, and none of it is needed to read them.
- The day view renders the note as it is written and writes single lines back. Headings can be folded away by title, across all days.
- The cross-day task list collects every open
- [ ]and begun- [/]from every day. Open on a day before today means overdue. It filters by horizon (overdue · today · 7 / 14 / 30 days · all) and by tag and contact (a sub-task counting with its parents' tokens, §11), puts important first and “whenever” last, keeps sub-tasks with their parent, unfolds the ones a time is holding back (§8), and jumps to the source line on a tap. - Statistics summarize one tag — or one contact — across the vault: how many lines and days carry it, what became of the tasks among them, and, for a tag, its readings as numbers or as counted words (§12). A contact carries no reading, so it is the counting alone.
- The overview of one tag or one contact gathers its open and begun tasks, its appointments in the next 90 days (recurrences included, cancelled occurrences left out), the tasks done with it, its statistics and every line that carries it, newest day first. Lines belong to it by the rule the statistics and the search share (§11): case-insensitive, and a tag takes in what is nested under it. Nothing about a person is stored anywhere but in these lines.
- Search scans every line of every note, newest day first, with no
index to build or invalidate. A query is read word by word and every part has to
hold: words,
"a phrase",#tag(the tag or one nested under it, not a substring),@name, a leading-on any of them to rule it out,before:/after:with a date, and — with Pro —is:for task states and line kinds. Case and accents are folded — “strasse” finds “Straße”, “muller” finds “Müller” — by comparing a folded copy of each line, so the cost is paid once when a note is read rather than on every keystroke. A date typed into the search box (2026-08-13,13.8.2026,13.8.) offers that day directly. - History keeps earlier states of a day in the app's own storage: up to 20 per day, nothing older than 180 days, never the same text twice in a row. They are whole texts rather than diffs, and they are recoverable convenience data, so the app works with them thrown away. Restoring keeps the state it replaced, which means a restore can be undone.
- Sync (WebDAV, built in) compares a local content hash and the remote ETag against what was true at the last successful sync, so clock skew between devices cannot corrupt the outcome. Both sides changed means conflict, and a conflict keeps both versions (§2). Deletions of day notes do not propagate: a file missing on one side is restored from the other. A removed day template is the one exception (§15).
- Export writes every note into a ZIP in the same
YYYY/MMlayout, plus the day templates undertemplates/. No bookkeeping, no conflict copies, UTF-8 without BOM. - Widgets show the open tasks of a day. The “not before” time is carried into their cache — for every day the cache holds, not just the day it was written on — so the home screen can work out both “today” and “now” for itself after a midnight the app slept through.
Notes changed by a sync client or another editor are picked up by comparing file stamps, checked at most every couple of seconds. External writes appear without the app having to be restarted.
18Interoperability
The point of the format is that other tools can work on these files. What follows is what you can rely on.
| Written as | Elsewhere |
|---|---|
- [ ], - [x] | Standard GFM. Renders as a checkbox in Obsidian, Markor, GitHub, VS Code. |
- [>], - [-], - [/] | Renders as a list item with the character in brackets. Harmless text. Several Obsidian themes draw [/] and [-] as states of their own. |
>2026-08-12, R/P1W, !, ~ | Plain text. At the start of a line, >2026-08-12 renders as a block quote — which is why the app writes markers at the end of a line. |
#tag, @name | Plain text, or a real tag in editors that have the same convention (Obsidian tags, for one). |
13:00 Dentist | An ordinary paragraph. |
--- Habits --- | A paragraph. Reads as a labelled break either way. |
--- | A thematic break, as CommonMark says. |
From the command line
# every line mentioning the office grep -rn "#office" Notes/ # everything still open, oldest first grep -rn -- "- \[ \]" Notes/ | sort # what was moved, and where to grep -rn -- "- \[>\]" Notes/ # one tag's readings, one per line grep -rho "#weight:[0-9.,]*" Notes/ | sed 's/#weight://' # the notes as a git history cd Notes && git init && git add . && git commit -m "notes"
Writing these files yourself
- Appending a task is appending a line. There is nothing to register and no index to update.
- Keep a file's existing line endings, and write UTF-8 without a BOM.
- Be careful with Markdown formatters. A tool that reindents or renumbers list items can move a sub-task out of its block (§6), since indentation is meaning here and not style.
- Two independent writers of the same file need a conflict story. tagwerk's own sync keeps both versions. A folder shared through Syncthing or the Nextcloud client produces the conflict copies of §2, which the app then offers for review.
- You may write a day file that tagwerk currently has open, and it will not be overwritten in silence: before saving, tagwerk checks whether the file still holds what it read, and keeps whatever it finds instead as a conflict copy (§2). Your version survives; which one wins the day file is then a decision in the app.
19Pattern reference
The patterns the parser actually uses, in .NET/PCRE notation. They are given here so an
implementation can match tagwerk exactly rather than approximately.
\p{L} is a Unicode letter,
\p{M} a combining mark (the second half of a decomposed
"ü") and \p{N} a Unicode digit. Three of them are wrapped over
several lines to fit the page; they hold no line breaks and no whitespace at the wrap.
Task line ^\s*-\s\[(?<state>[ xX>/-])\]\s?(?<text>.*)$ Appointment line (whole line, from column 0) ^(?<sh>\d{1,2}):(?<sm>\d{2})(?: ?- ?(?<eh>\d{1,2}):(?<em>\d{2}))?\s+(?<text>\S.*)$ plus: hours ≤ 23, minutes ≤ 59 "Not before" (against the task text, after the checkbox) ^(?<h>\d{1,2}):(?<m>\d{2})(?=\s|$) Forward marker >(?<date>\d{4}-\d{2}-\d{2}) A date on its own (§7; a link, not a marker — the editor's rule) (?<![-\d])\d{4}-\d{2}-\d{2}(?![-\d]) Priority (?<![^\s(\[])(?<marker>!|~)(?![^\s)\].,;:!?]) Recurrence (case-insensitive) (?<![^\s(\[])R(?<count>\d*)/(?:(?<anchor>\d{4}-\d{2}-\d{2})/)? (?:P(?=\d)(?:(?<y>\d+)Y)?(?:(?<m>\d+)M)?(?:(?<w>\d+)W)?(?:(?<d>\d+)D)? |(?<rule>FREQ=[A-Z]+(?:;[A-Z]+=[A-Z0-9,+\-]*[A-Z0-9])*))(?![^\s)\].,;:!?]) the rule branch finds the shape; §10 decides whether it is one Reminder (§23, case-insensitive) (?<![^\s(\[])C/(?<body>P(?=\d|T\d)(?:(?<d>\d+)D)?(?:T(?=\d)(?:(?<h>\d+)H)?(?:(?<m>\d+)M)?)?)?(?![^\s)\].,;:!?]) Contact (?<![\p{L}\p{M}\p{N}_])@(?<value>[\p{L}\p{M}\p{N}_-]+) Tag, with an optional reading (?<![\p{L}\p{M}\p{N}_#])#(?<value>[\p{L}\p{M}\p{N}_-]+(?:/[\p{L}\p{M}\p{N}_-]+)*) (?::(?<reading>[\p{L}\p{M}\p{N}_%+-]+(?:[.,][\p{L}\p{M}\p{N}_%+-]+)*))? ATX heading ^ {0,3}(?<hashes>#{1,6}) +\S Named divider ^ {0,3}-{3,}[ \t]+(?:\S|\S.*\S)[ \t]+-{3,}$ Thematic break ^ {0,3}((-\s*){3,}|(\*\s*){3,}|(_\s*){3,})$ Code fence delimiter ^\s*(`{3,}(?!.*`)|~~~) Day note file name ^(?<date>\d{4}-\d{2}-\d{2})\.md$ case-insensitive Template file name (§15; reading is forgiving, writing is not) ^template(?:-(?<suffix>[a-z]+|day0?[1-9]|day[12]\d|day3[01]))?\.md$ case-insensitive Web address (trailing punctuation trimmed afterwards, see §14) https?://[^\s<>"'`\\]+ case-insensitive Markdown link (§14; the closing bracket ends the address, so nothing is trimmed off it) \[(?<title>[^\[\]\n]+)\]\((?<url>https?://[^\s()]*(?:\([^\s()]*\)[^\s()]*)*)\) case-insensitive Vault link (§22; the anchor is split off the target afterwards) (?<!!)\[\[(?<target>[^\[\]|\n]+)(?:\|(?<label>[^\[\]|\n]*))?\]\] Cancelled appointment (§8; matched against the text after the time, trimmed) ^~~(?<inner>(?:(?!~~)[^\n])+)~~$ Struck-through text anywhere in a line (§3; appearance only — the editor's rule) ~~(?![\s~])([^~\n]*[^\s~])~~
# and
its reading; the reading is read separately.
20Not part of the format
Listed so you know it is missing on purpose. None of the following is read, and all of it would sit in a note as ordinary text.
- YAML front matter. No metadata block. The date is the file name, and nothing else in a note is machine-owned. A block another tool wrote is left alone: a task moved to such a day lands after it, never inside it.
- IDs of any kind. No task IDs, no series IDs, no back-references. A copy is a copy of the text, which is why every operation stays a line edit.
- Bookkeeping about a task. No created-at, no completed-at, no time tracking. A day note records what a day held; the app's history records what changed. The one duration a line may carry is a reminder's lead time (§23) — which is not bookkeeping but something a person writes because they mean it, and which stays readable as the characters it is in any editor. That is the line: a field the app writes and reads behind the writer's back is out, a request the writer typed is in.
- Time zones. A time in a note is local wall-clock time, as written, and a day is a day.
- Hours and minutes in a recurrence. Date-only durations and
date-only calendar rules, because a note is a day —
PT2H,BYHOURand the date-time form ofUNTILare all plain text (§10). COUNTinside a calendar rule. The marker carries the count, and the two do not mean the same thing (§10).- Embeds, per-file settings, and anything a link implies beyond opening a
file.
![[…]]is text, and so is every other transclusion spelling: nothing is laid into a note from elsewhere. Wiki links themselves are read since 2026-09-04 — as a way to a file and nothing more, with no index of note names, no back-references and no completion while typing (§22).
21The tag colours file
settings/tagwerk.colors gives tags a colour. The app
draws them in the calendar, in the note and in the home-screen widgets; nothing about a
note changes, and no note ever refers to this file. A vault without it is a vault whose
tags have no colours, which is the ordinary state.
# tagwerk — colours for tags. One "#tag: colour" per line. # Names: mint, green, cyan, blue, lavender, rose, amber, slate, or a hex value like #3b82f6. #work: blue #project/api: lavender #sport: #3b82f6
Lines
- One assignment per line: a tag, a colon, a colour. Spaces around either are ignored.
- The tag is written the way it is written in a note, sigil included — whatever §11
accepts as a tag is accepted here, and nothing else. A tag carrying a reading
(
#mood:7) is not a tag this file can colour: the colour belongs to the tag, not to one of its readings. - The colour is one of the eight names above, or a
hex value — three or six digits,
#f00as well as#ff0000. Names are matched without regard to case. Eight digits are refused: a see-through fill has no brightness to derive readable text from. - A line this cannot read is skipped, not an error. A hand-written file is allowed a typo without taking the colours with it — and the app keeps such lines, and comments, when it writes the file again, after its own lines and in their order. A line for a tag the app now colours is replaced by its choice.
- A tag named twice takes its last line. The file reads top to bottom.
- A line beginning with
#— hash, space — is a comment. That is not a special rule: a tag's name starts immediately after its sigil, so# anythingwas never a tag.
What a colour applies to
- Nesting inherits. With
#project: bluein the file,#project/apiis blue without a line of its own, and so is#project/api/docs. A line of its own always wins over what it inherits. Note that the filters read a nested tag the other way (§17) — a filter answers “did you mean this tag”, a colour answers “what does this belong to”. - One colour per line of a note. Where a line carries several coloured tags, the first one written wins.
- Tags are matched without regard to case, like everywhere else:
#Büroand#büroare one tag with one colour.
tagwerk.colors is what the app writes and what another
tool should write. Android's file providers do not always keep it: creating a document
whose name does not carry the extension of its MIME type appends one
(tagwerk.colors.txt), and a name already in use is
numbered (tagwerk.colors (2).txt). Those are read as this
file, newest first, and the next save writes the canonical name again and removes them.
The same holds for tagwerk.license.
No pattern for this file appears in §19, and that is deliberate: it has none of its own. What counts as a tag here is decided by the tag pattern in §11, so the two cannot drift apart.
22Vault links
[[Notiz]] points at a file in a folder of the reader's
own. It is the spelling other note editors use, and it is read here for exactly one
purpose: to open that file. There is no index of note names, no back-reference, no
completion while typing and no embedding — see §20.
- [ ] Angebot prüfen [[Projekte/Kunden/Meier]] Siehe [[Meier|das Angebot]] und [[Anhänge/Vertrag.pdf]]
- The target is what stands before an optional
|: a bare name ([[Notiz]]) or a path from the root of a linked folder ([[Ordner/Notiz]]). Forward slashes, in a note written on any platform. - The label after the
|is what a reader sees instead of the target. It has to say something:[[Notiz| ]]would leave nothing to read or to aim at, so it stays text — the rule §14 applies to an empty Markdown title. - An anchor — everything from the first
#of the target — is read and then dropped: no file is namedNotiz#Kapitel, and the file is opened at its beginning. It is part of the markup all the same, so nothing inside it counts as a tag or a contact. - No extension means
.md, and a target that carries one means that file. Both are tried either way round, because a name may hold a full stop without that being an extension:[[v1.2 Notizen]]findsv1.2 Notizen.md. - No brackets, no pipe and no line break inside either part.
[[#Kapitel]],[[ ]]and half-written markup are text. ![[…]]is not a link. An embed asks for the file to be laid into the text, which this format does not do — and a link that silently opened it instead would answer a different question than the one the writer asked.
What a link resolves against
The folders are the reader's own, listed in the app and searched in the order they stand in. Where a target names a path, the folder that has that path answers and the rest are not searched; where it names a bare name, the shallowest path carrying it wins, and files that are still equal after that are offered as a choice rather than decided quietly. Matching ignores case, everywhere — a note travels between devices whose file systems disagree about it, and the same line must not open a file on one and find nothing on the next.
23Reminders
A line can ask to be reminded about. The marker is
C — for cue, a signal that prompts you to act
— a slash, and optionally how long before the line's own time:
19:00 Zahnarzt C/PT30M thirty minutes before 19:00 Zahnarzt C/ at the time itself - [ ] 09:00 Angebot raus C/ on a task, too
- The body is an ISO 8601 duration limited to days, hours and
minutes —
PT30M,PT2H,PT1H30M,P1D,P1DT2H. Anything else is text, and so is a number too large to hold. - The slash is part of the marker even with an empty body. A bare
Cat the end of a line would collide with ordinary writing, andR/carries its slash for the same reason. - Read without regard to case, because a phone capitalises the first letter of a line for you.
- Boundaries as in §9: whitespace or the start of the line in front, whitespace or the
end of the line behind. So
C/C++,AC/DC,c/o,20 °C/WandTeil ABC/P1Dare all ordinary text. - The first marker in a line decides, as with the priority.
- A line with no time has no moment to count back from, so a marker on one is read and does nothing.
- A cancelled appointment (§8) reminds about nothing. The strike
covers the whole line, marker included:
19:00 ~~Mastermind C/PT10M~~.
Why this is the one place minutes are allowed
§20 rules hours and minutes out of a recurrence, and that stands: a recurrence is an assertion about days, and a note is a day. A reminder is the opposite assertion — it is a moment, and minutes are the whole of it.
What the format does not say
Whether anything actually rings. A reminder is delivered by a device, so whether it is switched on, on which of your devices, and how far ahead it looks are settings of the app and not properties of the note. The marker on the line is the request; a file that is only ever read stays a file that is only ever read.
Nothing is written back either. A reminder that has been shown, dismissed or put off leaves no trace in the note — that is state about a device and a moment, and §20's rule against machine-owned fields in a line covers it.