Your notes already contain a timeline
A folder of Markdown files is a timeline: one note per item, the dates and fields read out of the YAML frontmatter, and one timeline.json in the folder to say that you meant it. Nothing is imported and nothing is copied. An edit you make in the browser goes back into the note it came from, one frontmatter key at a time.
What makes a folder a timeline
A timeline.json inside it. The file may be {}:
its job is to mark which folder you meant. A folder without one is descended
into rather than registered, so the subfolders on the way to your notes do not
each become an empty timeline of their own.
export TIMELINES_LOCAL_ROOT=~/Documents/Vault
npm run dev
Every folder under that root carrying the marker is one timeline, and every
Markdown file in it, subfolders included, is one of its items. A folder that
is a timeline owns everything below it, so two timelines out of one vault
means two folders with a marker each, side by side.
Self-hosting covers the root, the
read-only switch and the rest of the scan block.
What a note becomes
---
title: Kickoff workshop
date: 2026-01-15
duration: 2d
status: Doing
group: Discovery
tags: [workshop, extern]
owner: mail@example.com
---
Notes from the workshop go here, as usual. | Frontmatter | What it becomes |
|---|---|
title | The item’s label. A note without one is labelled with its filename. |
date, scheduled, created | The start, first key that resolves. A day stays a day: 2026-01-15 is not turned into an instant in a timezone the note never named. |
end, end_date, until, duration | The end of the bar: an end date outright, or a length such as 7d, 2w, 90m. A note carrying none of them is a point. |
group | The lane. groupFromFolder in the folder’s scan block takes it from the subfolder instead, for notes that name none. |
status | Open, Doing or Done, read case-insensitively. A bar the timeline has passed while its status says otherwise gets an overdue mark. |
icon, type | The glyph on the bar, and whether the item draws as a point, a bar, a box or a background band. |
tags | Coloured pills in front of the title, and a dimension you can group and filter by. Nothing has to be declared for it. |
id | The handle other notes point at. Without one, the note’s path inside the folder is the id, which a rename changes. |
| everything else | Kept on the item as metadata, whole. A note is never a lossy copy of its file, which is what lets a write put back what it did not touch. |
The body below the frontmatter is the item’s body, rendered as Markdown in the
detail panel when you select the item. The [[wikilinks]] in it can
become the dependency arrows as well, which the folder switches on with
linkEdges and self-hosting
describes.
Notes without a date stay in
A note the cascade finds no date for is still an item. The list view shows it and sorts it to the end, and the timeline view leaves it out while saying how many it left out, as 3 without a start (not on the timeline) in its status line. A folder is what this source shows, so a note that vanished without a word would make the timeline disagree with the directory it claims to be.
The same reasoning makes the date keys the folder’s to choose. A vault that
stamps created on every note would otherwise put a hundred items
on the day they were typed, which looks like data and is an artefact of the
editor. dateFields: [] in the scan block says that
no frontmatter key in this folder holds an item date, and the notes stay
unplaced unless their filename carries one.
A key you already write, as a field you can use
Tags need no declaration, and neither does anything you only want to read. A key you want to group by, filter on and edit becomes a field when the container declares it:
{
"name": "Research",
"groupBy": "cf:owner",
"customFields": [
{
"key": "owner",
"label": "Owner",
"type": "select",
"options": [{ "value": "mail@example.com", "label": "Mel" }]
}
]
}
The field then appears in the item form, in the grouping menu and in the
filter, and an edit writes it back to the same owner: line of the
note it came from. The keys the scan added for its own bookkeeping, the
note’s path and where its date was read, are never written into your
file.
An edit in the browser goes into the note
A runtime that has the folder on disk serves the timeline editable, which is
what npm run dev is. Moving a bar, renaming an item or changing a
field patches the one frontmatter key that changed and leaves the rest of the
file byte for byte alone: comments, key order, quoting style, the blank line
under the block, the body. Round-tripping a vault through a YAML serializer
instead would produce a diff over every note you opened.
| In the interface | On disk |
|---|---|
| Moving or resizing an item | The date key the scan read from that note. A date that came from the filename is promoted to an explicit key instead. |
| Adding an item | A new note in the timeline’s folder, named after the title rather than after a minted id. |
| Deleting an item | The note moves to .trash/, the convention Obsidian already uses, and never gets unlinked. |
| Editing a note elsewhere meanwhile | The write is refused rather than applied over it. A file has no version counter, so its modification time is the version, and a stale one is a conflict. |
A deployment serves the same folder read-only, because nothing behind it has a
filesystem to write into. And a process that can write is not always one that
should: TIMELINES_LOCAL_READONLY=1 refuses every write for a whole
instance, which is the setting for a folder you write prose in.
Related
- Pointing an instance at a vault, and what a folder declares
- A hand-written project plan instead
- Local sources in the documentation
Frequently asked questions
- Which frontmatter field becomes the item’s date?
- The first one that resolves out of
date,scheduled,created. When none of them carries a date, a date at the start of the filename is used, so2026-01-15-standup.mdlands on the right day with no frontmatter at all. The folder can name other keys, or none, in thescanblock of itstimeline.json. - What happens to a note with no date?
- It stays an item. The list view shows it and sorts it to the end, and the timeline view leaves it out and says how many it left out. Dropping such notes would make a source that is supposed to show a folder quietly show less than the folder.
- Can a note span a range instead of a single day?
- Yes. A
durationin the frontmatter (7d,2w,90m) extends the start into a bar, or anend/end_date/untilfield gives the end date outright. - How do I show only some of the notes in a folder?
- With the Filter control in the interface, which narrows by lane, status, tag or any declared field: values within one dimension are combined with OR, dimensions with AND. A narrowing worth keeping becomes a saved view, stored in the folder’s
timeline.jsontogether with the presentation and the grouping. One folder is one timeline, so splitting it into several means several folders, each with its owntimeline.json. - Which frontmatter key does a dragged bar write back to?
- The key the item’s date was read from, which the scan records per item. A date that came from the filename has no key yet, so the first write puts an explicit one in the frontmatter rather than renaming the file, and from then on the note states its own date.
- Does the timeline update when I save a note in my editor?
- Yes, without a reload and without a rebuild. A local timeline reports the newest modification time across its files as a watermark, the open page polls it, and a changed folder is re-read. That covers any writer: your editor, Obsidian, a
git checkout.