Version 1.3
Frozen snapshot. This is OpenWatchlist v1.3 at its permanent URL, preserved exactly as published. The current specification always lives at /spec.html — implement against that unless you specifically need v1.3. See the changelog for what changed since.

OpenWatchlist specification

OpenWatchlist is a plain-text format for tracking the films and series you watch. A valid file is readable in any text editor, diffable in any version control system, and useful with no software at all. Apps are viewers and editors over the file — never owners of it.

# My Watchlist

> the July queue — shows first,
> films when there's a free evening

- Dune: Part Two (2024)
- Severance (2022) 4.5/5 * @s2e6 #apple-tv | so creepy
- Aftersun (2022) 4.5/5 * +2026-01-15 | quietly devastating
- The Flash (2023) 2/10 ~

## With John

- Heat (1995) #crime
- Mad Men (2007) 5/5 +

Services: Netflix | Apple TV+

The > lines are a comment — notes to yourself, never parsed as titles. Then four entries: one queued, one being watched (mid s2e6), one watched with a date, one set aside with ~ (still unwatched — archiving hides it, it doesn't rewrite history). Each line carries its own state. Below them, a shelf called “With John” groups two more titles. The shelf name is organization, nothing else; the + on Mad Men is what says it's been watched. The last line lists the author's streaming services.

Design principles

  1. Humans first. Every construct must be writable on a phone keyboard and understandable without documentation. If a feature needs syntax a person wouldn't naturally type, it doesn't go in.
  2. The line is the record. Everything true about a title — status, rating, history — lives on its own line and travels with it. Moving a line never changes its meaning.
  3. The file is the database. There is no canonical copy elsewhere. Tools must read what humans write and write what humans can read.
  4. Never destroy what you don't understand. Unknown shelves and unparseable lines are preserved verbatim by conforming writers.
  5. Order is data. A user's ordering of entries is meaningful (a curated queue, a ranking) and conforming writers preserve it except for user-initiated moves.
  6. Lenient in, canonical out. Parsers accept entry tokens in any order and several equivalent spellings; writers emit one canonical form.

The entry line

Each title is one line: a bulleted - Title or a plain Title, followed by optional tokens, in this canonical order:

Title (Year) rating favorite masterpiece priority status/progress watch-date archive #tags | notes

Everything except the title is optional. A parser accepts the tokens in any order after the title; a writer always emits the canonical order above. In marks:

Title (YYYY) 4.5 * ^ !!! @s2e6 +2026-01-15 ~ #tags | note

Watch status

A title's watch status is carried on its line — by the marks it does or doesn't have. Only these four determine it:

Marks on the line Status
nothing unwatched — a bare title is a queued title
_ unwatched, explicitly — “not watched yet,” on the record
@ (progress) watching — you're somewhere in it
+ (watched) watched — you finished it, optionally dated

When watch marks combine, the current state wins: @ > + > _ > nothing. So +2024-11-03 @s3e4 reads as watching — a rewatch in progress, with its history intact.

Everything else — archive ~, favorite *, masterpiece ^, priority ! — is a separate metadata flag, never a watch status.

Archived is a flag, not a status

~ means set aside — dropped, retired, hidden from the active list. It is orthogonal to watch status: archiving something never erases whether you watched it. Every combination is meaningful:

Heat (1995) ~                      archived · unwatched (never got to it)
The Irishman (2019) @1:20:00 ~     archived · watching (gave up an hour in, place kept)
Game of Thrones (2011) + ~         archived · watched (finished, then retired)

A conforming tool reports both facts — “archived” and the underlying watch status — and un-archiving (removing the ~) simply returns the line to its active life with everything intact.

Shelves never decide status. A line means the same thing on any shelf, in any file, in any order. See Shelves.

Tokens

Token Form Meaning
Year (YYYY) Disambiguates remakes — Suspiria (1977) vs (2018). Premiere year for TV
Rating n/5, n/10, or bare n Personal rating. Plain numbers 0–5 read out of 5, above 5 read out of 10; explicit forms (4.5/5, 8/10) are always allowed and preferred when clarity matters (see below)
Favorite * Flag — independent of rating and status
Masterpiece ^ Flag — a higher, narrower indication than favorite: elite, all-time-level work. A title can be * ^ (both), or ^ without * (a masterpiece that isn't a comfort favorite)
Priority ! !! !!! Flag — eventually / soon / watch next. Three levels; !!! is the maximum
Unwatched _ Status — explicitly not watched yet (a bare line is already unwatched; _ puts it on the record)
Progress @, @s2e6, @s2, @1:20:00, @80m Status — where you are: season/episode or a movie timecode; bare @ means watching, position unrecorded. Because progress lives on the line, moving an entry anywhere never loses your place
Watched + or +YYYY-MM-DD Status — watched, optionally dated (ISO). Repeat the token for rewatches
Archived ~ Flag — set aside, orthogonal to watch status: an archived line keeps its unwatched/watching/watched state (see Archived)
Tag #tag Freeform; letters, numbers, -, _. Lowercase kebab-case recommended
Note | text Free text to end of line; always last

Ratings: plain numbers

Ratings are plain numbers: 0–5 defaults to out of 5, greater than 5 defaults to out of 10. A plain 5 means 5/5 — if you mean five out of ten, write 5/10. Explicit forms (4.5/5, 8/10, 2/10) are always allowed and preferred when clarity matters.

A trailing number is a rating by default. The one exception keeps titles that end in a number intact: a number sitting directly before the year is part of the title — which is exactly where it belongs. Add the year and the title is safe; leave it off and the number reads as a score.

Oppenheimer (2023) 8      rating 8/10   (trailing number → rating)
Heat (1995) 4             rating 4/5    (0–5 reads out of 5)
Ocean's 8 (2018)          title "Ocean's 8", no rating   (number before the year)
District 9 (2009)         title "District 9", no rating
Ocean's 11                title "Ocean's 11"   (numbers above 10 are never a rating)
Ocean's 8                 title "Ocean's", rating 8/10   (no year → the 8 is read as a score)

Two guardrails make this safe in practice: a plain integer above 10 is never a rating (so Ocean's 11 and Catch 22 stay titles), and a bare decimal like 4.5 is always a rating anywhere — essentially nothing is titled a decimal. When a title ends in a number, just include its year.

Input leniencies

Real files carry artifacts of the editors that made them. Two spellings are official read-side leniencies — parsers SHOULD accept them; writers MUST emit the canonical form:

Lenient input Read as Why
\* favorite * Markdown-minded editors and exporters escape a bare * (it could read as emphasis). Without the leniency the unknown token halts right-to-left parsing and silently swallows the year, rating, and favorite into the title
@YYYY-MM-DD watched date +YYYY-MM-DD The pre-1.2 spelling of a watch date; files from early tools still carry it

Bracket marks

The same status marks may be written at the start of a line in task-list brackets — handy when you want your list to render as checkboxes on GitHub or a markdown notes application like Obsidian, or when a leading mark reads better than a trailing one:

- [ ] Heat (1995) #crime            unwatched
- [@] Severance (2022) @s2e6        watching
- [x] Mad Men (2007) 5/5            watched
- [ ] The Flash (2023) 2/10         unwatched
- [+] Game of Thrones (2011) ~      watched · archived
- [_] Blow Out (1981)               unwatched (explicit)

[ ] and [x] are standard GitHub-Flavored Markdown and render as real checkboxes; [_], [@], and [+] extend the same bracket notation and display as readable text elsewhere. A bracket mark and an inline mark are the same channel: [@] means what @ means, [+] means what + means, combine it with watch marks to archive something watched or in progress. A line's state is resolved from all its marks together under Watch status: bracket and inline marks should usually match, and when they conflict the same precedence applies (@ beats +, and ~ is the separate archived flag). Writers preserve whichever spelling (inline or bracket) a line already uses.

Preamble

An OpenWatchlist file is UTF-8 Markdown. Anything before the first ## heading is the preamble — typically an # H1 title, free notes, and (very commonly) entries that simply live at the top level, on no shelf at all. Non-entry preamble text is preserved verbatim.

Comments

Some lines are notes, not titles. A line is a comment when its first characters — after optional leading whitespace, and optionally after a single list bullet (- or * ) — are one of four markers:

> The main style: markdown blockquote lines.
> They read as comments here — and render
> as a tidy quote in any markdown viewer.

// Heat (1995) +        a line switched off — kept, but not parsed
-- also a comment

/* a block comment:
every line down to the closing marker
is part of the comment */
Marker Meaning
> The recommended style for prose notes — it's a markdown blockquote, so it renders as a quote wherever markdown renders
// The natural spelling for switching a line off: // Heat (1995) keeps the line — and everything on it — while removing it from the list
-- Also a whole-line comment. A markdown horizontal rule (---) begins with --, so pasted notes files with rules between sections parse cleanly
/**/ Block comment across lines. The line opening with /* begins it; every line up to and including the line containing */ is a comment

Comments are whole lines only. There are no inline or trailing comments: a // or -- in the middle of a line is ordinary text and stays in the title or note. Commentary that should ride along with an entry belongs in its | note.

Block comments consume whole lines too: anything after */ on the closing line is still comment text, and a one-liner /* like this */ comments out exactly that line. An unclosed /* runs to the end of the file — the behavior every other language trained your fingers on — and tools should warn, because it comments out everything below it.

Comments are opaque. They produce no entries and no services, they never start or end a shelf (a commented line inside a shelf leaves the shelf intact around it), and they attach to nothing — a comment above an entry is not metadata for that entry. Conforming writers preserve every comment byte-for-byte, in place. Commenting a line out is the format's official way to say “keep this line; it isn't a title.”

Shelves

Every ## Heading starts a shelf, running until the next ## heading or end of file. A shelf is organization — a place you keep things:

## With John

- Heat (1995)
- Blow Out (1981) +2026-02-11

## Rom-coms

- Set It Up (2018)
- Notting Hill (1999) 4/5 +

## Halloween marathon

- The Thing (1982) *
- Suspiria (1977)

Shelves do not decide watch status. Blow Out and Notting Hill above are watched because of their + marks — not because of which shelf they're on, and the unmarked titles around them are unwatched wherever they sit. Entries on any shelf parse under the full entry grammar; tools preserve every shelf's name, order, and entry style, and never auto-empty one.

Name shelves anything: ## With John, ## Rom-coms, ## Favorites, ## Dad's recommendations. Apps may offer to organize a file into shelves for you — grouping by status (## Watched), by genre, by anything — but that's a filing convenience the user opts into. The marks remain the truth; regrouping lines never changes what they mean.

Note: each shelf keeps whichever entry style it already uses — bulleted (- Title) or plain lines separated by blank lines. Both are equally valid; a writer preserves the style it finds.

Streaming services

The services you subscribe to are one line:

Services: Netflix | Hulu | Max | Apple TV+
  • The canonical label is Services:; readers also accept Streaming Services: and Subscriptions:, case-insensitive, optionally after a list bullet.
  • Names are separated by | with optional surrounding spaces. Each name is plain text, not entry grammar — no token stripping applies, so Apple TV+ and Disney+ survive intact; only | delimits.
  • The line may appear anywhere in the file — preamble, mid-shelf, anywhere a reader finds it. The conventional home is the last line of the file. If several services lines exist, readers merge them in file order (first occurrence of a name wins).

Legacy form, read forever: before v1.3 services were a special shelf — ## Streaming Services (aliases: Services, Subscriptions), one plain name per line. Conforming readers keep accepting that shelf and merge it with any compact line; conforming writers emit the compact line when writing services.

Files with no shelves

A list dumped from a notes app usually has no structure at all — and it doesn't need any. Since status lives on the line and shelves are optional organization, a file that is nothing but titles is already a complete OpenWatchlist document:

Heat (1995)
Casablanca (1942)
[x] The Thing (1982) 5/5
Severance @s2e6

parses as two queued titles, one watched, one in progress. Paste anything; structure is never a prerequisite.

Canonical examples

Heat (1995) !!! #crime #mann #pacino #deniro | need to watch
Heat (1995) _ !!! #crime #mann | explicitly unwatched
Severance (2022) 4.5 * @s2e6 #with-john #apple-tv | watching with John, very creepy
The Irishman (2019) @1:20:00 !! #scorsese #netflix | paused halfway through, finish soon
The Batman (2022) 4 * +2024-11-03 #dc #crime #noir | great atmosphere, slightly too long
Mad Men (2007) 5 * ^ + #prestige-tv #amc | watched, date unknown
The Flash (2023) 2/10 ~ #dc #superhero | bad, archived
Children of Men (2006) 5 * ^ !!! +2025-12-18 #sci-fi #dystopian | all-time favorite

Formatting conventions

  • Lowercase kebab-case tags: #with-john #apple-tv #sci-fi #prestige-tv #based-on-book.
  • !!! is the maximum priority. Four or more exclamation marks read as title text, not a louder priority.
  • A plain rating of 5 means 5/5. Five out of ten is written 5/10.

Identity

Two lines refer to the same title when their title text and year match, case- and punctuation-insensitive. The year is part of a title's identity: Mulan (1998) and Mulan (2020) are different entries. Duplicate identities within a file are an authoring error tools should surface, not silently merge. Identity is also how tools correlate one title across multiple list files.

Conformance

A conforming reader parses every construct in this document, treats unknown constructs and unparseable lines as opaque content, and never errors on arbitrary text.

A conforming writer emits canonical token order and spellings, preserves the preamble, every shelf, and entry order byte-for-byte apart from user-initiated changes, preserves each shelf's existing entry style, and round-trips: parsing then writing a canonical file reproduces it exactly.

Versioning

The format is versioned by this document. Backward compatibility is a hard requirement: a valid file must parse identically under every future version. New tokens may be added only where an older parser would already leave them harmlessly in the title. One narrow class of exception is permitted and must be recorded in the changelog: new line-level constructs may claim line shapes that carry no plausible meaning as titles — v1.3's comment markers claimed lines starting //, --, >, and /*, and its compact services line claimed lines starting Services:, all of which v1.2 read as (nonsense) titles.

Every version of this specification is preserved at a permanent URL of the form /spec-v<version>.html (e.g. /spec-v1.2.html); this page, /spec.html, is always the current version. The changelog lists every version with what changed. Implementers — tools and AI agents alike — should build against this page; files never declare a version and never need to, because a current parser reads every valid older file.

OpenWatchlist is an open format. This document may be reproduced freely. The playground's parser.js is the reference parser for this specification.