# Pomodoso plugins — full reference A plugin is one YAML file. Pomodoso validates it, stores it, and renders it with built-in components: the file can't run code, load scripts or call other services. Anything the format can't express doesn't exist yet — don't invent keys or block types. ## Rules that matter - Keys (collections, fields, settings, computed, views) are lower_snake_case, up to 40 characters, starting with a letter. The plugin `id` is lower-kebab-case. - Read a value anywhere a value goes with `$name`: a setting, a computed value or a built-in (`$today_date`, `$now`, `$tab.url`, `$tab.title`, `$tab.image`, `$record`). `$tab.*` only works in an add-button's `prefill`. - Put a value inside a label or text with `{$name}`. - A one-tap action (counter-button, mini-counter, hook `yes`, day picks) has no form, so every required field of its collection must be optional, have a `default`, or be set by the action. - Every record also has built-in fields you can list, sort and filter by without declaring them: `created_at` and `updated_at`, plus `occurred_at` on events and `day` on dailies. - Literal values must fit their field: numbers within min/max, select values from `options`. - The file is at most 256 KB. - Newer blocks and values need a newer Pomodoso. The validator reports the app format version a file needs (now up to 0.2); older clients don't see it in the directory. - Validate against https://pomodoso.com/schema/plugin.v1.json; Pomodoso also checks that every collection, field and `$reference` you name exists, and says what's available when one doesn't. ## The file - `schema_version` (required): 1. Always `1`. - `id` (required): text. The plugin id, lower-kebab-case (`quit-smoking`). It never changes between versions. - `name` (required): text. Shown in the app list. - `version` (required): text. Semver, `1.0.0`. A breaking change needs a new major and a `migrate` block. - `icon`: text. One word: book, film, grid, no-smoking, water, coffee, run, heart, mood, sleep, money, music, game, plant, pill, food, star, check, calendar, pen, link, code, brain, dumbbell. Anything else shows the initial. - `description`: text. One sentence. - `author`: text. Your name. - `license`: text. Default MIT. - `settings`: list of object. Values the user sets on install (a starting limit, a goal). Readable as `$key`. - `collections` (required): list of object. What the plugin stores. Each has a `key`, a `kind` and `fields`. Empty (`[]`) for an app that keeps no data, like a year progress bar. - `computed`: map of key → computed value. Named values calculated from the records, readable as `$name`. - `views` (required): list of object. The screens of the plugin, each a list of blocks. A view with `of: ` is the screen of one record (opened from a list or board with `opens`); its blocks read `$record` (the id) and `$record.`. `layout: wide` opens a view full width (a browser tab in the extension). The first view is the main screen and has no `of`. - `today`: object. Optional widget for the Today tab; the user switches it on. `default_on` suggests a starting state. - `hooks`: list of object. Optional questions after pomodoros or at day end, and lines in reports. - `rules`: list of object. Fields set automatically when a record starts matching `when` (stamp a date when a book becomes read). `only_if_empty` keeps a value the user set. - `migrate`: object. How a breaking update carries existing records over: `from: "1.x"` and `steps` (rename_collection, rename_field, map_values, drop_field). ## Settings Each setting: - `key` (required): key - `type` (required): number | text | boolean | select - `label` (required): text - `default`: text | number | true | false - `options`: list of key | object - `min`: number - `max`: number ## Collections - `event`: Things that happen at a moment: a cigarette, a glass of water. Each record gets `occurred_at`. - `item`: Things you keep and update: a book, a link. Records have no date of their own beyond `created_at`. - `daily`: One record per day: a mood, a day state. Records have a `day`; saving the same day again updates it. Each field: - `key` (required): key - `type` (required): text | longtext | number | scale | boolean | date | url | select | multiselect | tags | rating | duration | image_url | ref | task - `label`: text - `optional`: true | false - `default`: text | number | true | false | list of text - `options`: list of key | object - `user_editable`: true | false - `min`: number - `max`: number - `unit`: text - `collection`: key Field types: - `text`: One line of text. - `longtext`: Multi-line text (notes). - `number`: A number; `min`, `max` and `unit` are optional. - `scale`: A number picked from a short range (default 1–5), shown as buttons. - `boolean`: Yes / no, shown as a checkbox. - `date`: A calendar day, YYYY-MM-DD. - `url`: A link. - `select`: One option from `options`. Add `user_editable: true` to let the user rename, recolor and add options. - `multiselect`: Several options from `options`. - `tags`: Free-form tags, typed comma-separated. No `options`. - `rating`: Stars (default 1–5). - `duration`: Minutes. - `image_url`: An image link (https), shown as a cover in boards. - `ref`: A record of another item collection (`collection`) this one belongs to: a card of an issue, a note of a book. Picked from a list; shows its title. Deleting that record deletes the ones that point to it. - `task`: A task from the user's Pomodoso task list, picked from them. The app stores only its id and shows its title; the task shows the record back, to open it. Apps can't read or change tasks. ## Computed values Each entry under `computed` has exactly one operator key, which names the collection (or holds the operator's settings). They can reference each other with `$name`, without cycles. Ranges: `today`, `yesterday`, `this_week`, `last_week`, `this_month`, `last_month`, `this_year`, `all`, or a rolling window like `14d` or `12mo`. ### `count` How many records match. Optional `where`, `range`, `by` (the date field the range applies to) and `group` (day | week | month, which makes it a series for charts). - `count` (required): key - `where`: map of key → text | number | true | false | object - `range`: today | yesterday | this_week | last_week | this_month | last_month | this_year | all | a rolling window like 14d or 12mo - `by`: key - `group`: day | week | month ### `sum` Sum of a numeric `field` over the matching records. Same options as count. - `sum` (required): key - `field` (required): key - `where`: map of key → text | number | true | false | object - `range`: today | yesterday | this_week | last_week | this_month | last_month | this_year | all | a rolling window like 14d or 12mo - `by`: key - `group`: day | week | month ### `avg` Average of a numeric `field`. Same options as count. - `avg` (required): key - `field` (required): key - `where`: map of key → text | number | true | false | object - `range`: today | yesterday | this_week | last_week | this_month | last_month | this_year | all | a rolling window like 14d or 12mo - `by`: key - `group`: day | week | month ### `min` Smallest value of a numeric `field`. Same options as count. - `min` (required): key - `field` (required): key - `where`: map of key → text | number | true | false | object - `range`: today | yesterday | this_week | last_week | this_month | last_month | this_year | all | a rolling window like 14d or 12mo - `by`: key - `group`: day | week | month ### `max` Largest value of a numeric `field`. Same options as count. - `max` (required): key - `field` (required): key - `where`: map of key → text | number | true | false | object - `range`: today | yesterday | this_week | last_week | this_month | last_month | this_year | all | a rolling window like 14d or 12mo - `by`: key - `group`: day | week | month ### `last` The most recent record (or its `field`). Optional `where`. - `last` (required): key - `where`: map of key → text | number | true | false | object - `field`: key ### `first` The oldest record (or its `field`). Optional `where`. - `first` (required): key - `where`: map of key → text | number | true | false | object - `field`: key ### `streak` Consecutive days, ending today, with a count within `at_least` / `at_most`. Optional `where`. - `streak` (required): key - `where`: map of key → text | number | true | false | object - `at_least`: value (number, $reference or computed) - `at_most`: value (number, $reference or computed) ### `taper` A value that changes by a step every period since install: `from`, `down_by` or `up_by`, `every` (day | week | month), optional `min` / `max`. For limits that tighten over time. - `taper` (required): object - `from` (required): value (number, $reference or computed) - `down_by`: value (number, $reference or computed) - `up_by`: value (number, $reference or computed) - `every` (required): day | week | month - `min`: value (number, $reference or computed) - `max`: value (number, $reference or computed) ### `delta` Relative change between two values, `[a, b]` → (a − b) / b. Reads as a percent in templates. - `delta` (required): [value (number, $reference or computed), value (number, $reference or computed)] ### `calendar` How far the current `week`, `month` or `year` has gone, from the date alone (no collection). `show`: `progress` (default, a fraction: 0.43 on day 158 of 365), `passed` (days so far, today included), `left` (days after today) or `total` (days in the period). - `calendar` (required): week | month | year - `show`: progress | passed | left | total ### `ratio` One value divided by another, `[a, b]` → a / b: pages per day, cost per item. Empty when b is 0. - `ratio` (required): [value (number, $reference or computed), value (number, $reference or computed)] ## Views and blocks Each view has an `id`, an optional `label` (the tab name) and `blocks`, shown top to bottom. ### `counter-button` A big button that adds a record to an event collection in one tap. `set` fills fields; `details: form` opens a form instead. `subtract: true` adds a − button that deletes the latest one from today (a tap by mistake). - `label` (required): text - `adds` (required): key - `details`: none | form - `set`: map of key → text | number | true | false - `subtract`: true | false ### `add-button` A button that opens a form to add an item. `prefill` can use `$tab.url`, `$tab.title` and `$tab.image` (the current page and its preview image), so one tap saves the page you are on. - `label` (required): text - `adds` (required): key - `prefill`: map of key → text | number | true | false ### `form` An inline form for a collection. On a daily collection it edits today. On an event collection it also asks "When" (now by default), to log one you forgot. - `collection` (required): key ### `stat` One number or value with a label. `format` says how it reads. - `label` (required): text - `value` (required): value (number, $reference or computed) - `format`: number | time_ago | days | percent | share | duration | date ### `stat-row` Up to four stats side by side. - `items` (required): list of object ### `progress` A bar of `value` against `max`. `invert: true` for limits (going over is bad). `format` says how the numbers read (`share` shows only the percent). `style`: `bar` (default), `ring` (a ring of dots) or `dots` (one dot per unit when `max` is a whole number up to 400, like the days of a year); it can be a `$setting` so the user picks. - `label`: text - `value` (required): value (number, $reference or computed) - `max` (required): value (number, $reference or computed) - `invert`: true | false - `format`: number | time_ago | days | percent | share | duration | date - `style`: bar | ring | dots | $reference ### `chart` A bar or line chart of a grouped series (`count` / `sum` / … with `group`). Optional dashed `reference` line. - `label`: text - `kind` (required): bar | line - `series` (required): computed value - `reference`: value (number, $reference or computed) ### `list` Records as rows: `primary` field, up to three `secondary` ones, optional `filter`, `sort`, `open` (a url field), a `swipe` action that sets fields, and `opens` (a view with `of` this collection: tapping a row opens that record's screen). - `collection` (required): key - `filter`: map of key → text | number | true | false | object - `primary` (required): key - `secondary`: list of key - `open`: key - `opens`: key - `sort`: object - `field` (required): key - `order`: asc | desc - `swipe`: object - `label`: text - `set` (required): map of key → text | number | true | false ### `tag-filter` Chips that filter the lists and boards of the same view by a tags, multiselect or select field. - `collection` (required): key - `field` (required): key ### `board` Items grouped in columns by a select field (`group_by`), as cards with title, subtitle, image and badge; optional `filter` (in a record's screen, `{ issue: $record }` shows its cards) and `opens`. Full width (`layout: wide`) the columns sit side by side, cards drag between them and each column has its own add. - `collection` (required): key - `filter`: map of key → text | number | true | false | object - `group_by` (required): key - `card` (required): object - `title` (required): key - `subtitle`: key - `image`: key - `badge`: key - `opens`: key ### `year-grid` Every day of the year as a colored cell (like a contribution graph), colored by a select field. - `collection` (required): key - `color_by`: key - `legend`: true | false ### `day-picker` Pick a select value for today, or move to other days. - `collection` (required): key - `field` (required): key ### `breakdown` How many records have each option of a select, multiselect or tags field, as bars. - `collection` (required): key - `field` (required): key - `range`: today | yesterday | this_week | last_week | this_month | last_month | this_year | all | a rolling window like 14d or 12mo ### `text` A paragraph; `{$name}` inside it is replaced by the value. - `text` (required): text ## Today widget `today: { default_on: true | false, widget: … }` ### `mini-counter` A number with a + button that adds to an event collection (`adds`). Optional `max`; `subtract: true` adds a − button that deletes the latest one from today. - `label` (required): text - `value` (required): value (number, $reference or computed) - `max`: value (number, $reference or computed) - `adds` (required): key - `subtract`: true | false ### `select-today` Option chips that set today's value of a daily collection's select field. `after: year-grid` shows the year in pixels (colored by that field) once today is set, with a Change link to pick again. - `label` (required): text - `collection` (required): key - `field` (required): key - `after`: year-grid ### `count-badge` A single number. - `label` (required): text - `value` (required): value (number, $reference or computed) ### `stat` A single value with a `format`. - `label` (required): text - `value` (required): value (number, $reference or computed) - `format`: number | time_ago | days | percent | share | duration | date ### `progress` A bar of `value` against `max` (default 1), with an optional `format`, a `caption` line under it (`{$name}` works) and a `style` (`bar`, `ring` or `dots`, or a `$setting`). Ring and dots take the whole row. - `label` (required): text - `value` (required): value (number, $reference or computed) - `max`: value (number, $reference or computed) - `format`: number | time_ago | days | percent | share | duration | date - `caption`: text - `style`: bar | ring | dots | $reference ### `record` The latest item of a collection matching `where` (the book you are reading), by its `title` field, with a number `field` you edit right on the card (the page you are on), against an optional `max` field (its pages, as a bar). Optional `caption` line with `{$name}` values. - `label` (required): text - `collection` (required): key - `where`: map of key → text | number | true | false | object - `title` (required): key - `field` (required): key - `max`: key - `caption`: text ### `list` The records of a collection matching `where` as rows (the open boards), each opening its screen (`opens`, a view with `of`), with an optional `badge` per row (a value that reads the row as `$record`: its cards done) and `badge_of` (what the badge is out of, shown as 3/5), and an optional `more` row opening another view of the app. Takes the whole row on Today. - `label` (required): text - `collection` (required): key - `where`: map of key → text | number | true | false | object - `opens` (required): key - `badge`: value (number, $reference or computed) - `badge_of`: value (number, $reference or computed) - `more`: object - `label` (required): text - `view` (required): key - `badge`: value (number, $reference or computed) ### `stats` Up to four values, two per row, each with its `label` and optional `format` (`items`). Fits half a row on Today, like the other widgets. - `label` (required): text - `items` (required): list of object ## Hooks - `pomodoro_end`: After a pomodoro, during the break: `ask` a question; `yes` adds a record to an event collection, or `pick` sets a select on today. At most one plugin question per break. - `day_end`: The next day: `ask` about yesterday, with `yes` (adds a record to an event collection, dated yesterday) or `pick` (sets a select on yesterday's daily record). - `daily_report`: A `line` added to the daily report, with `{$name}` values. - `weekly_report`: A `line` added to the weekly report. A pomodoro_end / day_end hook: - `on` (required): pomodoro_end | day_end - `ask` (required): text - `yes`: object - `add` (required): key - `set`: map of key → text | number | true | false - `pick`: object - `collection` (required): key - `field` (required): key A daily_report / weekly_report hook: - `on` (required): daily_report | weekly_report - `line` (required): text A prompt hook takes exactly one of `yes` or `pick`. ## Stat formats - `number`: 12, 2.5 - `time_ago`: 3h 20m ago (for timestamps such as `last`) - `days`: 8 days - `percent`: +20%, −34% (for fractions such as `delta`) - `share`: 43.3%: a fraction as a plain percent (`calendar` progress). In a progress block or widget, the value as a share of `max` (158 of 365 reads 43.3%). - `duration`: 1h 35m (minutes) - `date`: Oct 21, 2026 ## Common mistakes - Inventing a block type (`kanban`, `calendar`): use `board` or `year-grid`. The error lists what's available. - A counter-button on a collection with a required field and no `set` or `default` for it. - Writing a reference without `$` (`value: today` instead of `value: $today`). - A chart series without `group`: charts need `count` / `sum` / `avg` / `min` / `max` with `group: day | week | month`. - `options` on a field that isn't select or multiselect (tags take no options). - Naming a setting or computed value `now` or `today_date` (built in). - A breaking change (renaming or removing a field, collection or option, changing a type) without a new major version and a `migrate` block. ## Complete examples ### quit-smoking ```yaml schema_version: 1 id: quit-smoking name: Quit smoking version: 1.1.0 icon: no-smoking description: A daily limit that drops every week. Log each one and watch the trend go down. author: Pomodoso license: MIT settings: - { key: start_limit, type: number, label: Starting daily limit, default: 15, min: 0 } - { key: weekly_reduction, type: number, label: Reduce every week by, default: 1, min: 0 } collections: - key: cigarette kind: event fields: - { key: craving, type: scale, label: "How strong was the craving?", min: 1, max: 5, optional: true } - key: trigger type: select optional: true options: [coffee, stress, after_meal, pomodoro_break, social] - { key: note, type: text, optional: true } computed: today: { count: cigarette, range: today } limit: { taper: { from: $start_limit, down_by: $weekly_reduction, every: week, min: 0 } } last: { last: cigarette } under_limit: { streak: cigarette, at_most: $limit } week: { count: cigarette, range: this_week } last_week: { count: cigarette, range: last_week } week_change: { delta: [$week, $last_week] } views: - id: main blocks: - { type: counter-button, label: Smoked one, adds: cigarette, subtract: true } - { type: progress, value: $today, max: $limit, invert: true } - type: stat-row items: - { label: Since last, value: $last, format: time_ago } - { label: Under limit, value: $under_limit, format: days } - { label: vs last week, value: $week_change, format: percent } - type: chart label: Last 14 days kind: bar series: { count: cigarette, group: day, range: 14d } reference: $limit - id: log label: Log with details blocks: - type: text text: Forgot one? Set "When" to the time you smoked it. - { type: form, collection: cigarette } today: default_on: true widget: { type: mini-counter, label: Cigarettes, value: $today, max: $limit, adds: cigarette, subtract: true } hooks: - on: pomodoro_end ask: Did you smoke during this break? yes: { add: cigarette, set: { trigger: pomodoro_break } } - on: weekly_report line: "Cigarettes: {$week} this week ({$week_change} vs last week)" ``` ### year-in-pixels ```yaml schema_version: 1 id: year-in-pixels name: "Year in Pixels: Happiness" version: 2.1.0 icon: mood description: Color every day by how happy it was. You choose the states and their colors. author: Pomodoso license: MIT collections: - key: day_state kind: daily fields: - key: state type: select user_editable: true options: - { value: great, label: Great, color: "#2D8A7A" } - { value: good, label: Good, color: "#8FB08F" } - { value: okay, label: Okay, color: "#E8D9A8" } - { value: bad, label: Bad, color: "#D98C7A" } - { value: awful, label: Awful, color: "#A8432D" } - { key: note, type: text, optional: true } computed: logged_this_year: { count: day_state, range: this_year } good_streak: { streak: day_state, where: { state: { in: [great, good] } }, at_least: 1 } views: - id: main blocks: - { type: day-picker, collection: day_state, field: state } - { type: year-grid, collection: day_state, color_by: state, legend: true } - { type: breakdown, collection: day_state, field: state, range: this_year } - type: stat-row items: - { label: Days logged this year, value: $logged_this_year } - { label: Good days in a row, value: $good_streak, format: days } today: default_on: true widget: { type: select-today, label: How happy was today?, collection: day_state, field: state, after: year-grid } hooks: - on: day_end ask: How happy was yesterday? pick: { collection: day_state, field: state } # 1.x mixed mood and productivity; productivity now has its own app # (productivity-pixels). Its states map to the closest mood. migrate: from: "1.x" steps: - map_values: { collection: day_state, field: state, map: { productive: good, normal: okay, unproductive: bad } } ``` ### reading-list ```yaml schema_version: 1 id: reading-list name: Reading list version: 1.2.0 icon: bookmark description: Articles, videos and papers to get to later, organized with tags. author: Pomodoso license: MIT collections: - key: link kind: item title_field: title fields: - { key: url, type: url } - { key: title, type: text } - { key: kind, type: select, options: [article, video, paper, other], default: article } - { key: tags, type: tags, optional: true } - { key: status, type: select, options: [to_read, done], default: to_read } - { key: done_on, type: date, label: Read on, optional: true } computed: to_read: { count: link, where: { status: to_read } } read_week: { count: link, where: { status: done }, range: this_week, by: done_on } read_month: { count: link, where: { status: done }, range: this_month, by: done_on } read_year: { count: link, where: { status: done }, range: this_year, by: done_on } views: - id: main blocks: - type: add-button label: Save current tab adds: link prefill: { url: $tab.url, title: $tab.title } - { type: tag-filter, collection: link, field: tags } - type: list collection: link filter: { status: to_read } primary: title secondary: [kind, tags] open: url sort: { field: created_at, order: desc } swipe: { label: Done, set: { status: done } } - id: done label: Done blocks: - type: stat-row items: - { label: Read this week, value: $read_week } - { label: This month, value: $read_month } - { label: This year, value: $read_year } - type: list collection: link filter: { status: done } primary: title secondary: [done_on] open: url sort: { field: done_on, order: desc } today: default_on: true widget: type: stats label: Reading list items: - { label: To read, value: $to_read } - { label: This week, value: $read_week } - { label: This month, value: $read_month } - { label: This year, value: $read_year } rules: - collection: link when: { status: done } set: { done_on: $today_date } only_if_empty: true ``` ### bookshelf ```yaml schema_version: 1 id: bookshelf name: Bookshelf version: 1.2.0 icon: book description: Books you want to read, are reading and have read. author: Pomodoso license: MIT collections: - key: book kind: item title_field: title fields: - { key: title, type: text } - { key: author, type: text, optional: true } - { key: status, type: select, options: [want, reading, read], default: want } - { key: pages, type: number, label: Pages, optional: true, min: 1 } - { key: current_page, type: number, label: On page, optional: true, min: 0 } - { key: rating, type: rating, optional: true } - { key: tags, type: tags, optional: true } - { key: cover, type: image_url, optional: true } - { key: link, type: url, optional: true } - { key: finished_on, type: date, optional: true } computed: reading: { count: book, where: { status: reading } } read_this_month: { count: book, where: { status: read }, range: this_month, by: finished_on } read_this_year: { count: book, where: { status: read }, range: this_year, by: finished_on } # Pages of the books finished this year, and per day so far this year. pages_this_year: { sum: book, field: pages, where: { status: read }, range: this_year, by: finished_on } days_this_year: { calendar: year, show: passed } pages_per_day: { ratio: [$pages_this_year, $days_this_year] } pages_in_progress: { sum: book, field: current_page, where: { status: reading } } views: - id: main blocks: - type: add-button label: Add the book on this page adds: book prefill: { title: $tab.title, link: $tab.url, cover: $tab.image } - { type: add-button, label: Add a book, adds: book } - { type: tag-filter, collection: book, field: tags } - type: board collection: book group_by: status card: { title: title, subtitle: author, image: cover, badge: rating } - id: stats label: Stats blocks: - type: stat-row items: - { label: Read this month, value: $read_this_month } - { label: Read this year, value: $read_this_year } - type: stat-row items: - { label: Pages read this year, value: $pages_this_year } - { label: Pages a day, value: $pages_per_day } - { label: In current books, value: $pages_in_progress } - type: text text: Add each book's pages to count them. Open a book you're reading to note the page you're on. - type: chart label: Books per month kind: bar series: { count: book, where: { status: read }, by: finished_on, group: month, range: 12mo } today: default_on: true widget: type: record label: Reading collection: book where: { status: reading } title: title field: current_page max: pages caption: "{$read_this_month} read this month · {$read_this_year} this year" rules: - collection: book when: { status: read } set: { finished_on: $today_date } only_if_empty: true ``` ### movieshelf ```yaml schema_version: 1 id: movieshelf name: Movieshelf version: 1.1.0 icon: film description: Movies to watch and the ones you've seen. author: Pomodoso license: MIT collections: - key: movie kind: item title_field: title fields: - { key: title, type: text } - { key: director, type: text, optional: true } - { key: status, type: select, options: [watchlist, watched], default: watchlist } - { key: rating, type: rating, optional: true } - { key: tags, type: tags, optional: true } - { key: cover, type: image_url, optional: true } - { key: link, type: url, optional: true } - { key: watched_on, type: date, optional: true } computed: watchlist: { count: movie, where: { status: watchlist } } watched_this_year: { count: movie, where: { status: watched }, range: this_year, by: watched_on } views: - id: main blocks: - type: add-button label: Add the movie on this page adds: movie prefill: { title: $tab.title, link: $tab.url, cover: $tab.image } - { type: add-button, label: Add a movie, adds: movie } - { type: tag-filter, collection: movie, field: tags } - type: board collection: movie group_by: status card: { title: title, subtitle: director, image: cover, badge: rating } - id: stats label: Stats blocks: - { type: stat, label: Watched this year, value: $watched_this_year } - type: chart label: Movies per month kind: bar series: { count: movie, where: { status: watched }, by: watched_on, group: month, range: 12mo } today: default_on: true widget: type: stats label: Movieshelf items: - { label: Watchlist, value: $watchlist } - { label: Watched this year, value: $watched_this_year } rules: - collection: movie when: { status: watched } set: { watched_on: $today_date } only_if_empty: true ``` ### kanban ```yaml schema_version: 1 id: kanban name: Kanban version: 1.0.0 icon: check description: Boards with To do, In progress and Done. Link a board to a task to open it from there. author: Pomodoso license: MIT collections: - key: board kind: item title_field: title fields: - { key: title, type: text, label: Name } - { key: task, type: task, label: Linked task, optional: true } - { key: notes, type: longtext, optional: true } - key: state type: select options: [open, closed] default: open - key: card kind: item title_field: title fields: - { key: title, type: text } - { key: board, type: ref, collection: board } - key: status type: select user_editable: true options: - { value: todo, label: To do, color: "#B9B4A7" } - { value: doing, label: In progress, color: "#E0B04A" } - { value: done, label: Done, color: "#2D8A7A" } default: todo - { key: notes, type: longtext, optional: true } views: - id: main label: Boards blocks: - { type: add-button, label: New board, adds: board } - type: list collection: board filter: { state: open } primary: title secondary: [task] sort: { field: created_at, order: desc } opens: kanban swipe: { label: Close, set: { state: closed } } - id: closed label: Closed blocks: - type: list collection: board filter: { state: closed } primary: title opens: kanban swipe: { label: Reopen, set: { state: open } } - id: kanban of: board layout: wide blocks: - { type: add-button, label: Add a task, adds: card, prefill: { board: $record } } - type: board collection: card filter: { board: $record } group_by: status card: { title: title } today: default_on: true widget: type: list label: Kanban collection: board where: { state: open } opens: kanban # Per board: its cards done, out of all of them (in progress counts as not done). badge: { count: card, where: { board: $record, status: done } } badge_of: { count: card, where: { board: $record } } ```