Version 1.2
Frozen snapshot. This is OpenWatchlist v1.2 at its permanent URL, preserved exactly as published. The current specification always lives at /spec.html — implement against that unless you specifically need v1.2. 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

- 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 +

## Streaming Services

- Netflix
- Apple TV+

Four entries at the top: 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.

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.

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.

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

One shelf is special: ## Streaming Services (aliases: Services, Subscriptions) lists the services the author subscribes to, one per line. Service lines are plain names, not entry grammarApple TV+ must survive intact, so no token stripping applies inside it.

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.

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