From 9290c0c6276556cf7a5aff496ae461f4c17eaf3a Mon Sep 17 00:00:00 2001 From: callumalpass Date: Tue, 27 Oct 2026 21:58:45 +1100 Subject: [PATCH] Add TaskNotes rc.19: tasknotes.task rc.6 and the TaskNotes settings record - Add mdbase.app-settings 1.0.0 (byte-identical to mdbase Reader's), tasknotes.settings 1.0.0 and the tasknotes-settings seed type. - Add tasknotes.task 0.3.0-rc.6 at a versioned contract target, keep rc.5 managed at _contracts/tasknotes.task.md for types that still implement it, and seed starter revision 6 with baselines 5 to 1. - Hide rc.18; extend the upgrade and plugin-collection tests. --- README.md | 23 + contracts/mdbase.app-settings/1.0.0.md | 55 +++ contracts/tasknotes.settings/1.0.0.md | 48 ++ contracts/tasknotes.task/0.3.0-rc.6.md | 399 ++++++++++++++++ .../contracts/mdbase.app-settings/1.0.0.md | 55 +++ .../contracts/tasknotes.settings/1.0.0.md | 48 ++ .../contracts/tasknotes.task/0.3.0-rc.6.md | 399 ++++++++++++++++ .../mdbase.app-settings/1.0.0.schema.json | 36 ++ .../tasknotes.settings/1.0.0.schema.json | 141 ++++++ .../0.3.0-rc.6.schema.json | 343 ++++++++++++++ .../tasknotes.task/0.3.0-rc.6.schema.json | 202 ++++++++ dist/artifacts/types/tasknotes-settings/1.md | 155 ++++++ dist/artifacts/types/tasknotes-task/6.md | 444 ++++++++++++++++++ dist/catalog.json | 84 +++- dist/packs/tasknotes.task/0.3.0-rc.19.json | 167 +++++++ .../mdbase.app-settings/1.0.0.schema.json | 36 ++ .../tasknotes.settings/1.0.0.schema.json | 141 ++++++ .../0.3.0-rc.6.schema.json | 343 ++++++++++++++ .../tasknotes.task/0.3.0-rc.6.schema.json | 202 ++++++++ packs/tasknotes.task/0.3.0-rc.18.pack.yaml | 2 +- packs/tasknotes.task/0.3.0-rc.19.pack.yaml | 77 +++ schemas/mdbase.app-settings/1.0.0.schema.json | 36 ++ schemas/tasknotes.settings/1.0.0.schema.json | 141 ++++++ .../0.3.0-rc.6.schema.json | 343 ++++++++++++++ schemas/tasknotes.task/0.3.0-rc.6.schema.json | 202 ++++++++ scripts/sync-tasknotes-pack.mjs | 6 + scripts/tasknotes-plugin-collections.test.mjs | 9 +- scripts/tasknotes-upgrade.test.mjs | 45 +- types/tasknotes-settings/1.md | 155 ++++++ types/tasknotes-task/6.md | 444 ++++++++++++++++++ 30 files changed, 4772 insertions(+), 9 deletions(-) create mode 100644 contracts/mdbase.app-settings/1.0.0.md create mode 100644 contracts/tasknotes.settings/1.0.0.md create mode 100644 contracts/tasknotes.task/0.3.0-rc.6.md create mode 100644 dist/artifacts/contracts/mdbase.app-settings/1.0.0.md create mode 100644 dist/artifacts/contracts/tasknotes.settings/1.0.0.md create mode 100644 dist/artifacts/contracts/tasknotes.task/0.3.0-rc.6.md create mode 100644 dist/artifacts/schemas/mdbase.app-settings/1.0.0.schema.json create mode 100644 dist/artifacts/schemas/tasknotes.settings/1.0.0.schema.json create mode 100644 dist/artifacts/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json create mode 100644 dist/artifacts/schemas/tasknotes.task/0.3.0-rc.6.schema.json create mode 100644 dist/artifacts/types/tasknotes-settings/1.md create mode 100644 dist/artifacts/types/tasknotes-task/6.md create mode 100644 dist/packs/tasknotes.task/0.3.0-rc.19.json create mode 100644 dist/schemas/mdbase.app-settings/1.0.0.schema.json create mode 100644 dist/schemas/tasknotes.settings/1.0.0.schema.json create mode 100644 dist/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json create mode 100644 dist/schemas/tasknotes.task/0.3.0-rc.6.schema.json create mode 100644 packs/tasknotes.task/0.3.0-rc.19.pack.yaml create mode 100644 schemas/mdbase.app-settings/1.0.0.schema.json create mode 100644 schemas/tasknotes.settings/1.0.0.schema.json create mode 100644 schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json create mode 100644 schemas/tasknotes.task/0.3.0-rc.6.schema.json create mode 100644 types/tasknotes-settings/1.md create mode 100644 types/tasknotes-task/6.md diff --git a/README.md b/README.md index 4e7944c..0d2f7dd 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,29 @@ hidden. A customised task type whose lock records no origin is preserved, and because it still implements the replaced contract the upgrade is blocked for review rather than merged against a guessed starter. +## TaskNotes settings record + +rc.19 provides `tasknotes.task` 0.3.0-rc.6, `tasknotes.settings` 1.0.0 and the +generic `mdbase.app-settings` 1.0.0 (copied byte for byte from mdbase Reader, so +both apps install the same contract). rc.6 moves app behaviour out of the task +binding: NLP triggers, templating, archive moves, time tracking, checkbox +resets on recurrence, the link write format, and per-status `next_status`, +`exclude_from_cycle`, `auto_archive` and `auto_archive_delay_minutes`. TaskNotes +keeps them in one record, `_settings/dev.tasknotes.md`, of the seeded +`tasknotes-settings` type (unique on `app`). The pack seeds the type only; the +record is written by TaskNotes, which reads each setting from the record, then +from an rc.5 binding that still holds it, then its default. + +The rc.6 contract is installed at `_contracts/tasknotes.task/0.3.0-rc.6.md`. +The rc.5 contract stays managed at `_contracts/tasknotes.task.md`, not +provided, so task types that still implement it (edited types the pack +preserves, and types the TaskNotes plugin wrote) stay valid until TaskNotes +upgrades them. Starter revision 6 (type v5) is revision 5 with the moved +settings removed and the contract version raised; it lists revisions 5 to 1 as +baselines, and rc.18 is hidden. A collection that edited its status +definitions (for example their colours) conflicts on that list and the +upgrade is blocked for review; TaskNotes upgrades such a type itself. + Starter files are named by revision (`types/tasknotes-task/.md`); a revision that does not change the task data keeps the type `version`, so collections already at that version upgrade without a version conflict. diff --git a/contracts/mdbase.app-settings/1.0.0.md b/contracts/mdbase.app-settings/1.0.0.md new file mode 100644 index 0000000..2a64809 --- /dev/null +++ b/contracts/mdbase.app-settings/1.0.0.md @@ -0,0 +1,55 @@ +--- +kind: mdbase.contract +contract_type: record +id: mdbase.app-settings +version: 1.0.0 +name: App settings +description: One record per app holding the policy that app's clients honour in this collection. +record_schema: + dialect: json-schema-2020-12 + ref: ../../schemas/mdbase.app-settings/1.0.0.schema.json +--- + +# App settings + +An app settings record holds values that every client of one app honours in this +collection, such as how new files are named. The values change client behaviour, +never what another record means. + +## Location and identity + +A collection-scope record lives at `_settings/.md`, where `` is the +record's `app` field. Clients read it by that path, without a query. Each +implementing type declares `collection.unique` on `app` with `scope: type`, so a +collection holds at most one collection-scope record per app. + +The record's `type` field names the app's own settings type, not a shared value. +Generic tools find every settings record through this contract. + +## Reserved fields + +- `app`: the app id. +- `scope`: `collection`, or `user` for one person's overrides. +- `user`: a link to an `mdbase.person` record, present only when `scope` is + `user`. +- `settings_version`: the version of the app's settings schema that last wrote + the record. + +Every other frontmatter field belongs to the app and is described by the app's +own settings contract. The body is free Markdown for people; apps never parse it. + +## Client behaviour + +- A missing record means every setting has its default. Clients never create the + record on read. +- A missing or invalid field takes its default; valid fields are used as + written. The record is not rewritten until someone saves. +- A save creates the record at its fixed path the first time, and otherwise + patches only the fields it changes, guarded by the record's revision. +- A client that finds a `settings_version` newer than it understands treats the + settings as read-only and uses them as written. + +## Authority + +This artifact is passive. A settings record grants nothing and must never hold +secrets: anyone who can read or write records can read or edit it. diff --git a/contracts/tasknotes.settings/1.0.0.md b/contracts/tasknotes.settings/1.0.0.md new file mode 100644 index 0000000..721723b --- /dev/null +++ b/contracts/tasknotes.settings/1.0.0.md @@ -0,0 +1,48 @@ +--- +kind: mdbase.contract +contract_type: record +id: tasknotes.settings +version: 1.0.0 +name: TaskNotes settings +description: Collection-wide TaskNotes behaviour, such as templates, archive moves and status cycling. +record_schema: + dialect: json-schema-2020-12 + ref: ../../schemas/tasknotes.settings/1.0.0.schema.json +--- + +# TaskNotes settings + +The collection's settings record for TaskNotes, at `_settings/dev.tasknotes.md`. +It also implements `mdbase.app-settings`, whose reserved fields (`app`, `scope`, +`settings_version`) it shares. + +These settings change what TaskNotes clients do, never what a task record +means: that stays in the `tasknotes.task` binding of each task type. +`tasknotes.task` 0.3.0-rc.6 moved them here from the binding. A client reads +each setting from this record, then from an earlier binding that still holds +it, then uses its default, so a collection whose task type is still on rc.5 +keeps its behaviour until it is upgraded. + +## Fields + +- `nlp_triggers`: natural-language capture triggers. Without it, each client + uses its own defaults. +- `template_enabled`, `template_path`, `occurrence_template_enabled`, + `occurrence_template_path`, `template_failure_mode`, + `template_unknown_variable_policy`: body templates for new tasks and + materialized occurrences. +- `move_on_archive`, `archive_folder`: whether archiving moves the file, and + where to. +- `auto_stop_time_tracking_on_complete`: stop a running timer on completion. +- `reset_body_checkboxes_on_recurrence`: uncheck body checkboxes when a + recurring task advances. +- `link_write_format`: `wikilink` or `markdown` for links written to task + frontmatter. +- `status_behavior`: per status value, `next_status`, `exclude_from_cycle`, + `auto_archive` and `auto_archive_delay_minutes`. A status without an entry + has no next status and no auto-archive (5 minute delay), and is out of the + cycle exactly when it is a skipped status. + +## Authority + +This artifact is passive and grants nothing. diff --git a/contracts/tasknotes.task/0.3.0-rc.6.md b/contracts/tasknotes.task/0.3.0-rc.6.md new file mode 100644 index 0000000..3c2c50c --- /dev/null +++ b/contracts/tasknotes.task/0.3.0-rc.6.md @@ -0,0 +1,399 @@ +--- +kind: mdbase.contract +contract_type: record +id: tasknotes.task +version: 0.3.0-rc.6 +name: TaskNotes task +description: Portable task data and behavior defined by tasknotes-spec 0.3.0-rc.6. +record_schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + $id: https://tasknotes.dev/schemas/tasknotes-task.schema.json + title: TaskNotes portable task view + description: The storage-neutral record view exposed by the tasknotes.task 0.3.0-rc.6 record contract. + type: object + required: + - status + - dateCreated + additionalProperties: false + properties: + id: + type: string + minLength: 1 + title: + type: string + minLength: 1 + status: + type: string + minLength: 1 + priority: + type: string + minLength: 1 + due: + anyOf: + - type: string + format: date + - type: string + format: date-time + scheduled: + anyOf: + - type: string + format: date + - type: string + format: date-time + contexts: + type: array + items: + type: string + projects: + type: array + items: + type: string + assignees: + type: array + uniqueItems: true + items: + type: string + minLength: 1 + pattern: \S + description: Links to records implementing mdbase.person, such as [[Alex Rivera]]. Implementing types declare this field in collection.links. These references never grant collection access. + attachments: + type: array + uniqueItems: true + items: + type: string + minLength: 1 + timeEstimate: + type: integer + minimum: 0 + completedDate: + type: string + format: date + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + recurrence: + type: string + recurrenceAnchor: + enum: + - scheduled + - completion + recurrenceParent: + type: string + occurrenceDate: + type: string + format: date + occurrenceMaterialization: + enum: + - manual + - on_completion + - rolling + occurrenceNextTrigger: + enum: + - completion + - completion_or_skip + occurrenceTemplate: + type: string + occurrencePastHorizon: + type: string + occurrenceFutureHorizon: + type: string + tags: + type: array + items: + type: string + timeEntries: + type: array + items: + type: object + reminders: + type: array + items: + type: object + blockedBy: + type: array + items: + type: object + completeInstances: + type: array + items: + type: string + format: date + skippedInstances: + type: array + items: + type: string + format: date + icsEventId: + type: array + items: + type: string + googleCalendarEventId: + type: string + googleCalendarExceptionEventId: + type: string + googleCalendarExceptionOriginalScheduled: + type: string + format: date + googleCalendarMovedOriginalDates: + type: array + items: + type: string + format: date + sortOrder: + type: string +binding_schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + $id: https://tasknotes.dev/schemas/tasknotes-task-binding.schema.json + title: TaskNotes task data-contract binding + description: Semantic configuration supplied by an mdbase type that implements tasknotes.task 0.3.0-rc.6. App behaviour, such as templates, archive moves, status cycling and natural-language triggers, lives in the app's tasknotes.settings record instead. + type: object + required: + - profiles + - capabilities + - title + - status + - priority + - recurrence + - occurrences + - links + - archive + properties: + profiles: + type: array + minItems: 1 + uniqueItems: true + items: + enum: + - core-lite + - recurrence + - templating + - materialized-occurrences + - extended + capabilities: + type: array + uniqueItems: true + items: + enum: + - dependencies + - reminders + - attachments + - links + - time-tracking + - materialized-occurrences + - rename + - archive + - batch + - concurrency + - dry-run + - migration + - templating + title: + $ref: "#/$defs/titlePolicy" + status: + $ref: "#/$defs/statusPolicy" + priority: + $ref: "#/$defs/priorityPolicy" + recurrence: + $ref: "#/$defs/recurrencePolicy" + occurrences: + $ref: "#/$defs/occurrencePolicy" + links: + $ref: "#/$defs/linkPolicy" + archive: + $ref: "#/$defs/archivePolicy" + additionalProperties: false + $defs: + nonEmptyString: + type: string + minLength: 1 + stringSet: + type: array + uniqueItems: true + items: + $ref: "#/$defs/nonEmptyString" + titlePolicy: + type: object + required: + - storage + properties: + storage: + enum: + - filename + - frontmatter + filename_format: + enum: + - title + - zettel + - timestamp + - uuid + - custom + custom_filename_template: + $ref: "#/$defs/nonEmptyString" + allOf: + - if: + properties: + filename_format: + const: custom + required: + - filename_format + then: + properties: + custom_filename_template: + $ref: "#/$defs/nonEmptyString" + required: + - custom_filename_template + additionalProperties: true + statusDefinition: + type: object + required: + - value + - label + - color + - is_completed + - is_skipped + - order + properties: + value: + $ref: "#/$defs/nonEmptyString" + label: + type: string + color: + type: string + icon: + $ref: "#/$defs/nonEmptyString" + is_completed: + type: boolean + is_skipped: + type: boolean + order: + type: number + additionalProperties: true + statusPolicy: + type: object + required: + - values + - default + - completed_values + - definitions + properties: + values: + $ref: "#/$defs/stringSet" + default: + $ref: "#/$defs/nonEmptyString" + completed_values: + $ref: "#/$defs/stringSet" + skipped_values: + $ref: "#/$defs/stringSet" + default_skipped: + $ref: "#/$defs/nonEmptyString" + definitions: + type: array + items: + $ref: "#/$defs/statusDefinition" + additionalProperties: false + priorityDefinition: + type: object + required: + - value + - label + - color + - weight + properties: + value: + $ref: "#/$defs/nonEmptyString" + label: + type: string + color: + type: string + icon: + $ref: "#/$defs/nonEmptyString" + weight: + type: number + additionalProperties: true + priorityPolicy: + type: object + required: + - values + - default + - definitions + properties: + values: + $ref: "#/$defs/stringSet" + default: + $ref: "#/$defs/nonEmptyString" + definitions: + type: array + items: + $ref: "#/$defs/priorityDefinition" + additionalProperties: false + recurrencePolicy: + type: object + required: + - syntax + - maintain_due_date_offset + properties: + syntax: + const: tasknotes + maintain_due_date_offset: + type: boolean + additionalProperties: false + occurrencePolicy: + type: object + required: + - identity_roles + - default_materialization + - default_next_trigger + properties: + identity_roles: + const: + - recurrenceParent + - occurrenceDate + default_materialization: + enum: + - manual + - on_completion + - rolling + default_next_trigger: + enum: + - completion + - completion_or_skip + past_horizon: + $ref: "#/$defs/nonEmptyString" + future_horizon: + $ref: "#/$defs/nonEmptyString" + additionalProperties: false + linkPolicy: + type: object + required: + - accepted_formats + properties: + accepted_formats: + type: array + minItems: 1 + uniqueItems: true + items: + enum: + - wikilink + - markdown + additionalProperties: false + archivePolicy: + type: object + required: + - archived_tag + properties: + archived_tag: + $ref: "#/$defs/nonEmptyString" + additionalProperties: false +--- + +# TaskNotes task contract + +Types implement this contract through `implements`; applications consume +the normalized contract view rather than assuming frontmatter names. diff --git a/dist/artifacts/contracts/mdbase.app-settings/1.0.0.md b/dist/artifacts/contracts/mdbase.app-settings/1.0.0.md new file mode 100644 index 0000000..2a64809 --- /dev/null +++ b/dist/artifacts/contracts/mdbase.app-settings/1.0.0.md @@ -0,0 +1,55 @@ +--- +kind: mdbase.contract +contract_type: record +id: mdbase.app-settings +version: 1.0.0 +name: App settings +description: One record per app holding the policy that app's clients honour in this collection. +record_schema: + dialect: json-schema-2020-12 + ref: ../../schemas/mdbase.app-settings/1.0.0.schema.json +--- + +# App settings + +An app settings record holds values that every client of one app honours in this +collection, such as how new files are named. The values change client behaviour, +never what another record means. + +## Location and identity + +A collection-scope record lives at `_settings/.md`, where `` is the +record's `app` field. Clients read it by that path, without a query. Each +implementing type declares `collection.unique` on `app` with `scope: type`, so a +collection holds at most one collection-scope record per app. + +The record's `type` field names the app's own settings type, not a shared value. +Generic tools find every settings record through this contract. + +## Reserved fields + +- `app`: the app id. +- `scope`: `collection`, or `user` for one person's overrides. +- `user`: a link to an `mdbase.person` record, present only when `scope` is + `user`. +- `settings_version`: the version of the app's settings schema that last wrote + the record. + +Every other frontmatter field belongs to the app and is described by the app's +own settings contract. The body is free Markdown for people; apps never parse it. + +## Client behaviour + +- A missing record means every setting has its default. Clients never create the + record on read. +- A missing or invalid field takes its default; valid fields are used as + written. The record is not rewritten until someone saves. +- A save creates the record at its fixed path the first time, and otherwise + patches only the fields it changes, guarded by the record's revision. +- A client that finds a `settings_version` newer than it understands treats the + settings as read-only and uses them as written. + +## Authority + +This artifact is passive. A settings record grants nothing and must never hold +secrets: anyone who can read or write records can read or edit it. diff --git a/dist/artifacts/contracts/tasknotes.settings/1.0.0.md b/dist/artifacts/contracts/tasknotes.settings/1.0.0.md new file mode 100644 index 0000000..721723b --- /dev/null +++ b/dist/artifacts/contracts/tasknotes.settings/1.0.0.md @@ -0,0 +1,48 @@ +--- +kind: mdbase.contract +contract_type: record +id: tasknotes.settings +version: 1.0.0 +name: TaskNotes settings +description: Collection-wide TaskNotes behaviour, such as templates, archive moves and status cycling. +record_schema: + dialect: json-schema-2020-12 + ref: ../../schemas/tasknotes.settings/1.0.0.schema.json +--- + +# TaskNotes settings + +The collection's settings record for TaskNotes, at `_settings/dev.tasknotes.md`. +It also implements `mdbase.app-settings`, whose reserved fields (`app`, `scope`, +`settings_version`) it shares. + +These settings change what TaskNotes clients do, never what a task record +means: that stays in the `tasknotes.task` binding of each task type. +`tasknotes.task` 0.3.0-rc.6 moved them here from the binding. A client reads +each setting from this record, then from an earlier binding that still holds +it, then uses its default, so a collection whose task type is still on rc.5 +keeps its behaviour until it is upgraded. + +## Fields + +- `nlp_triggers`: natural-language capture triggers. Without it, each client + uses its own defaults. +- `template_enabled`, `template_path`, `occurrence_template_enabled`, + `occurrence_template_path`, `template_failure_mode`, + `template_unknown_variable_policy`: body templates for new tasks and + materialized occurrences. +- `move_on_archive`, `archive_folder`: whether archiving moves the file, and + where to. +- `auto_stop_time_tracking_on_complete`: stop a running timer on completion. +- `reset_body_checkboxes_on_recurrence`: uncheck body checkboxes when a + recurring task advances. +- `link_write_format`: `wikilink` or `markdown` for links written to task + frontmatter. +- `status_behavior`: per status value, `next_status`, `exclude_from_cycle`, + `auto_archive` and `auto_archive_delay_minutes`. A status without an entry + has no next status and no auto-archive (5 minute delay), and is out of the + cycle exactly when it is a skipped status. + +## Authority + +This artifact is passive and grants nothing. diff --git a/dist/artifacts/contracts/tasknotes.task/0.3.0-rc.6.md b/dist/artifacts/contracts/tasknotes.task/0.3.0-rc.6.md new file mode 100644 index 0000000..3c2c50c --- /dev/null +++ b/dist/artifacts/contracts/tasknotes.task/0.3.0-rc.6.md @@ -0,0 +1,399 @@ +--- +kind: mdbase.contract +contract_type: record +id: tasknotes.task +version: 0.3.0-rc.6 +name: TaskNotes task +description: Portable task data and behavior defined by tasknotes-spec 0.3.0-rc.6. +record_schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + $id: https://tasknotes.dev/schemas/tasknotes-task.schema.json + title: TaskNotes portable task view + description: The storage-neutral record view exposed by the tasknotes.task 0.3.0-rc.6 record contract. + type: object + required: + - status + - dateCreated + additionalProperties: false + properties: + id: + type: string + minLength: 1 + title: + type: string + minLength: 1 + status: + type: string + minLength: 1 + priority: + type: string + minLength: 1 + due: + anyOf: + - type: string + format: date + - type: string + format: date-time + scheduled: + anyOf: + - type: string + format: date + - type: string + format: date-time + contexts: + type: array + items: + type: string + projects: + type: array + items: + type: string + assignees: + type: array + uniqueItems: true + items: + type: string + minLength: 1 + pattern: \S + description: Links to records implementing mdbase.person, such as [[Alex Rivera]]. Implementing types declare this field in collection.links. These references never grant collection access. + attachments: + type: array + uniqueItems: true + items: + type: string + minLength: 1 + timeEstimate: + type: integer + minimum: 0 + completedDate: + type: string + format: date + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + recurrence: + type: string + recurrenceAnchor: + enum: + - scheduled + - completion + recurrenceParent: + type: string + occurrenceDate: + type: string + format: date + occurrenceMaterialization: + enum: + - manual + - on_completion + - rolling + occurrenceNextTrigger: + enum: + - completion + - completion_or_skip + occurrenceTemplate: + type: string + occurrencePastHorizon: + type: string + occurrenceFutureHorizon: + type: string + tags: + type: array + items: + type: string + timeEntries: + type: array + items: + type: object + reminders: + type: array + items: + type: object + blockedBy: + type: array + items: + type: object + completeInstances: + type: array + items: + type: string + format: date + skippedInstances: + type: array + items: + type: string + format: date + icsEventId: + type: array + items: + type: string + googleCalendarEventId: + type: string + googleCalendarExceptionEventId: + type: string + googleCalendarExceptionOriginalScheduled: + type: string + format: date + googleCalendarMovedOriginalDates: + type: array + items: + type: string + format: date + sortOrder: + type: string +binding_schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + $id: https://tasknotes.dev/schemas/tasknotes-task-binding.schema.json + title: TaskNotes task data-contract binding + description: Semantic configuration supplied by an mdbase type that implements tasknotes.task 0.3.0-rc.6. App behaviour, such as templates, archive moves, status cycling and natural-language triggers, lives in the app's tasknotes.settings record instead. + type: object + required: + - profiles + - capabilities + - title + - status + - priority + - recurrence + - occurrences + - links + - archive + properties: + profiles: + type: array + minItems: 1 + uniqueItems: true + items: + enum: + - core-lite + - recurrence + - templating + - materialized-occurrences + - extended + capabilities: + type: array + uniqueItems: true + items: + enum: + - dependencies + - reminders + - attachments + - links + - time-tracking + - materialized-occurrences + - rename + - archive + - batch + - concurrency + - dry-run + - migration + - templating + title: + $ref: "#/$defs/titlePolicy" + status: + $ref: "#/$defs/statusPolicy" + priority: + $ref: "#/$defs/priorityPolicy" + recurrence: + $ref: "#/$defs/recurrencePolicy" + occurrences: + $ref: "#/$defs/occurrencePolicy" + links: + $ref: "#/$defs/linkPolicy" + archive: + $ref: "#/$defs/archivePolicy" + additionalProperties: false + $defs: + nonEmptyString: + type: string + minLength: 1 + stringSet: + type: array + uniqueItems: true + items: + $ref: "#/$defs/nonEmptyString" + titlePolicy: + type: object + required: + - storage + properties: + storage: + enum: + - filename + - frontmatter + filename_format: + enum: + - title + - zettel + - timestamp + - uuid + - custom + custom_filename_template: + $ref: "#/$defs/nonEmptyString" + allOf: + - if: + properties: + filename_format: + const: custom + required: + - filename_format + then: + properties: + custom_filename_template: + $ref: "#/$defs/nonEmptyString" + required: + - custom_filename_template + additionalProperties: true + statusDefinition: + type: object + required: + - value + - label + - color + - is_completed + - is_skipped + - order + properties: + value: + $ref: "#/$defs/nonEmptyString" + label: + type: string + color: + type: string + icon: + $ref: "#/$defs/nonEmptyString" + is_completed: + type: boolean + is_skipped: + type: boolean + order: + type: number + additionalProperties: true + statusPolicy: + type: object + required: + - values + - default + - completed_values + - definitions + properties: + values: + $ref: "#/$defs/stringSet" + default: + $ref: "#/$defs/nonEmptyString" + completed_values: + $ref: "#/$defs/stringSet" + skipped_values: + $ref: "#/$defs/stringSet" + default_skipped: + $ref: "#/$defs/nonEmptyString" + definitions: + type: array + items: + $ref: "#/$defs/statusDefinition" + additionalProperties: false + priorityDefinition: + type: object + required: + - value + - label + - color + - weight + properties: + value: + $ref: "#/$defs/nonEmptyString" + label: + type: string + color: + type: string + icon: + $ref: "#/$defs/nonEmptyString" + weight: + type: number + additionalProperties: true + priorityPolicy: + type: object + required: + - values + - default + - definitions + properties: + values: + $ref: "#/$defs/stringSet" + default: + $ref: "#/$defs/nonEmptyString" + definitions: + type: array + items: + $ref: "#/$defs/priorityDefinition" + additionalProperties: false + recurrencePolicy: + type: object + required: + - syntax + - maintain_due_date_offset + properties: + syntax: + const: tasknotes + maintain_due_date_offset: + type: boolean + additionalProperties: false + occurrencePolicy: + type: object + required: + - identity_roles + - default_materialization + - default_next_trigger + properties: + identity_roles: + const: + - recurrenceParent + - occurrenceDate + default_materialization: + enum: + - manual + - on_completion + - rolling + default_next_trigger: + enum: + - completion + - completion_or_skip + past_horizon: + $ref: "#/$defs/nonEmptyString" + future_horizon: + $ref: "#/$defs/nonEmptyString" + additionalProperties: false + linkPolicy: + type: object + required: + - accepted_formats + properties: + accepted_formats: + type: array + minItems: 1 + uniqueItems: true + items: + enum: + - wikilink + - markdown + additionalProperties: false + archivePolicy: + type: object + required: + - archived_tag + properties: + archived_tag: + $ref: "#/$defs/nonEmptyString" + additionalProperties: false +--- + +# TaskNotes task contract + +Types implement this contract through `implements`; applications consume +the normalized contract view rather than assuming frontmatter names. diff --git a/dist/artifacts/schemas/mdbase.app-settings/1.0.0.schema.json b/dist/artifacts/schemas/mdbase.app-settings/1.0.0.schema.json new file mode 100644 index 0000000..d548b11 --- /dev/null +++ b/dist/artifacts/schemas/mdbase.app-settings/1.0.0.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "mdbase.app-settings 1.0.0 record contract view", + "description": "The reserved fields every app settings record shares. Everything else in the record belongs to the app and is described by the app's own settings contract.", + "type": "object", + "required": ["app", "scope", "settings_version"], + "properties": { + "app": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$", + "description": "The app whose clients honour these settings, such as tasknotes or dev.mdbase.reader." + }, + "scope": { + "enum": ["collection", "user"], + "description": "Who the values apply to: everyone using the app in this collection, or one person." + }, + "user": { + "type": "string", + "minLength": 1, + "description": "A link to the mdbase.person record the values apply to. Present only when scope is user." + }, + "settings_version": { + "type": "integer", + "minimum": 1, + "description": "The version of the app's settings schema that last wrote the record. A client that does not understand it treats the settings as read-only." + } + }, + "allOf": [ + { + "if": { "properties": { "scope": { "const": "user" } }, "required": ["scope"] }, + "then": { "required": ["user"] }, + "else": { "not": { "required": ["user"] } } + } + ], + "additionalProperties": true +} diff --git a/dist/artifacts/schemas/tasknotes.settings/1.0.0.schema.json b/dist/artifacts/schemas/tasknotes.settings/1.0.0.schema.json new file mode 100644 index 0000000..c1bcb16 --- /dev/null +++ b/dist/artifacts/schemas/tasknotes.settings/1.0.0.schema.json @@ -0,0 +1,141 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "tasknotes.settings 1.0.0", + "description": "Collection-wide behaviour that every TaskNotes client honours. Every field is optional and has a default, so a record with none of them behaves like no record at all.", + "type": "object", + "required": [ + "app", + "scope", + "settings_version" + ], + "properties": { + "app": { + "const": "dev.tasknotes", + "description": "Marks this record as TaskNotes' settings." + }, + "scope": { + "const": "collection", + "description": "These settings apply to everyone using TaskNotes in this collection." + }, + "settings_version": { + "type": "integer", + "minimum": 1, + "description": "The version of these settings that last wrote the record. TaskNotes writes 1." + }, + "nlp_triggers": { + "type": "array", + "items": { + "type": "object", + "required": [ + "property_id", + "trigger", + "enabled" + ], + "properties": { + "property_id": { + "type": "string", + "minLength": 1 + }, + "trigger": { + "type": "string", + "minLength": 1 + }, + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "description": "Natural-language capture triggers, such as @ for contexts. Without the field each client uses its own defaults." + }, + "template_enabled": { + "type": "boolean", + "default": false, + "description": "Apply template_path to the body of new tasks." + }, + "template_path": { + "type": "string", + "description": "The template for new task bodies. Empty or absent means none." + }, + "occurrence_template_enabled": { + "type": "boolean", + "default": false, + "description": "Apply occurrence_template_path to new materialized occurrences." + }, + "occurrence_template_path": { + "type": "string", + "description": "The template for new occurrence bodies. Empty or absent means none." + }, + "template_failure_mode": { + "enum": [ + "error", + "warning_fallback" + ], + "description": "What a client does when a template cannot be applied." + }, + "template_unknown_variable_policy": { + "enum": [ + "preserve", + "empty" + ], + "description": "What a client writes for a template variable it does not know." + }, + "move_on_archive": { + "type": "boolean", + "default": false, + "description": "Move a task's file to archive_folder when it is archived." + }, + "archive_folder": { + "type": "string", + "description": "Where archived tasks move to. Empty or absent means the client's default." + }, + "auto_stop_time_tracking_on_complete": { + "type": "boolean", + "default": false, + "description": "Stop a running timer when its task is completed." + }, + "reset_body_checkboxes_on_recurrence": { + "type": "boolean", + "default": false, + "description": "Uncheck body checkboxes when a recurring task moves to its next occurrence." + }, + "link_write_format": { + "enum": [ + "wikilink", + "markdown" + ], + "default": "wikilink", + "description": "How clients write links into task frontmatter. Both formats are always read." + }, + "status_behavior": { + "type": "object", + "description": "Behaviour per status value. A status without an entry has no next status and no auto-archive, and is out of the status cycle exactly when it is a skipped status.", + "additionalProperties": { + "type": "object", + "properties": { + "next_status": { + "type": "string", + "minLength": 1, + "description": "The status the cycle moves to next." + }, + "exclude_from_cycle": { + "type": "boolean", + "description": "Leave this status out of the status cycle." + }, + "auto_archive": { + "type": "boolean", + "description": "Archive a task some time after it takes this status." + }, + "auto_archive_delay_minutes": { + "type": "number", + "minimum": 0, + "description": "How long after taking this status a task is archived." + } + }, + "additionalProperties": false + }, + "default": {} + } + }, + "additionalProperties": true +} diff --git a/dist/artifacts/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json b/dist/artifacts/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json new file mode 100644 index 0000000..b817391 --- /dev/null +++ b/dist/artifacts/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json @@ -0,0 +1,343 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://tasknotes.dev/schemas/tasknotes-task-binding.schema.json", + "title": "TaskNotes task data-contract binding", + "description": "Semantic configuration supplied by an mdbase type that implements tasknotes.task 0.3.0-rc.6. App behaviour, such as templates, archive moves, status cycling and natural-language triggers, lives in the app's tasknotes.settings record instead.", + "type": "object", + "required": [ + "profiles", + "capabilities", + "title", + "status", + "priority", + "recurrence", + "occurrences", + "links", + "archive" + ], + "properties": { + "profiles": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "enum": [ + "core-lite", + "recurrence", + "templating", + "materialized-occurrences", + "extended" + ] + } + }, + "capabilities": { + "type": "array", + "uniqueItems": true, + "items": { + "enum": [ + "dependencies", + "reminders", + "attachments", + "links", + "time-tracking", + "materialized-occurrences", + "rename", + "archive", + "batch", + "concurrency", + "dry-run", + "migration", + "templating" + ] + } + }, + "title": { + "$ref": "#/$defs/titlePolicy" + }, + "status": { + "$ref": "#/$defs/statusPolicy" + }, + "priority": { + "$ref": "#/$defs/priorityPolicy" + }, + "recurrence": { + "$ref": "#/$defs/recurrencePolicy" + }, + "occurrences": { + "$ref": "#/$defs/occurrencePolicy" + }, + "links": { + "$ref": "#/$defs/linkPolicy" + }, + "archive": { + "$ref": "#/$defs/archivePolicy" + } + }, + "additionalProperties": false, + "$defs": { + "nonEmptyString": { + "type": "string", + "minLength": 1 + }, + "stringSet": { + "type": "array", + "uniqueItems": true, + "items": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "titlePolicy": { + "type": "object", + "required": [ + "storage" + ], + "properties": { + "storage": { + "enum": [ + "filename", + "frontmatter" + ] + }, + "filename_format": { + "enum": [ + "title", + "zettel", + "timestamp", + "uuid", + "custom" + ] + }, + "custom_filename_template": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "allOf": [ + { + "if": { + "properties": { + "filename_format": { + "const": "custom" + } + }, + "required": [ + "filename_format" + ] + }, + "then": { + "properties": { + "custom_filename_template": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "required": [ + "custom_filename_template" + ] + } + } + ], + "additionalProperties": true + }, + "statusDefinition": { + "type": "object", + "required": [ + "value", + "label", + "color", + "is_completed", + "is_skipped", + "order" + ], + "properties": { + "value": { + "$ref": "#/$defs/nonEmptyString" + }, + "label": { + "type": "string" + }, + "color": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/nonEmptyString" + }, + "is_completed": { + "type": "boolean" + }, + "is_skipped": { + "type": "boolean" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": true + }, + "statusPolicy": { + "type": "object", + "required": [ + "values", + "default", + "completed_values", + "definitions" + ], + "properties": { + "values": { + "$ref": "#/$defs/stringSet" + }, + "default": { + "$ref": "#/$defs/nonEmptyString" + }, + "completed_values": { + "$ref": "#/$defs/stringSet" + }, + "skipped_values": { + "$ref": "#/$defs/stringSet" + }, + "default_skipped": { + "$ref": "#/$defs/nonEmptyString" + }, + "definitions": { + "type": "array", + "items": { + "$ref": "#/$defs/statusDefinition" + } + } + }, + "additionalProperties": false + }, + "priorityDefinition": { + "type": "object", + "required": [ + "value", + "label", + "color", + "weight" + ], + "properties": { + "value": { + "$ref": "#/$defs/nonEmptyString" + }, + "label": { + "type": "string" + }, + "color": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/nonEmptyString" + }, + "weight": { + "type": "number" + } + }, + "additionalProperties": true + }, + "priorityPolicy": { + "type": "object", + "required": [ + "values", + "default", + "definitions" + ], + "properties": { + "values": { + "$ref": "#/$defs/stringSet" + }, + "default": { + "$ref": "#/$defs/nonEmptyString" + }, + "definitions": { + "type": "array", + "items": { + "$ref": "#/$defs/priorityDefinition" + } + } + }, + "additionalProperties": false + }, + "recurrencePolicy": { + "type": "object", + "required": [ + "syntax", + "maintain_due_date_offset" + ], + "properties": { + "syntax": { + "const": "tasknotes" + }, + "maintain_due_date_offset": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "occurrencePolicy": { + "type": "object", + "required": [ + "identity_roles", + "default_materialization", + "default_next_trigger" + ], + "properties": { + "identity_roles": { + "const": [ + "recurrenceParent", + "occurrenceDate" + ] + }, + "default_materialization": { + "enum": [ + "manual", + "on_completion", + "rolling" + ] + }, + "default_next_trigger": { + "enum": [ + "completion", + "completion_or_skip" + ] + }, + "past_horizon": { + "$ref": "#/$defs/nonEmptyString" + }, + "future_horizon": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "additionalProperties": false + }, + "linkPolicy": { + "type": "object", + "required": [ + "accepted_formats" + ], + "properties": { + "accepted_formats": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "enum": [ + "wikilink", + "markdown" + ] + } + } + }, + "additionalProperties": false + }, + "archivePolicy": { + "type": "object", + "required": [ + "archived_tag" + ], + "properties": { + "archived_tag": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "additionalProperties": false + } + } +} diff --git a/dist/artifacts/schemas/tasknotes.task/0.3.0-rc.6.schema.json b/dist/artifacts/schemas/tasknotes.task/0.3.0-rc.6.schema.json new file mode 100644 index 0000000..7575372 --- /dev/null +++ b/dist/artifacts/schemas/tasknotes.task/0.3.0-rc.6.schema.json @@ -0,0 +1,202 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://tasknotes.dev/schemas/tasknotes-task.schema.json", + "title": "TaskNotes portable task view", + "description": "The storage-neutral record view exposed by the tasknotes.task 0.3.0-rc.6 record contract.", + "type": "object", + "required": [ + "status", + "dateCreated" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "status": { + "type": "string", + "minLength": 1 + }, + "priority": { + "type": "string", + "minLength": 1 + }, + "due": { + "anyOf": [ + { + "type": "string", + "format": "date" + }, + { + "type": "string", + "format": "date-time" + } + ] + }, + "scheduled": { + "anyOf": [ + { + "type": "string", + "format": "date" + }, + { + "type": "string", + "format": "date-time" + } + ] + }, + "contexts": { + "type": "array", + "items": { + "type": "string" + } + }, + "projects": { + "type": "array", + "items": { + "type": "string" + } + }, + "assignees": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "pattern": "\\S" + }, + "description": "Links to records implementing mdbase.person, such as [[Alex Rivera]]. Implementing types declare this field in collection.links. These references never grant collection access." + }, + "attachments": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1 + } + }, + "timeEstimate": { + "type": "integer", + "minimum": 0 + }, + "completedDate": { + "type": "string", + "format": "date" + }, + "dateCreated": { + "type": "string", + "format": "date-time" + }, + "dateModified": { + "type": "string", + "format": "date-time" + }, + "recurrence": { + "type": "string" + }, + "recurrenceAnchor": { + "enum": [ + "scheduled", + "completion" + ] + }, + "recurrenceParent": { + "type": "string" + }, + "occurrenceDate": { + "type": "string", + "format": "date" + }, + "occurrenceMaterialization": { + "enum": [ + "manual", + "on_completion", + "rolling" + ] + }, + "occurrenceNextTrigger": { + "enum": [ + "completion", + "completion_or_skip" + ] + }, + "occurrenceTemplate": { + "type": "string" + }, + "occurrencePastHorizon": { + "type": "string" + }, + "occurrenceFutureHorizon": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "timeEntries": { + "type": "array", + "items": { + "type": "object" + } + }, + "reminders": { + "type": "array", + "items": { + "type": "object" + } + }, + "blockedBy": { + "type": "array", + "items": { + "type": "object" + } + }, + "completeInstances": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "skippedInstances": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "icsEventId": { + "type": "array", + "items": { + "type": "string" + } + }, + "googleCalendarEventId": { + "type": "string" + }, + "googleCalendarExceptionEventId": { + "type": "string" + }, + "googleCalendarExceptionOriginalScheduled": { + "type": "string", + "format": "date" + }, + "googleCalendarMovedOriginalDates": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "sortOrder": { + "type": "string" + } + } +} diff --git a/dist/artifacts/types/tasknotes-settings/1.md b/dist/artifacts/types/tasknotes-settings/1.md new file mode 100644 index 0000000..f4c7d80 --- /dev/null +++ b/dist/artifacts/types/tasknotes-settings/1.md @@ -0,0 +1,155 @@ +--- +kind: mdbase.type +name: tasknotes-settings +version: 1 +description: TaskNotes' collection-wide settings, one record at _settings/dev.tasknotes.md. +match: + where: + app: + eq: dev.tasknotes +schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + title: tasknotes.settings 1.0.0 + description: Collection-wide behaviour that every TaskNotes client honours. Every field is optional and has a default, so a record with none of them behaves like no record at all. + type: object + required: + - app + - scope + - settings_version + properties: + app: + const: dev.tasknotes + description: Marks this record as TaskNotes' settings. + scope: + const: collection + description: These settings apply to everyone using TaskNotes in this collection. + settings_version: + type: integer + minimum: 1 + description: The version of these settings that last wrote the record. TaskNotes writes 1. + nlp_triggers: + type: array + items: + type: object + required: + - property_id + - trigger + - enabled + properties: + property_id: + type: string + minLength: 1 + trigger: + type: string + minLength: 1 + enabled: + type: boolean + additionalProperties: false + description: Natural-language capture triggers, such as @ for contexts. Without the field each client uses its own defaults. + template_enabled: + type: boolean + default: false + description: Apply template_path to the body of new tasks. + template_path: + type: string + description: The template for new task bodies. Empty or absent means none. + occurrence_template_enabled: + type: boolean + default: false + description: Apply occurrence_template_path to new materialized occurrences. + occurrence_template_path: + type: string + description: The template for new occurrence bodies. Empty or absent means none. + template_failure_mode: + enum: + - error + - warning_fallback + description: What a client does when a template cannot be applied. + template_unknown_variable_policy: + enum: + - preserve + - empty + description: What a client writes for a template variable it does not know. + move_on_archive: + type: boolean + default: false + description: Move a task's file to archive_folder when it is archived. + archive_folder: + type: string + description: Where archived tasks move to. Empty or absent means the client's default. + auto_stop_time_tracking_on_complete: + type: boolean + default: false + description: Stop a running timer when its task is completed. + reset_body_checkboxes_on_recurrence: + type: boolean + default: false + description: Uncheck body checkboxes when a recurring task moves to its next occurrence. + link_write_format: + enum: + - wikilink + - markdown + default: wikilink + description: How clients write links into task frontmatter. Both formats are always read. + status_behavior: + type: object + description: Behaviour per status value. A status without an entry has no next status and no auto-archive, and is out of the status cycle exactly when it is a skipped status. + additionalProperties: + type: object + properties: + next_status: + type: string + minLength: 1 + description: The status the cycle moves to next. + exclude_from_cycle: + type: boolean + description: Leave this status out of the status cycle. + auto_archive: + type: boolean + description: Archive a task some time after it takes this status. + auto_archive_delay_minutes: + type: number + minimum: 0 + description: How long after taking this status a task is archived. + additionalProperties: false + default: {} + additionalProperties: true +collection: + unique: + - field: app + scope: type +implements: + - contract: mdbase.app-settings + version: 1.0.0 + fields: + app: app + scope: scope + settings_version: settings_version + - contract: tasknotes.settings + version: 1.0.0 + fields: + app: app + scope: scope + settings_version: settings_version + nlp_triggers: nlp_triggers + template_enabled: template_enabled + template_path: template_path + occurrence_template_enabled: occurrence_template_enabled + occurrence_template_path: occurrence_template_path + template_failure_mode: template_failure_mode + template_unknown_variable_policy: template_unknown_variable_policy + move_on_archive: move_on_archive + archive_folder: archive_folder + auto_stop_time_tracking_on_complete: auto_stop_time_tracking_on_complete + reset_body_checkboxes_on_recurrence: reset_body_checkboxes_on_recurrence + link_write_format: link_write_format + status_behavior: status_behavior +--- + +# TaskNotes settings + +Settings that every TaskNotes client honours in this collection, such as body +templates, archive moves and status cycling. TaskNotes reads them from +`_settings/dev.tasknotes.md` and writes only the fields a save changes. diff --git a/dist/artifacts/types/tasknotes-task/6.md b/dist/artifacts/types/tasknotes-task/6.md new file mode 100644 index 0000000..71bc380 --- /dev/null +++ b/dist/artifacts/types/tasknotes-task/6.md @@ -0,0 +1,444 @@ +--- +kind: mdbase.type +name: task +version: 5 +description: A task managed by TaskNotes. +match: + where: + tags: + contains: task +schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + type: object + additionalProperties: true + properties: + id: + type: string + minLength: 1 + title: + type: string + minLength: 1 + status: + enum: &a2 + - none + - open + - in-progress + - done + - cancelled + default: open + priority: + enum: &a4 + - none + - low + - normal + - high + default: normal + due: &a1 + anyOf: + - type: string + format: date + - type: string + format: date-time + scheduled: *a1 + contexts: + type: array + items: + type: string + projects: + type: array + items: + type: string + assignees: + type: array + items: + type: string + minLength: 1 + pattern: \S + uniqueItems: true + attachments: + type: array + items: + type: string + minLength: 1 + uniqueItems: true + timeEstimate: + type: integer + minimum: 0 + completedDate: + type: string + format: date + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + recurrence: + type: string + recurrence_anchor: + enum: + - scheduled + - completion + default: scheduled + occurrence_materialization: + enum: + - manual + - on_completion + - rolling + default: manual + occurrence_next_trigger: + enum: + - completion + - completion_or_skip + default: completion + occurrence_template: + type: string + occurrence_past_horizon: + type: string + occurrence_future_horizon: + type: string + recurrence_parent: + type: string + occurrence_date: + type: string + format: date + tags: + type: array + items: + type: string + timeEntries: + type: array + items: + type: object + additionalProperties: false + properties: + startTime: + type: string + format: date-time + endTime: + type: string + format: date-time + description: + type: string + duration: + type: integer + reminders: + type: array + items: + oneOf: + - type: object + required: + - id + - type + - absoluteTime + additionalProperties: false + properties: + id: + type: string + type: + const: absolute + description: + type: string + absoluteTime: + type: string + format: date-time + - type: object + required: + - id + - type + - relatedTo + - offset + additionalProperties: false + properties: + id: + type: string + type: + const: relative + description: + type: string + relatedTo: + enum: + - due + - scheduled + offset: + type: string + blockedBy: + type: array + items: + type: object + additionalProperties: false + properties: + uid: + type: string + reltype: + type: string + gap: + type: string + required: + - uid + complete_instances: + type: array + items: + type: string + format: date + skipped_instances: + type: array + items: + type: string + format: date + icsEventId: + type: array + items: + type: string + googleCalendarEventId: + type: string + googleCalendarExceptionEventId: + type: string + googleCalendarExceptionOriginalScheduled: + type: string + format: date + googleCalendarMovedOriginalDates: + type: array + items: + type: string + format: date + tasknotes_manual_order: + type: string + allOf: + - if: + required: + - status + properties: + status: + enum: &a3 + - done + not: + required: + - recurrence + then: + required: + - completedDate + required: + - title + - status + - dateCreated +collection: + read_defaults: + status: open + priority: normal + recurrence_anchor: scheduled + occurrence_materialization: manual + occurrence_next_trigger: completion + links: + projects[]: + target_type: any + validate_exists: false + assignees[]: + validate_exists: false + attachments[]: + validate_exists: false + occurrence_template: + target_type: any + validate_exists: false + recurrence_parent: + target_type: task + validate_exists: false + blockedBy[].uid: + target_type: task + validate_exists: false + path: + runtime: tasknotes + template: "{{zettel}}" + folder: tasks + generated_by: tasknotes.filename.create + display: + name_field: title + unique: + - field: id + scope: type +lifecycle: + on_create: + set: + id: + uuid: true + dateCreated: + now: true + dateModified: + now: true + on_update: + set: + dateModified: + now: true +implements: + - contract: tasknotes.task + version: 0.3.0-rc.6 + fields: + id: id + title: title + status: status + priority: priority + due: due + scheduled: scheduled + contexts: contexts + projects: projects + assignees: assignees + attachments: attachments + timeEstimate: timeEstimate + completedDate: completedDate + dateCreated: dateCreated + dateModified: dateModified + recurrence: recurrence + recurrenceAnchor: recurrence_anchor + occurrenceMaterialization: occurrence_materialization + occurrenceNextTrigger: occurrence_next_trigger + occurrenceTemplate: occurrence_template + occurrencePastHorizon: occurrence_past_horizon + occurrenceFutureHorizon: occurrence_future_horizon + recurrenceParent: recurrence_parent + occurrenceDate: occurrence_date + tags: tags + timeEntries: timeEntries + reminders: reminders + blockedBy: blockedBy + completeInstances: complete_instances + skippedInstances: skipped_instances + icsEventId: icsEventId + googleCalendarEventId: googleCalendarEventId + googleCalendarExceptionEventId: googleCalendarExceptionEventId + googleCalendarExceptionOriginalScheduled: googleCalendarExceptionOriginalScheduled + googleCalendarMovedOriginalDates: googleCalendarMovedOriginalDates + sortOrder: tasknotes_manual_order + binding: + profiles: + - core-lite + - recurrence + - materialized-occurrences + capabilities: + - dependencies + - reminders + - attachments + - links + - time-tracking + - materialized-occurrences + - archive + - templating + title: + storage: frontmatter + filename_format: zettel + status: + values: *a2 + default: open + completed_values: *a3 + skipped_values: + - cancelled + default_skipped: cancelled + definitions: + - value: none + label: None + color: "#94a3b8" + is_completed: false + is_skipped: false + order: 0 + - value: open + label: Open + color: "#64748b" + is_completed: false + is_skipped: false + order: 1 + - value: in-progress + label: In progress + color: "#3b82f6" + is_completed: false + is_skipped: false + order: 2 + - value: done + label: Done + color: "#22c55e" + is_completed: true + is_skipped: false + order: 3 + - value: cancelled + label: Cancelled + color: "#94a3b8" + is_completed: false + is_skipped: true + order: 4 + priority: + values: *a4 + default: normal + definitions: + - value: none + label: None + color: "#94a3b8" + weight: 0 + - value: low + label: Low + color: "#3b82f6" + weight: 1 + - value: normal + label: Normal + color: "#f59e0b" + weight: 2 + - value: high + label: High + color: "#ef4444" + weight: 3 + recurrence: + syntax: tasknotes + maintain_due_date_offset: true + occurrences: + identity_roles: + - recurrenceParent + - occurrenceDate + default_materialization: manual + default_next_trigger: completion + past_horizon: P0D + future_horizon: P14D + links: + accepted_formats: + - wikilink + - markdown + archive: + archived_tag: archived +x-tasknotes-generator: + managed_fields: + - attachments + - blockedBy + - complete_instances + - completedDate + - contexts + - dateCreated + - dateModified + - due + - googleCalendarEventId + - googleCalendarExceptionEventId + - googleCalendarExceptionOriginalScheduled + - googleCalendarMovedOriginalDates + - icsEventId + - id + - occurrence_date + - occurrence_future_horizon + - occurrence_materialization + - occurrence_next_trigger + - occurrence_past_horizon + - occurrence_template + - priority + - projects + - recurrence + - recurrence_anchor + - recurrence_parent + - reminders + - scheduled + - skipped_instances + - status + - tags + - tasknotes_manual_order + - timeEntries + - timeEstimate + - title +--- +# Task + +Task records live under `tasks/`. diff --git a/dist/catalog.json b/dist/catalog.json index e9a079b..d384356 100644 --- a/dist/catalog.json +++ b/dist/catalog.json @@ -9,6 +9,16 @@ "url": "https://mdbase.dev/" }, "contracts": [ + { + "id": "mdbase.app-settings", + "version": "1.0.0", + "name": "App settings", + "description": "One record per app holding the policy that app's clients honour in this collection.", + "contract_type": "record", + "digest": "sha256:9028d8ccd99cfbb4034399777376315486eb8e699aea7757a6b193743f1084c8", + "artifact": "./artifacts/contracts/mdbase.app-settings/1.0.0.md", + "standards": [] + }, { "id": "mdbase.comment", "version": "1.0.0", @@ -229,6 +239,16 @@ "artifact": "./artifacts/contracts/obsidian.base/1.0.0.md", "standards": [] }, + { + "id": "tasknotes.settings", + "version": "1.0.0", + "name": "TaskNotes settings", + "description": "Collection-wide TaskNotes behaviour, such as templates, archive moves and status cycling.", + "contract_type": "record", + "digest": "sha256:e8c25653ef37c032fb4cb1f1c3f7c618092a09c4911a41aba42c0476796fe0d1", + "artifact": "./artifacts/contracts/tasknotes.settings/1.0.0.md", + "standards": [] + }, { "id": "tasknotes.task", "version": "0.3.0-rc.3", @@ -248,6 +268,16 @@ "digest": "sha256:ecadd00700e249940f4244aaa5b5985a96557d13340463ec491dfa5e89b032a4", "artifact": "./artifacts/contracts/tasknotes.task/0.3.0-rc.5.md", "standards": [] + }, + { + "id": "tasknotes.task", + "version": "0.3.0-rc.6", + "name": "TaskNotes task", + "description": "Portable task data and behavior defined by tasknotes-spec 0.3.0-rc.6.", + "contract_type": "record", + "digest": "sha256:3f4eb90782948ed68112ffcc99575911036020544cf501de3d2265b588b38456", + "artifact": "./artifacts/contracts/tasknotes.task/0.3.0-rc.6.md", + "standards": [] } ], "packs": [ @@ -868,7 +898,7 @@ ] }, "installation": { - "visibility": "default", + "visibility": "hidden", "recommendation": "integration-managed", "primary_type": "task", "caution": "Upgrades the previous starter type while preserving independent customizations. Conflicts or other references to the previous contract block the whole upgrade.", @@ -879,6 +909,58 @@ } ] } + }, + { + "id": "tasknotes.task", + "version": "0.3.0-rc.19", + "name": "TaskNotes task type pack", + "description": "Portable tasks whose app behaviour (templates, archive moves, status cycling, time tracking and link format) lives in a TaskNotes settings record, with a reviewed, atomic upgrade from every TaskNotes starter published before.", + "digest": "sha256:ca9ac8ad5c90c7d9a19be226153a32b619b9156f83f95c38ad7ad2346e094b63", + "provision": "./packs/tasknotes.task/0.3.0-rc.19.json", + "provides": [ + { + "id": "tasknotes.task", + "version": "0.3.0-rc.6", + "digest": "sha256:c400ead6e218b715d86ad31125bb3d4b2e276817da6ba8065449fd0947b24d67" + }, + { + "id": "tasknotes.settings", + "version": "1.0.0", + "digest": "sha256:a61d55535871d27e9599cb3588148a0590d9e2198d6ee7a0bf3197350b60dc53" + }, + { + "id": "mdbase.app-settings", + "version": "1.0.0", + "digest": "sha256:4ae872a56290e2739ff876df1ca8fdac428753c854d65fd8e8e62045bd643a4e" + } + ], + "resource_count": 10, + "display": { + "name": "TaskNotes tasks", + "summary": "Manage portable Markdown tasks, assignments, dates, recurrence, reminders, and time tracking.", + "category": "work", + "audience": "general", + "icon": "square-check-big", + "badges": [ + "TaskNotes compatible" + ] + }, + "installation": { + "visibility": "default", + "recommendation": "integration-managed", + "primary_type": "task", + "caution": "Upgrades the previous starter type while preserving independent customizations. Conflicts block the whole upgrade. TaskNotes moves settings an edited type still holds into its settings record when it upgrades that type.", + "types": [ + { + "name": "task", + "label": "Task" + }, + { + "name": "tasknotes-settings", + "label": "Tasknotes settings" + } + ] + } } ] } diff --git a/dist/packs/tasknotes.task/0.3.0-rc.19.json b/dist/packs/tasknotes.task/0.3.0-rc.19.json new file mode 100644 index 0000000..0e7dcb7 --- /dev/null +++ b/dist/packs/tasknotes.task/0.3.0-rc.19.json @@ -0,0 +1,167 @@ +{ + "manifest": { + "kind": "mdbase.type-pack", + "id": "tasknotes.task", + "version": "0.3.0-rc.19", + "name": "TaskNotes task type pack", + "description": "Portable tasks whose app behaviour (templates, archive moves, status cycling, time tracking and link format) lives in a TaskNotes settings record, with a reviewed, atomic upgrade from every TaskNotes starter published before.", + "resources": [ + { + "kind": "contract", + "mode": "managed", + "source": "contracts/tasknotes.task/0.3.0-rc.5.md", + "target": "_contracts/tasknotes.task.md", + "digest": "sha256:ecadd00700e249940f4244aaa5b5985a96557d13340463ec491dfa5e89b032a4" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/tasknotes.task/0.3.0-rc.6.md", + "target": "_contracts/tasknotes.task/0.3.0-rc.6.md", + "digest": "sha256:3f4eb90782948ed68112ffcc99575911036020544cf501de3d2265b588b38456" + }, + { + "kind": "type", + "mode": "seed", + "source": "types/tasknotes-task/6.md", + "target": "_types/task.md", + "digest": "sha256:87e52c25b474a06283b29e2983ae4fc6e618fd1a4cbcc5856ff9a67328df605b", + "upgrade_from": [ + { + "digest": "sha256:b3cf8dbe8885b331c494d2eeb36abfb052890e06b757877d655c269e666487dc", + "version": 4, + "document": "---\nkind: mdbase.type\nname: task\nversion: 4\ndescription: A task managed by TaskNotes.\nmatch:\n where:\n tags:\n contains: task\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n type: object\n additionalProperties: true\n properties:\n id:\n type: string\n minLength: 1\n title:\n type: string\n minLength: 1\n status:\n enum: &a2\n - none\n - open\n - in-progress\n - done\n - cancelled\n default: open\n priority:\n enum: &a4\n - none\n - low\n - normal\n - high\n default: normal\n due: &a1\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n scheduled: *a1\n contexts:\n type: array\n items:\n type: string\n projects:\n type: array\n items:\n type: string\n assignees:\n type: array\n items:\n type: string\n minLength: 1\n pattern: \\S\n uniqueItems: true\n attachments:\n type: array\n items:\n type: string\n minLength: 1\n uniqueItems: true\n timeEstimate:\n type: integer\n minimum: 0\n completedDate:\n type: string\n format: date\n dateCreated:\n type: string\n format: date-time\n dateModified:\n type: string\n format: date-time\n recurrence:\n type: string\n recurrence_anchor:\n enum:\n - scheduled\n - completion\n default: scheduled\n occurrence_materialization:\n enum:\n - manual\n - on_completion\n - rolling\n default: manual\n occurrence_next_trigger:\n enum:\n - completion\n - completion_or_skip\n default: completion\n occurrence_template:\n type: string\n occurrence_past_horizon:\n type: string\n occurrence_future_horizon:\n type: string\n recurrence_parent:\n type: string\n occurrence_date:\n type: string\n format: date\n tags:\n type: array\n items:\n type: string\n timeEntries:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n startTime:\n type: string\n format: date-time\n endTime:\n type: string\n format: date-time\n description:\n type: string\n duration:\n type: integer\n reminders:\n type: array\n items:\n oneOf:\n - type: object\n required:\n - id\n - type\n - absoluteTime\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: absolute\n description:\n type: string\n absoluteTime:\n type: string\n format: date-time\n - type: object\n required:\n - id\n - type\n - relatedTo\n - offset\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: relative\n description:\n type: string\n relatedTo:\n enum:\n - due\n - scheduled\n offset:\n type: string\n blockedBy:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n uid:\n type: string\n reltype:\n type: string\n gap:\n type: string\n required:\n - uid\n complete_instances:\n type: array\n items:\n type: string\n format: date\n skipped_instances:\n type: array\n items:\n type: string\n format: date\n icsEventId:\n type: array\n items:\n type: string\n googleCalendarEventId:\n type: string\n googleCalendarExceptionEventId:\n type: string\n googleCalendarExceptionOriginalScheduled:\n type: string\n format: date\n googleCalendarMovedOriginalDates:\n type: array\n items:\n type: string\n format: date\n tasknotes_manual_order:\n type: string\n allOf:\n - if:\n required:\n - status\n properties:\n status:\n enum: &a3\n - done\n not:\n required:\n - recurrence\n then:\n required:\n - completedDate\n required:\n - title\n - status\n - dateCreated\ncollection:\n read_defaults:\n status: open\n priority: normal\n recurrence_anchor: scheduled\n occurrence_materialization: manual\n occurrence_next_trigger: completion\n links:\n projects[]:\n target_type: any\n validate_exists: false\n assignees[]:\n validate_exists: false\n attachments[]:\n validate_exists: false\n occurrence_template:\n target_type: any\n validate_exists: false\n recurrence_parent:\n target_type: task\n validate_exists: false\n blockedBy[].uid:\n target_type: task\n validate_exists: false\n path:\n runtime: tasknotes\n template: \"{{zettel}}\"\n folder: tasks\n generated_by: tasknotes.filename.create\n display:\n name_field: title\n unique:\n - field: id\n scope: type\nlifecycle:\n on_create:\n set:\n id:\n uuid: true\n dateCreated:\n now: true\n dateModified:\n now: true\n on_update:\n set:\n dateModified:\n now: true\nimplements:\n - contract: tasknotes.task\n version: 0.3.0-rc.5\n fields:\n id: id\n title: title\n status: status\n priority: priority\n due: due\n scheduled: scheduled\n contexts: contexts\n projects: projects\n assignees: assignees\n attachments: attachments\n timeEstimate: timeEstimate\n completedDate: completedDate\n dateCreated: dateCreated\n dateModified: dateModified\n recurrence: recurrence\n recurrenceAnchor: recurrence_anchor\n occurrenceMaterialization: occurrence_materialization\n occurrenceNextTrigger: occurrence_next_trigger\n occurrenceTemplate: occurrence_template\n occurrencePastHorizon: occurrence_past_horizon\n occurrenceFutureHorizon: occurrence_future_horizon\n recurrenceParent: recurrence_parent\n occurrenceDate: occurrence_date\n tags: tags\n timeEntries: timeEntries\n reminders: reminders\n blockedBy: blockedBy\n completeInstances: complete_instances\n skippedInstances: skipped_instances\n icsEventId: icsEventId\n googleCalendarEventId: googleCalendarEventId\n googleCalendarExceptionEventId: googleCalendarExceptionEventId\n googleCalendarExceptionOriginalScheduled: googleCalendarExceptionOriginalScheduled\n googleCalendarMovedOriginalDates: googleCalendarMovedOriginalDates\n sortOrder: tasknotes_manual_order\n binding:\n profiles:\n - core-lite\n - recurrence\n - materialized-occurrences\n capabilities:\n - dependencies\n - reminders\n - attachments\n - links\n - time-tracking\n - materialized-occurrences\n - archive\n - templating\n title:\n storage: frontmatter\n filename_format: zettel\n status:\n values: *a2\n default: open\n completed_values: *a3\n skipped_values:\n - cancelled\n default_skipped: cancelled\n definitions:\n - value: none\n label: None\n color: \"#94a3b8\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 0\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: open\n label: Open\n color: \"#64748b\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 1\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: in-progress\n label: In progress\n color: \"#3b82f6\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 2\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: done\n label: Done\n color: \"#22c55e\"\n is_completed: true\n is_skipped: false\n exclude_from_cycle: false\n order: 3\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: cancelled\n label: Cancelled\n color: \"#94a3b8\"\n is_completed: false\n is_skipped: true\n exclude_from_cycle: true\n order: 4\n auto_archive: false\n auto_archive_delay_minutes: 5\n priority:\n values: *a4\n default: normal\n definitions:\n - value: none\n label: None\n color: \"#94a3b8\"\n weight: 0\n - value: low\n label: Low\n color: \"#3b82f6\"\n weight: 1\n - value: normal\n label: Normal\n color: \"#f59e0b\"\n weight: 2\n - value: high\n label: High\n color: \"#ef4444\"\n weight: 3\n recurrence:\n syntax: tasknotes\n maintain_due_date_offset: true\n reset_body_checkboxes: false\n occurrences:\n identity_roles:\n - recurrenceParent\n - occurrenceDate\n default_materialization: manual\n default_next_trigger: completion\n past_horizon: P0D\n future_horizon: P14D\n links:\n accepted_formats:\n - wikilink\n - markdown\n write_format: wikilink\n archive:\n archived_tag: archived\n move_on_archive: false\n time_tracking:\n auto_stop_on_complete: false\n templating:\n enabled: false\n occurrence_enabled: false\nx-tasknotes-generator:\n managed_fields:\n - attachments\n - blockedBy\n - complete_instances\n - completedDate\n - contexts\n - dateCreated\n - dateModified\n - due\n - googleCalendarEventId\n - googleCalendarExceptionEventId\n - googleCalendarExceptionOriginalScheduled\n - googleCalendarMovedOriginalDates\n - icsEventId\n - id\n - occurrence_date\n - occurrence_future_horizon\n - occurrence_materialization\n - occurrence_next_trigger\n - occurrence_past_horizon\n - occurrence_template\n - priority\n - projects\n - recurrence\n - recurrence_anchor\n - recurrence_parent\n - reminders\n - scheduled\n - skipped_instances\n - status\n - tags\n - tasknotes_manual_order\n - timeEntries\n - timeEstimate\n - title\n---\n# Task\n\nTask records live under `tasks/`.\n" + }, + { + "digest": "sha256:2b6016c3543c0dfff491cc6262aed3afd4d672360484174042a261acd1d8ff5f", + "version": 4, + "document": "---\nkind: mdbase.type\nname: task\nversion: 4\ndescription: A task managed by TaskNotes.\nmatch:\n where:\n tags:\n contains: task\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n type: object\n additionalProperties: true\n properties:\n id:\n type: string\n minLength: 1\n title:\n type: string\n minLength: 1\n status:\n enum: &a2\n - none\n - open\n - in-progress\n - done\n - cancelled\n default: open\n priority:\n enum: &a4\n - none\n - low\n - normal\n - high\n default: normal\n due: &a1\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n scheduled: *a1\n contexts:\n type: array\n items:\n type: string\n projects:\n type: array\n items:\n type: string\n assignees:\n type: array\n items:\n type: string\n minLength: 1\n pattern: \\S\n uniqueItems: true\n attachments:\n type: array\n items:\n type: string\n minLength: 1\n uniqueItems: true\n timeEstimate:\n type: integer\n minimum: 0\n completedDate:\n type: string\n format: date\n dateCreated:\n type: string\n format: date-time\n dateModified:\n type: string\n format: date-time\n recurrence:\n type: string\n recurrence_anchor:\n enum:\n - scheduled\n - completion\n default: scheduled\n occurrence_materialization:\n enum:\n - manual\n - on_completion\n - rolling\n default: manual\n occurrence_next_trigger:\n enum:\n - completion\n - completion_or_skip\n default: completion\n occurrence_template:\n type: string\n occurrence_past_horizon:\n type: string\n occurrence_future_horizon:\n type: string\n recurrence_parent:\n type: string\n occurrence_date:\n type: string\n format: date\n tags:\n type: array\n items:\n type: string\n timeEntries:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n startTime:\n type: string\n format: date-time\n endTime:\n type: string\n format: date-time\n description:\n type: string\n duration:\n type: integer\n reminders:\n type: array\n items:\n oneOf:\n - type: object\n required:\n - id\n - type\n - absoluteTime\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: absolute\n description:\n type: string\n absoluteTime:\n type: string\n format: date-time\n - type: object\n required:\n - id\n - type\n - relatedTo\n - offset\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: relative\n description:\n type: string\n relatedTo:\n enum:\n - due\n - scheduled\n offset:\n type: string\n blockedBy:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n uid:\n type: string\n reltype:\n type: string\n gap:\n type: string\n required:\n - uid\n complete_instances:\n type: array\n items:\n type: string\n format: date\n skipped_instances:\n type: array\n items:\n type: string\n format: date\n icsEventId:\n type: array\n items:\n type: string\n googleCalendarEventId:\n type: string\n googleCalendarExceptionEventId:\n type: string\n googleCalendarExceptionOriginalScheduled:\n type: string\n format: date\n googleCalendarMovedOriginalDates:\n type: array\n items:\n type: string\n format: date\n tasknotes_manual_order:\n type: string\n allOf:\n - if:\n required:\n - status\n properties:\n status:\n enum: &a3\n - done\n not:\n required:\n - recurrence\n then:\n required:\n - completedDate\n required:\n - title\n - status\n - dateCreated\ncollection:\n read_defaults:\n status: open\n priority: normal\n recurrence_anchor: scheduled\n occurrence_materialization: manual\n occurrence_next_trigger: completion\n links:\n projects[]:\n target_type: any\n validate_exists: false\n assignees[]:\n validate_exists: false\n attachments[]:\n validate_exists: false\n occurrence_template:\n target_type: any\n validate_exists: false\n recurrence_parent:\n target_type: task\n validate_exists: false\n blockedBy[].uid:\n target_type: task\n validate_exists: false\n path:\n runtime: tasknotes\n template: \"{{zettel}}\"\n folder: tasks\n generated_by: tasknotes.filename.create\n display:\n name_field: title\n unique:\n - field: id\n scope: type\nlifecycle:\n on_create:\n set:\n id:\n uuid: true\n dateCreated:\n now: true\n dateModified:\n now: true\n on_update:\n set:\n dateModified:\n now: true\nimplements:\n - contract: tasknotes.task\n version: 0.3.0-rc.5\n fields:\n id: id\n title: title\n status: status\n priority: priority\n due: due\n scheduled: scheduled\n contexts: contexts\n projects: projects\n assignees: assignees\n attachments: attachments\n timeEstimate: timeEstimate\n completedDate: completedDate\n dateCreated: dateCreated\n dateModified: dateModified\n recurrence: recurrence\n recurrenceAnchor: recurrence_anchor\n occurrenceMaterialization: occurrence_materialization\n occurrenceNextTrigger: occurrence_next_trigger\n occurrenceTemplate: occurrence_template\n occurrencePastHorizon: occurrence_past_horizon\n occurrenceFutureHorizon: occurrence_future_horizon\n recurrenceParent: recurrence_parent\n occurrenceDate: occurrence_date\n tags: tags\n timeEntries: timeEntries\n reminders: reminders\n blockedBy: blockedBy\n completeInstances: complete_instances\n skippedInstances: skipped_instances\n icsEventId: icsEventId\n googleCalendarEventId: googleCalendarEventId\n googleCalendarExceptionEventId: googleCalendarExceptionEventId\n googleCalendarExceptionOriginalScheduled: googleCalendarExceptionOriginalScheduled\n googleCalendarMovedOriginalDates: googleCalendarMovedOriginalDates\n sortOrder: tasknotes_manual_order\n binding:\n profiles:\n - core-lite\n - recurrence\n - materialized-occurrences\n capabilities:\n - dependencies\n - reminders\n - attachments\n - links\n - time-tracking\n - materialized-occurrences\n - archive\n - templating\n title:\n storage: frontmatter\n filename_format: zettel\n status:\n values: *a2\n default: open\n completed_values: *a3\n skipped_values:\n - cancelled\n default_skipped: cancelled\n definitions:\n - value: none\n label: None\n color: \"#94a3b8\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 0\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: open\n label: Open\n color: \"#64748b\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 1\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: in-progress\n label: In progress\n color: \"#3b82f6\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 2\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: done\n label: Done\n color: \"#22c55e\"\n is_completed: true\n is_skipped: false\n exclude_from_cycle: false\n order: 3\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: cancelled\n label: Cancelled\n color: \"#94a3b8\"\n is_completed: false\n is_skipped: true\n exclude_from_cycle: true\n order: 4\n auto_archive: false\n auto_archive_delay_minutes: 5\n priority:\n values: *a4\n default: normal\n definitions:\n - value: none\n label: None\n color: \"#94a3b8\"\n weight: 0\n - value: low\n label: Low\n color: \"#3b82f6\"\n weight: 1\n - value: normal\n label: Normal\n color: \"#f59e0b\"\n weight: 2\n - value: high\n label: High\n color: \"#ef4444\"\n weight: 3\n recurrence:\n syntax: tasknotes\n maintain_due_date_offset: true\n reset_body_checkboxes: false\n occurrences:\n identity_roles:\n - recurrenceParent\n - occurrenceDate\n default_materialization: manual\n default_next_trigger: completion\n past_horizon: P0D\n future_horizon: P14D\n links:\n accepted_formats:\n - wikilink\n - markdown\n write_format: wikilink\n archive:\n archived_tag: archived\n move_on_archive: false\n time_tracking:\n auto_stop_on_complete: false\n templating:\n enabled: false\n occurrence_enabled: false\nx-tasknotes-generator:\n managed_fields:\n - assignees\n - attachments\n - blockedBy\n - complete_instances\n - completedDate\n - contexts\n - dateCreated\n - dateModified\n - due\n - googleCalendarEventId\n - googleCalendarExceptionEventId\n - googleCalendarExceptionOriginalScheduled\n - googleCalendarMovedOriginalDates\n - icsEventId\n - id\n - occurrence_date\n - occurrence_future_horizon\n - occurrence_materialization\n - occurrence_next_trigger\n - occurrence_past_horizon\n - occurrence_template\n - priority\n - projects\n - recurrence\n - recurrence_anchor\n - recurrence_parent\n - reminders\n - scheduled\n - skipped_instances\n - status\n - tags\n - tasknotes_manual_order\n - timeEntries\n - timeEstimate\n - title\n---\n# Task\n\nTask records live under `tasks/`.\n" + }, + { + "digest": "sha256:02d1a2a04f26937dd7eec3cde3070dd770c73625e06f386d6214044d176788dd", + "version": 3, + "document": "---\nkind: mdbase.type\nname: task\nversion: 3\ndescription: A task managed by TaskNotes.\nmatch:\n where:\n tags:\n contains: task\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n type: object\n additionalProperties: true\n properties:\n id:\n type: string\n minLength: 1\n title:\n type: string\n minLength: 1\n status:\n enum: &a1\n - none\n - open\n - in-progress\n - done\n default: open\n priority:\n enum: &a3\n - none\n - low\n - normal\n - high\n default: normal\n due:\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n scheduled:\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n contexts:\n type: array\n items:\n type: string\n projects:\n type: array\n items:\n type: string\n assignees:\n type: array\n items:\n type: string\n minLength: 1\n pattern: \\S\n uniqueItems: true\n attachments:\n type: array\n items:\n type: string\n minLength: 1\n uniqueItems: true\n timeEstimate:\n type: integer\n minimum: 0\n completedDate:\n type: string\n format: date\n dateCreated:\n type: string\n format: date-time\n dateModified:\n type: string\n format: date-time\n recurrence:\n type: string\n recurrence_anchor:\n enum:\n - scheduled\n - completion\n default: scheduled\n occurrence_materialization:\n enum:\n - manual\n - on_completion\n - rolling\n default: manual\n occurrence_next_trigger:\n enum:\n - completion\n - completion_or_skip\n default: completion\n occurrence_template:\n type: string\n occurrence_past_horizon:\n type: string\n occurrence_future_horizon:\n type: string\n recurrence_parent:\n type: string\n occurrence_date:\n type: string\n format: date\n tags:\n type: array\n items:\n type: string\n timeEntries:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n startTime:\n type: string\n format: date-time\n endTime:\n type: string\n format: date-time\n description:\n type: string\n duration:\n type: integer\n reminders:\n type: array\n items:\n oneOf:\n - type: object\n required:\n - id\n - type\n - absoluteTime\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: absolute\n description:\n type: string\n absoluteTime:\n type: string\n format: date-time\n - type: object\n required:\n - id\n - type\n - relatedTo\n - offset\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: relative\n description:\n type: string\n relatedTo:\n enum:\n - due\n - scheduled\n offset:\n type: string\n blockedBy:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n uid:\n type: string\n reltype:\n type: string\n gap:\n type: string\n required:\n - uid\n complete_instances:\n type: array\n items:\n type: string\n format: date\n skipped_instances:\n type: array\n items:\n type: string\n format: date\n icsEventId:\n type: array\n items:\n type: string\n googleCalendarEventId:\n type: string\n googleCalendarExceptionEventId:\n type: string\n googleCalendarExceptionOriginalScheduled:\n type: string\n format: date\n googleCalendarMovedOriginalDates:\n type: array\n items:\n type: string\n format: date\n tasknotes_manual_order:\n type: string\n allOf:\n - if:\n required:\n - status\n properties:\n status:\n enum: &a2\n - done\n not:\n required:\n - recurrence\n then:\n required:\n - completedDate\n required:\n - title\n - status\n - dateCreated\ncollection:\n read_defaults:\n status: open\n priority: normal\n recurrence_anchor: scheduled\n occurrence_materialization: manual\n occurrence_next_trigger: completion\n links:\n projects[]:\n target_type: any\n validate_exists: false\n assignees[]:\n validate_exists: false\n attachments[]:\n validate_exists: false\n occurrence_template:\n target_type: any\n validate_exists: false\n recurrence_parent:\n target_type: task\n validate_exists: false\n blockedBy[].uid:\n target_type: task\n validate_exists: false\n path:\n runtime: tasknotes\n template: \"{{zettel}}\"\n folder: tasks\n generated_by: tasknotes.filename.create\n display:\n name_field: title\n unique:\n - field: id\n scope: type\nlifecycle:\n on_create:\n set:\n id:\n uuid: true\n dateCreated:\n now: true\n dateModified:\n now: true\n on_update:\n set:\n dateModified:\n now: true\nimplements:\n - contract: tasknotes.task\n version: 0.3.0-rc.5\n fields:\n id: id\n title: title\n status: status\n priority: priority\n due: due\n scheduled: scheduled\n contexts: contexts\n projects: projects\n assignees: assignees\n attachments: attachments\n timeEstimate: timeEstimate\n completedDate: completedDate\n dateCreated: dateCreated\n dateModified: dateModified\n recurrence: recurrence\n recurrenceAnchor: recurrence_anchor\n occurrenceMaterialization: occurrence_materialization\n occurrenceNextTrigger: occurrence_next_trigger\n occurrenceTemplate: occurrence_template\n occurrencePastHorizon: occurrence_past_horizon\n occurrenceFutureHorizon: occurrence_future_horizon\n recurrenceParent: recurrence_parent\n occurrenceDate: occurrence_date\n tags: tags\n timeEntries: timeEntries\n reminders: reminders\n blockedBy: blockedBy\n completeInstances: complete_instances\n skippedInstances: skipped_instances\n icsEventId: icsEventId\n googleCalendarEventId: googleCalendarEventId\n googleCalendarExceptionEventId: googleCalendarExceptionEventId\n googleCalendarExceptionOriginalScheduled: googleCalendarExceptionOriginalScheduled\n googleCalendarMovedOriginalDates: googleCalendarMovedOriginalDates\n sortOrder: tasknotes_manual_order\n binding:\n profiles:\n - core-lite\n - recurrence\n - templating\n - materialized-occurrences\n - extended\n capabilities:\n - dependencies\n - reminders\n - attachments\n - links\n - time-tracking\n - materialized-occurrences\n - archive\n - templating\n title:\n storage: frontmatter\n filename_format: zettel\n status:\n values: *a1\n default: open\n completed_values: *a2\n skipped_values: []\n definitions:\n - value: none\n label: None\n color: \"#cccccc\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 0\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: open\n label: Open\n color: \"#808080\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 1\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: in-progress\n label: In progress\n color: \"#0066cc\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 2\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: done\n label: Done\n color: \"#00aa00\"\n is_completed: true\n is_skipped: false\n exclude_from_cycle: false\n order: 3\n auto_archive: false\n auto_archive_delay_minutes: 5\n priority:\n values: *a3\n default: normal\n definitions:\n - value: none\n label: None\n color: \"#cccccc\"\n weight: 0\n - value: low\n label: Low\n color: \"#00aa00\"\n weight: 1\n - value: normal\n label: Normal\n color: \"#ffaa00\"\n weight: 2\n - value: high\n label: High\n color: \"#ff0000\"\n weight: 3\n recurrence:\n syntax: tasknotes\n maintain_due_date_offset: true\n reset_body_checkboxes: false\n occurrences:\n identity_roles:\n - recurrenceParent\n - occurrenceDate\n default_materialization: manual\n default_next_trigger: completion\n past_horizon: P0D\n future_horizon: P14D\n links:\n accepted_formats:\n - wikilink\n - markdown\n write_format: wikilink\n archive:\n archived_tag: archived\n move_on_archive: false\n time_tracking:\n auto_stop_on_complete: false\n templating:\n enabled: false\n occurrence_enabled: false\nx-tasknotes-generator:\n managed_fields:\n - assignees\n - attachments\n - blockedBy\n - complete_instances\n - completedDate\n - contexts\n - dateCreated\n - dateModified\n - due\n - googleCalendarEventId\n - googleCalendarExceptionEventId\n - googleCalendarExceptionOriginalScheduled\n - googleCalendarMovedOriginalDates\n - icsEventId\n - id\n - occurrence_date\n - occurrence_future_horizon\n - occurrence_materialization\n - occurrence_next_trigger\n - occurrence_past_horizon\n - occurrence_template\n - priority\n - projects\n - recurrence\n - recurrence_anchor\n - recurrence_parent\n - reminders\n - scheduled\n - skipped_instances\n - status\n - tags\n - tasknotes_manual_order\n - timeEntries\n - timeEstimate\n - title\n---\n\n# Task\n\nThis type definition implements the TaskNotes contract for this mdbase collection.\nIts JSON Schema describes persisted task frontmatter; collection and lifecycle\nmetadata describe generic mdbase behavior; `implements` maps the portable\nTaskNotes task view and supplies TaskNotes behavior.\n\nChanges made here are loaded by TaskNotes. Portable changes made in TaskNotes\nsettings are written back while unknown extensions are preserved.\n" + }, + { + "digest": "sha256:ade71117bd31e571f403511c48d432bab7a05dfd25e730ca2931f3afda7f7cd5", + "version": 2, + "document": "---\nkind: mdbase.type\nname: task\nversion: 2\ndescription: A task managed by TaskNotes.\nmatch:\n where:\n tags:\n contains: task\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n type: object\n additionalProperties: true\n properties:\n id:\n type: string\n minLength: 1\n title:\n type: string\n minLength: 1\n status:\n enum: &a1\n - none\n - open\n - in-progress\n - done\n default: open\n priority:\n enum: &a3\n - none\n - low\n - normal\n - high\n default: normal\n due:\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n scheduled:\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n contexts:\n type: array\n items:\n type: string\n projects:\n type: array\n items:\n type: string\n assignees:\n type: array\n items:\n type: string\n minLength: 1\n pattern: \\S\n uniqueItems: true\n attachments:\n type: array\n items:\n type: string\n minLength: 1\n uniqueItems: true\n timeEstimate:\n type: integer\n minimum: 0\n completedDate:\n type: string\n format: date\n dateCreated:\n type: string\n format: date-time\n dateModified:\n type: string\n format: date-time\n recurrence:\n type: string\n recurrence_anchor:\n enum:\n - scheduled\n - completion\n default: scheduled\n occurrence_materialization:\n enum:\n - manual\n - on_completion\n - rolling\n default: manual\n occurrence_next_trigger:\n enum:\n - completion\n - completion_or_skip\n default: completion\n occurrence_template:\n type: string\n occurrence_past_horizon:\n type: string\n occurrence_future_horizon:\n type: string\n recurrence_parent:\n type: string\n occurrence_date:\n type: string\n format: date\n tags:\n type: array\n items:\n type: string\n timeEntries:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n startTime:\n type: string\n format: date-time\n endTime:\n type: string\n format: date-time\n description:\n type: string\n duration:\n type: integer\n reminders:\n type: array\n items:\n oneOf:\n - type: object\n required:\n - id\n - type\n - absoluteTime\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: absolute\n description:\n type: string\n absoluteTime:\n type: string\n format: date-time\n - type: object\n required:\n - id\n - type\n - relatedTo\n - offset\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: relative\n description:\n type: string\n relatedTo:\n enum:\n - due\n - scheduled\n offset:\n type: string\n blockedBy:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n uid:\n type: string\n reltype:\n type: string\n gap:\n type: string\n required:\n - uid\n complete_instances:\n type: array\n items:\n type: string\n format: date\n skipped_instances:\n type: array\n items:\n type: string\n format: date\n icsEventId:\n type: array\n items:\n type: string\n googleCalendarEventId:\n type: string\n googleCalendarExceptionEventId:\n type: string\n googleCalendarExceptionOriginalScheduled:\n type: string\n format: date\n googleCalendarMovedOriginalDates:\n type: array\n items:\n type: string\n format: date\n tasknotes_manual_order:\n type: string\n allOf:\n - if:\n required:\n - status\n properties:\n status:\n enum: &a2\n - done\n not:\n required:\n - recurrence\n then:\n required:\n - completedDate\n required:\n - title\n - status\n - dateCreated\ncollection:\n read_defaults:\n status: open\n priority: normal\n recurrence_anchor: scheduled\n occurrence_materialization: manual\n occurrence_next_trigger: completion\n links:\n projects[]:\n target_type: any\n validate_exists: false\n attachments[]:\n validate_exists: false\n occurrence_template:\n target_type: any\n validate_exists: false\n recurrence_parent:\n target_type: task\n validate_exists: false\n blockedBy[].uid:\n target_type: task\n validate_exists: false\n path:\n runtime: tasknotes\n template: \"{{zettel}}\"\n folder: tasks\n generated_by: tasknotes.filename.create\n display:\n name_field: title\n unique:\n - field: id\n scope: type\nlifecycle:\n on_create:\n set:\n id:\n uuid: true\n dateCreated:\n now: true\n dateModified:\n now: true\n on_update:\n set:\n dateModified:\n now: true\nimplements:\n - contract: tasknotes.task\n version: 0.3.0-rc.4\n fields:\n id: id\n title: title\n status: status\n priority: priority\n due: due\n scheduled: scheduled\n contexts: contexts\n projects: projects\n assignees: assignees\n attachments: attachments\n timeEstimate: timeEstimate\n completedDate: completedDate\n dateCreated: dateCreated\n dateModified: dateModified\n recurrence: recurrence\n recurrenceAnchor: recurrence_anchor\n occurrenceMaterialization: occurrence_materialization\n occurrenceNextTrigger: occurrence_next_trigger\n occurrenceTemplate: occurrence_template\n occurrencePastHorizon: occurrence_past_horizon\n occurrenceFutureHorizon: occurrence_future_horizon\n recurrenceParent: recurrence_parent\n occurrenceDate: occurrence_date\n tags: tags\n timeEntries: timeEntries\n reminders: reminders\n blockedBy: blockedBy\n completeInstances: complete_instances\n skippedInstances: skipped_instances\n icsEventId: icsEventId\n googleCalendarEventId: googleCalendarEventId\n googleCalendarExceptionEventId: googleCalendarExceptionEventId\n googleCalendarExceptionOriginalScheduled: googleCalendarExceptionOriginalScheduled\n googleCalendarMovedOriginalDates: googleCalendarMovedOriginalDates\n sortOrder: tasknotes_manual_order\n binding:\n profiles:\n - core-lite\n - recurrence\n - templating\n - materialized-occurrences\n - extended\n capabilities:\n - dependencies\n - reminders\n - attachments\n - links\n - time-tracking\n - materialized-occurrences\n - archive\n - templating\n title:\n storage: frontmatter\n filename_format: zettel\n status:\n values: *a1\n default: open\n completed_values: *a2\n skipped_values: []\n definitions:\n - value: none\n label: None\n color: \"#cccccc\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 0\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: open\n label: Open\n color: \"#808080\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 1\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: in-progress\n label: In progress\n color: \"#0066cc\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 2\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: done\n label: Done\n color: \"#00aa00\"\n is_completed: true\n is_skipped: false\n exclude_from_cycle: false\n order: 3\n auto_archive: false\n auto_archive_delay_minutes: 5\n priority:\n values: *a3\n default: normal\n definitions:\n - value: none\n label: None\n color: \"#cccccc\"\n weight: 0\n - value: low\n label: Low\n color: \"#00aa00\"\n weight: 1\n - value: normal\n label: Normal\n color: \"#ffaa00\"\n weight: 2\n - value: high\n label: High\n color: \"#ff0000\"\n weight: 3\n recurrence:\n syntax: tasknotes\n maintain_due_date_offset: true\n reset_body_checkboxes: false\n occurrences:\n identity_roles:\n - recurrenceParent\n - occurrenceDate\n default_materialization: manual\n default_next_trigger: completion\n past_horizon: P0D\n future_horizon: P14D\n links:\n accepted_formats:\n - wikilink\n - markdown\n write_format: wikilink\n archive:\n archived_tag: archived\n move_on_archive: false\n time_tracking:\n auto_stop_on_complete: false\n templating:\n enabled: false\n occurrence_enabled: false\nx-tasknotes-generator:\n managed_fields:\n - assignees\n - attachments\n - blockedBy\n - complete_instances\n - completedDate\n - contexts\n - dateCreated\n - dateModified\n - due\n - googleCalendarEventId\n - googleCalendarExceptionEventId\n - googleCalendarExceptionOriginalScheduled\n - googleCalendarMovedOriginalDates\n - icsEventId\n - id\n - occurrence_date\n - occurrence_future_horizon\n - occurrence_materialization\n - occurrence_next_trigger\n - occurrence_past_horizon\n - occurrence_template\n - priority\n - projects\n - recurrence\n - recurrence_anchor\n - recurrence_parent\n - reminders\n - scheduled\n - skipped_instances\n - status\n - tags\n - tasknotes_manual_order\n - timeEntries\n - timeEstimate\n - title\n---\n\n# Task\n\nThis type definition implements the TaskNotes contract for this mdbase collection.\nIts JSON Schema describes persisted task frontmatter; collection and lifecycle\nmetadata describe generic mdbase behavior; `implements` maps the portable\nTaskNotes task view and supplies TaskNotes behavior.\n\nChanges made here are loaded by TaskNotes. Portable changes made in TaskNotes\nsettings are written back while unknown extensions are preserved.\n" + }, + { + "digest": "sha256:b7f8af7b18d77859dab1f1532c1b55c08c7c39879f55e4ef2a94cb7d2d2284eb", + "version": 1, + "document": "---\nkind: mdbase.type\nname: task\nversion: 1\ndescription: A task managed by TaskNotes.\nmatch:\n where:\n tags:\n contains: task\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n type: object\n additionalProperties: true\n properties:\n id:\n type: string\n minLength: 1\n title:\n type: string\n minLength: 1\n status:\n enum: &a2\n - none\n - open\n - in-progress\n - done\n - cancelled\n default: open\n priority:\n enum: &a4\n - none\n - low\n - normal\n - high\n default: normal\n due: &a1\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n scheduled: *a1\n contexts:\n type: array\n items:\n type: string\n projects:\n type: array\n items:\n type: string\n attachments:\n type: array\n items:\n type: string\n minLength: 1\n uniqueItems: true\n timeEstimate:\n type: integer\n minimum: 0\n completedDate:\n type: string\n format: date\n dateCreated:\n type: string\n format: date-time\n dateModified:\n type: string\n format: date-time\n recurrence:\n type: string\n recurrence_anchor:\n enum:\n - scheduled\n - completion\n default: scheduled\n occurrence_materialization:\n enum:\n - manual\n - on_completion\n - rolling\n default: manual\n occurrence_next_trigger:\n enum:\n - completion\n - completion_or_skip\n default: completion\n occurrence_template:\n type: string\n occurrence_past_horizon:\n type: string\n occurrence_future_horizon:\n type: string\n recurrence_parent:\n type: string\n occurrence_date:\n type: string\n format: date\n tags:\n type: array\n items:\n type: string\n timeEntries:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n startTime:\n type: string\n format: date-time\n endTime:\n type: string\n format: date-time\n description:\n type: string\n duration:\n type: integer\n reminders:\n type: array\n items:\n oneOf:\n - type: object\n required:\n - id\n - type\n - absoluteTime\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: absolute\n description:\n type: string\n absoluteTime:\n type: string\n format: date-time\n - type: object\n required:\n - id\n - type\n - relatedTo\n - offset\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: relative\n description:\n type: string\n relatedTo:\n enum:\n - due\n - scheduled\n offset:\n type: string\n blockedBy:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n uid:\n type: string\n reltype:\n type: string\n gap:\n type: string\n required:\n - uid\n complete_instances:\n type: array\n items:\n type: string\n format: date\n skipped_instances:\n type: array\n items:\n type: string\n format: date\n icsEventId:\n type: array\n items:\n type: string\n googleCalendarEventId:\n type: string\n googleCalendarExceptionEventId:\n type: string\n googleCalendarExceptionOriginalScheduled:\n type: string\n format: date\n googleCalendarMovedOriginalDates:\n type: array\n items:\n type: string\n format: date\n tasknotes_manual_order:\n type: string\n allOf:\n - if:\n required:\n - status\n properties:\n status:\n enum: &a3\n - done\n not:\n required:\n - recurrence\n then:\n required:\n - completedDate\n required:\n - title\n - status\n - dateCreated\ncollection:\n read_defaults:\n status: open\n priority: normal\n recurrence_anchor: scheduled\n occurrence_materialization: manual\n occurrence_next_trigger: completion\n links:\n projects[]:\n target_type: any\n validate_exists: false\n attachments[]:\n validate_exists: false\n occurrence_template:\n target_type: any\n validate_exists: false\n recurrence_parent:\n target_type: task\n validate_exists: false\n blockedBy[].uid:\n target_type: task\n validate_exists: false\n path:\n runtime: tasknotes\n template: \"{{zettel}}\"\n folder: tasks\n generated_by: tasknotes.filename.create\n display:\n name_field: title\n unique:\n - field: id\n scope: type\nlifecycle:\n on_create:\n set:\n id:\n uuid: true\n dateCreated:\n now: true\n dateModified:\n now: true\n on_update:\n set:\n dateModified:\n now: true\nimplements:\n - contract: tasknotes.task\n version: 0.3.0-rc.3\n fields:\n id: id\n title: title\n status: status\n priority: priority\n due: due\n scheduled: scheduled\n contexts: contexts\n projects: projects\n attachments: attachments\n timeEstimate: timeEstimate\n completedDate: completedDate\n dateCreated: dateCreated\n dateModified: dateModified\n recurrence: recurrence\n recurrenceAnchor: recurrence_anchor\n occurrenceMaterialization: occurrence_materialization\n occurrenceNextTrigger: occurrence_next_trigger\n occurrenceTemplate: occurrence_template\n occurrencePastHorizon: occurrence_past_horizon\n occurrenceFutureHorizon: occurrence_future_horizon\n recurrenceParent: recurrence_parent\n occurrenceDate: occurrence_date\n tags: tags\n timeEntries: timeEntries\n reminders: reminders\n blockedBy: blockedBy\n completeInstances: complete_instances\n skippedInstances: skipped_instances\n icsEventId: icsEventId\n googleCalendarEventId: googleCalendarEventId\n googleCalendarExceptionEventId: googleCalendarExceptionEventId\n googleCalendarExceptionOriginalScheduled: googleCalendarExceptionOriginalScheduled\n googleCalendarMovedOriginalDates: googleCalendarMovedOriginalDates\n sortOrder: tasknotes_manual_order\n binding:\n profiles:\n - core-lite\n - recurrence\n - materialized-occurrences\n capabilities:\n - dependencies\n - reminders\n - attachments\n - links\n - time-tracking\n - materialized-occurrences\n - archive\n - templating\n title:\n storage: frontmatter\n filename_format: zettel\n status:\n values: *a2\n default: open\n completed_values: *a3\n skipped_values:\n - cancelled\n default_skipped: cancelled\n definitions:\n - value: none\n label: None\n color: \"#94a3b8\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 0\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: open\n label: Open\n color: \"#64748b\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 1\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: in-progress\n label: In progress\n color: \"#3b82f6\"\n is_completed: false\n is_skipped: false\n exclude_from_cycle: false\n order: 2\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: done\n label: Done\n color: \"#22c55e\"\n is_completed: true\n is_skipped: false\n exclude_from_cycle: false\n order: 3\n auto_archive: false\n auto_archive_delay_minutes: 5\n - value: cancelled\n label: Cancelled\n color: \"#94a3b8\"\n is_completed: false\n is_skipped: true\n exclude_from_cycle: true\n order: 4\n auto_archive: false\n auto_archive_delay_minutes: 5\n priority:\n values: *a4\n default: normal\n definitions:\n - value: none\n label: None\n color: \"#94a3b8\"\n weight: 0\n - value: low\n label: Low\n color: \"#3b82f6\"\n weight: 1\n - value: normal\n label: Normal\n color: \"#f59e0b\"\n weight: 2\n - value: high\n label: High\n color: \"#ef4444\"\n weight: 3\n recurrence:\n syntax: tasknotes\n maintain_due_date_offset: true\n reset_body_checkboxes: false\n occurrences:\n identity_roles:\n - recurrenceParent\n - occurrenceDate\n default_materialization: manual\n default_next_trigger: completion\n past_horizon: P0D\n future_horizon: P14D\n links:\n accepted_formats:\n - wikilink\n - markdown\n write_format: wikilink\n archive:\n archived_tag: archived\n move_on_archive: false\n time_tracking:\n auto_stop_on_complete: false\n templating:\n enabled: false\n occurrence_enabled: false\nx-tasknotes-generator:\n managed_fields:\n - attachments\n - blockedBy\n - complete_instances\n - completedDate\n - contexts\n - dateCreated\n - dateModified\n - due\n - googleCalendarEventId\n - googleCalendarExceptionEventId\n - googleCalendarExceptionOriginalScheduled\n - googleCalendarMovedOriginalDates\n - icsEventId\n - id\n - occurrence_date\n - occurrence_future_horizon\n - occurrence_materialization\n - occurrence_next_trigger\n - occurrence_past_horizon\n - occurrence_template\n - priority\n - projects\n - recurrence\n - recurrence_anchor\n - recurrence_parent\n - reminders\n - scheduled\n - skipped_instances\n - status\n - tags\n - tasknotes_manual_order\n - timeEntries\n - timeEstimate\n - title\n---\n# Task\n\nTask records live under `tasks/`.\n" + } + ] + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/tasknotes.task/0.3.0-rc.6.schema.json", + "target": "_schemas/tasknotes/tasknotes-task.schema.json", + "digest": "sha256:ac78a55f46669d6e8bd08d608b7c25338fec8ba7606dbf54ebd6b8d4e66b7035" + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json", + "target": "_schemas/tasknotes/tasknotes-task-binding.schema.json", + "digest": "sha256:4f8f3288f593ce06a04525697308173147ff957e7066f83d9a922468d06be659" + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.app-settings/1.0.0.schema.json", + "target": "schemas/mdbase.app-settings/1.0.0.schema.json", + "digest": "sha256:f37ed43b57fe86465b5bb67216da71d6e351bc1b85bf55a20f95edf886f0749e" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.app-settings/1.0.0.md", + "target": "_contracts/mdbase.app-settings/1.0.0.md", + "digest": "sha256:9028d8ccd99cfbb4034399777376315486eb8e699aea7757a6b193743f1084c8" + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/tasknotes.settings/1.0.0.schema.json", + "target": "schemas/tasknotes.settings/1.0.0.schema.json", + "digest": "sha256:3a4fc207e14ab1579ca478ce84b25cb8dd85b804b3aa79d01eda08e4554dfbb1" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/tasknotes.settings/1.0.0.md", + "target": "_contracts/tasknotes.settings/1.0.0.md", + "digest": "sha256:e8c25653ef37c032fb4cb1f1c3f7c618092a09c4911a41aba42c0476796fe0d1" + }, + { + "kind": "type", + "mode": "seed", + "source": "types/tasknotes-settings/1.md", + "target": "_types/tasknotes-settings.md", + "digest": "sha256:22ec312c75df356b0b26ba3c46961212efe2803a5d57071fa5753bab7638c2cc" + } + ] + }, + "resources": [ + { + "source": "contracts/tasknotes.task/0.3.0-rc.5.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: tasknotes.task\nversion: 0.3.0-rc.5\nname: TaskNotes task\ndescription: Portable task data and behavior defined by tasknotes-spec 0.3.0-rc.5.\nrecord_schema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n $id: https://tasknotes.dev/schemas/tasknotes-task.schema.json\n title: TaskNotes portable task view\n description: The storage-neutral record view exposed by the tasknotes.task 0.3.0-rc.5 record contract.\n type: object\n required:\n - status\n - dateCreated\n additionalProperties: false\n properties:\n id:\n type: string\n minLength: 1\n title:\n type: string\n minLength: 1\n status:\n type: string\n minLength: 1\n priority:\n type: string\n minLength: 1\n due:\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n scheduled:\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n contexts:\n type: array\n items:\n type: string\n projects:\n type: array\n items:\n type: string\n assignees:\n type: array\n uniqueItems: true\n items:\n type: string\n minLength: 1\n pattern: \\S\n description: Links to records implementing mdbase.person, such as [[Alex Rivera]]. Implementing types declare this field in collection.links. These references never grant collection access.\n attachments:\n type: array\n uniqueItems: true\n items:\n type: string\n minLength: 1\n timeEstimate:\n type: integer\n minimum: 0\n completedDate:\n type: string\n format: date\n dateCreated:\n type: string\n format: date-time\n dateModified:\n type: string\n format: date-time\n recurrence:\n type: string\n recurrenceAnchor:\n enum:\n - scheduled\n - completion\n recurrenceParent:\n type: string\n occurrenceDate:\n type: string\n format: date\n occurrenceMaterialization:\n enum:\n - manual\n - on_completion\n - rolling\n occurrenceNextTrigger:\n enum:\n - completion\n - completion_or_skip\n occurrenceTemplate:\n type: string\n occurrencePastHorizon:\n type: string\n occurrenceFutureHorizon:\n type: string\n tags:\n type: array\n items:\n type: string\n timeEntries:\n type: array\n items:\n type: object\n reminders:\n type: array\n items:\n type: object\n blockedBy:\n type: array\n items:\n type: object\n completeInstances:\n type: array\n items:\n type: string\n format: date\n skippedInstances:\n type: array\n items:\n type: string\n format: date\n icsEventId:\n type: array\n items:\n type: string\n googleCalendarEventId:\n type: string\n googleCalendarExceptionEventId:\n type: string\n googleCalendarExceptionOriginalScheduled:\n type: string\n format: date\n googleCalendarMovedOriginalDates:\n type: array\n items:\n type: string\n format: date\n sortOrder:\n type: string\nbinding_schema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n $id: https://tasknotes.dev/schemas/tasknotes-task-binding.schema.json\n title: TaskNotes task data-contract binding\n description: Semantic configuration supplied by an mdbase type that implements tasknotes.task 0.3.0-rc.3.\n type: object\n required:\n - profiles\n - capabilities\n - title\n - status\n - priority\n - recurrence\n - occurrences\n - links\n - archive\n - time_tracking\n - templating\n properties:\n profiles:\n type: array\n minItems: 1\n uniqueItems: true\n items:\n enum:\n - core-lite\n - recurrence\n - templating\n - materialized-occurrences\n - extended\n capabilities:\n type: array\n uniqueItems: true\n items:\n enum:\n - dependencies\n - reminders\n - attachments\n - links\n - time-tracking\n - materialized-occurrences\n - rename\n - archive\n - batch\n - concurrency\n - dry-run\n - migration\n - templating\n title:\n $ref: \"#/$defs/titlePolicy\"\n status:\n $ref: \"#/$defs/statusPolicy\"\n priority:\n $ref: \"#/$defs/priorityPolicy\"\n recurrence:\n $ref: \"#/$defs/recurrencePolicy\"\n occurrences:\n $ref: \"#/$defs/occurrencePolicy\"\n links:\n $ref: \"#/$defs/linkPolicy\"\n archive:\n $ref: \"#/$defs/archivePolicy\"\n time_tracking:\n $ref: \"#/$defs/timeTrackingPolicy\"\n templating:\n $ref: \"#/$defs/templatingPolicy\"\n nlp:\n $ref: \"#/$defs/nlpPolicy\"\n additionalProperties: false\n $defs:\n nonEmptyString:\n type: string\n minLength: 1\n stringSet:\n type: array\n uniqueItems: true\n items:\n $ref: \"#/$defs/nonEmptyString\"\n titlePolicy:\n type: object\n required:\n - storage\n properties:\n storage:\n enum:\n - filename\n - frontmatter\n filename_format:\n enum:\n - title\n - zettel\n - timestamp\n - uuid\n - custom\n custom_filename_template:\n $ref: \"#/$defs/nonEmptyString\"\n allOf:\n - if:\n properties:\n filename_format:\n const: custom\n required:\n - filename_format\n then:\n properties:\n custom_filename_template:\n $ref: \"#/$defs/nonEmptyString\"\n required:\n - custom_filename_template\n additionalProperties: true\n statusDefinition:\n type: object\n required:\n - value\n - label\n - color\n - is_completed\n - is_skipped\n - exclude_from_cycle\n - order\n - auto_archive\n - auto_archive_delay_minutes\n properties:\n value:\n $ref: \"#/$defs/nonEmptyString\"\n label:\n type: string\n color:\n type: string\n icon:\n $ref: \"#/$defs/nonEmptyString\"\n is_completed:\n type: boolean\n is_skipped:\n type: boolean\n exclude_from_cycle:\n type: boolean\n next_status:\n $ref: \"#/$defs/nonEmptyString\"\n order:\n type: number\n auto_archive:\n type: boolean\n auto_archive_delay_minutes:\n type: number\n minimum: 0\n additionalProperties: true\n statusPolicy:\n type: object\n required:\n - values\n - default\n - completed_values\n - definitions\n properties:\n values:\n $ref: \"#/$defs/stringSet\"\n default:\n $ref: \"#/$defs/nonEmptyString\"\n completed_values:\n $ref: \"#/$defs/stringSet\"\n skipped_values:\n $ref: \"#/$defs/stringSet\"\n default_skipped:\n $ref: \"#/$defs/nonEmptyString\"\n definitions:\n type: array\n items:\n $ref: \"#/$defs/statusDefinition\"\n additionalProperties: false\n priorityDefinition:\n type: object\n required:\n - value\n - label\n - color\n - weight\n properties:\n value:\n $ref: \"#/$defs/nonEmptyString\"\n label:\n type: string\n color:\n type: string\n icon:\n $ref: \"#/$defs/nonEmptyString\"\n weight:\n type: number\n additionalProperties: true\n priorityPolicy:\n type: object\n required:\n - values\n - default\n - definitions\n properties:\n values:\n $ref: \"#/$defs/stringSet\"\n default:\n $ref: \"#/$defs/nonEmptyString\"\n definitions:\n type: array\n items:\n $ref: \"#/$defs/priorityDefinition\"\n additionalProperties: false\n recurrencePolicy:\n type: object\n required:\n - syntax\n - maintain_due_date_offset\n - reset_body_checkboxes\n properties:\n syntax:\n const: tasknotes\n maintain_due_date_offset:\n type: boolean\n reset_body_checkboxes:\n type: boolean\n additionalProperties: false\n occurrencePolicy:\n type: object\n required:\n - identity_roles\n - default_materialization\n - default_next_trigger\n properties:\n identity_roles:\n const:\n - recurrenceParent\n - occurrenceDate\n default_materialization:\n enum:\n - manual\n - on_completion\n - rolling\n default_next_trigger:\n enum:\n - completion\n - completion_or_skip\n past_horizon:\n $ref: \"#/$defs/nonEmptyString\"\n future_horizon:\n $ref: \"#/$defs/nonEmptyString\"\n additionalProperties: false\n linkPolicy:\n type: object\n required:\n - accepted_formats\n - write_format\n properties:\n accepted_formats:\n type: array\n minItems: 1\n uniqueItems: true\n items:\n enum:\n - wikilink\n - markdown\n write_format:\n enum:\n - wikilink\n - markdown\n additionalProperties: false\n archivePolicy:\n type: object\n required:\n - archived_tag\n - move_on_archive\n properties:\n archived_tag:\n $ref: \"#/$defs/nonEmptyString\"\n move_on_archive:\n type: boolean\n folder:\n $ref: \"#/$defs/nonEmptyString\"\n additionalProperties: false\n timeTrackingPolicy:\n type: object\n required:\n - auto_stop_on_complete\n properties:\n auto_stop_on_complete:\n type: boolean\n additionalProperties: false\n templatingPolicy:\n type: object\n required:\n - enabled\n - occurrence_enabled\n properties:\n enabled:\n type: boolean\n template_path:\n $ref: \"#/$defs/nonEmptyString\"\n occurrence_enabled:\n type: boolean\n occurrence_template_path:\n $ref: \"#/$defs/nonEmptyString\"\n failure_mode:\n enum:\n - error\n - warning_fallback\n unknown_variable_policy:\n enum:\n - preserve\n - empty\n additionalProperties: false\n nlpTrigger:\n type: object\n required:\n - property_id\n - trigger\n - enabled\n properties:\n property_id:\n $ref: \"#/$defs/nonEmptyString\"\n trigger:\n $ref: \"#/$defs/nonEmptyString\"\n enabled:\n type: boolean\n additionalProperties: false\n nlpPolicy:\n type: object\n required:\n - triggers\n properties:\n triggers:\n type: array\n items:\n $ref: \"#/$defs/nlpTrigger\"\n additionalProperties: false\n---\n\n# TaskNotes task contract\n\nTypes implement this contract through `implements`; applications consume\nthe normalized contract view rather than assuming frontmatter names.\n" + }, + { + "source": "contracts/tasknotes.task/0.3.0-rc.6.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: tasknotes.task\nversion: 0.3.0-rc.6\nname: TaskNotes task\ndescription: Portable task data and behavior defined by tasknotes-spec 0.3.0-rc.6.\nrecord_schema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n $id: https://tasknotes.dev/schemas/tasknotes-task.schema.json\n title: TaskNotes portable task view\n description: The storage-neutral record view exposed by the tasknotes.task 0.3.0-rc.6 record contract.\n type: object\n required:\n - status\n - dateCreated\n additionalProperties: false\n properties:\n id:\n type: string\n minLength: 1\n title:\n type: string\n minLength: 1\n status:\n type: string\n minLength: 1\n priority:\n type: string\n minLength: 1\n due:\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n scheduled:\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n contexts:\n type: array\n items:\n type: string\n projects:\n type: array\n items:\n type: string\n assignees:\n type: array\n uniqueItems: true\n items:\n type: string\n minLength: 1\n pattern: \\S\n description: Links to records implementing mdbase.person, such as [[Alex Rivera]]. Implementing types declare this field in collection.links. These references never grant collection access.\n attachments:\n type: array\n uniqueItems: true\n items:\n type: string\n minLength: 1\n timeEstimate:\n type: integer\n minimum: 0\n completedDate:\n type: string\n format: date\n dateCreated:\n type: string\n format: date-time\n dateModified:\n type: string\n format: date-time\n recurrence:\n type: string\n recurrenceAnchor:\n enum:\n - scheduled\n - completion\n recurrenceParent:\n type: string\n occurrenceDate:\n type: string\n format: date\n occurrenceMaterialization:\n enum:\n - manual\n - on_completion\n - rolling\n occurrenceNextTrigger:\n enum:\n - completion\n - completion_or_skip\n occurrenceTemplate:\n type: string\n occurrencePastHorizon:\n type: string\n occurrenceFutureHorizon:\n type: string\n tags:\n type: array\n items:\n type: string\n timeEntries:\n type: array\n items:\n type: object\n reminders:\n type: array\n items:\n type: object\n blockedBy:\n type: array\n items:\n type: object\n completeInstances:\n type: array\n items:\n type: string\n format: date\n skippedInstances:\n type: array\n items:\n type: string\n format: date\n icsEventId:\n type: array\n items:\n type: string\n googleCalendarEventId:\n type: string\n googleCalendarExceptionEventId:\n type: string\n googleCalendarExceptionOriginalScheduled:\n type: string\n format: date\n googleCalendarMovedOriginalDates:\n type: array\n items:\n type: string\n format: date\n sortOrder:\n type: string\nbinding_schema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n $id: https://tasknotes.dev/schemas/tasknotes-task-binding.schema.json\n title: TaskNotes task data-contract binding\n description: Semantic configuration supplied by an mdbase type that implements tasknotes.task 0.3.0-rc.6. App behaviour, such as templates, archive moves, status cycling and natural-language triggers, lives in the app's tasknotes.settings record instead.\n type: object\n required:\n - profiles\n - capabilities\n - title\n - status\n - priority\n - recurrence\n - occurrences\n - links\n - archive\n properties:\n profiles:\n type: array\n minItems: 1\n uniqueItems: true\n items:\n enum:\n - core-lite\n - recurrence\n - templating\n - materialized-occurrences\n - extended\n capabilities:\n type: array\n uniqueItems: true\n items:\n enum:\n - dependencies\n - reminders\n - attachments\n - links\n - time-tracking\n - materialized-occurrences\n - rename\n - archive\n - batch\n - concurrency\n - dry-run\n - migration\n - templating\n title:\n $ref: \"#/$defs/titlePolicy\"\n status:\n $ref: \"#/$defs/statusPolicy\"\n priority:\n $ref: \"#/$defs/priorityPolicy\"\n recurrence:\n $ref: \"#/$defs/recurrencePolicy\"\n occurrences:\n $ref: \"#/$defs/occurrencePolicy\"\n links:\n $ref: \"#/$defs/linkPolicy\"\n archive:\n $ref: \"#/$defs/archivePolicy\"\n additionalProperties: false\n $defs:\n nonEmptyString:\n type: string\n minLength: 1\n stringSet:\n type: array\n uniqueItems: true\n items:\n $ref: \"#/$defs/nonEmptyString\"\n titlePolicy:\n type: object\n required:\n - storage\n properties:\n storage:\n enum:\n - filename\n - frontmatter\n filename_format:\n enum:\n - title\n - zettel\n - timestamp\n - uuid\n - custom\n custom_filename_template:\n $ref: \"#/$defs/nonEmptyString\"\n allOf:\n - if:\n properties:\n filename_format:\n const: custom\n required:\n - filename_format\n then:\n properties:\n custom_filename_template:\n $ref: \"#/$defs/nonEmptyString\"\n required:\n - custom_filename_template\n additionalProperties: true\n statusDefinition:\n type: object\n required:\n - value\n - label\n - color\n - is_completed\n - is_skipped\n - order\n properties:\n value:\n $ref: \"#/$defs/nonEmptyString\"\n label:\n type: string\n color:\n type: string\n icon:\n $ref: \"#/$defs/nonEmptyString\"\n is_completed:\n type: boolean\n is_skipped:\n type: boolean\n order:\n type: number\n additionalProperties: true\n statusPolicy:\n type: object\n required:\n - values\n - default\n - completed_values\n - definitions\n properties:\n values:\n $ref: \"#/$defs/stringSet\"\n default:\n $ref: \"#/$defs/nonEmptyString\"\n completed_values:\n $ref: \"#/$defs/stringSet\"\n skipped_values:\n $ref: \"#/$defs/stringSet\"\n default_skipped:\n $ref: \"#/$defs/nonEmptyString\"\n definitions:\n type: array\n items:\n $ref: \"#/$defs/statusDefinition\"\n additionalProperties: false\n priorityDefinition:\n type: object\n required:\n - value\n - label\n - color\n - weight\n properties:\n value:\n $ref: \"#/$defs/nonEmptyString\"\n label:\n type: string\n color:\n type: string\n icon:\n $ref: \"#/$defs/nonEmptyString\"\n weight:\n type: number\n additionalProperties: true\n priorityPolicy:\n type: object\n required:\n - values\n - default\n - definitions\n properties:\n values:\n $ref: \"#/$defs/stringSet\"\n default:\n $ref: \"#/$defs/nonEmptyString\"\n definitions:\n type: array\n items:\n $ref: \"#/$defs/priorityDefinition\"\n additionalProperties: false\n recurrencePolicy:\n type: object\n required:\n - syntax\n - maintain_due_date_offset\n properties:\n syntax:\n const: tasknotes\n maintain_due_date_offset:\n type: boolean\n additionalProperties: false\n occurrencePolicy:\n type: object\n required:\n - identity_roles\n - default_materialization\n - default_next_trigger\n properties:\n identity_roles:\n const:\n - recurrenceParent\n - occurrenceDate\n default_materialization:\n enum:\n - manual\n - on_completion\n - rolling\n default_next_trigger:\n enum:\n - completion\n - completion_or_skip\n past_horizon:\n $ref: \"#/$defs/nonEmptyString\"\n future_horizon:\n $ref: \"#/$defs/nonEmptyString\"\n additionalProperties: false\n linkPolicy:\n type: object\n required:\n - accepted_formats\n properties:\n accepted_formats:\n type: array\n minItems: 1\n uniqueItems: true\n items:\n enum:\n - wikilink\n - markdown\n additionalProperties: false\n archivePolicy:\n type: object\n required:\n - archived_tag\n properties:\n archived_tag:\n $ref: \"#/$defs/nonEmptyString\"\n additionalProperties: false\n---\n\n# TaskNotes task contract\n\nTypes implement this contract through `implements`; applications consume\nthe normalized contract view rather than assuming frontmatter names.\n" + }, + { + "source": "types/tasknotes-task/6.md", + "document": "---\nkind: mdbase.type\nname: task\nversion: 5\ndescription: A task managed by TaskNotes.\nmatch:\n where:\n tags:\n contains: task\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n type: object\n additionalProperties: true\n properties:\n id:\n type: string\n minLength: 1\n title:\n type: string\n minLength: 1\n status:\n enum: &a2\n - none\n - open\n - in-progress\n - done\n - cancelled\n default: open\n priority:\n enum: &a4\n - none\n - low\n - normal\n - high\n default: normal\n due: &a1\n anyOf:\n - type: string\n format: date\n - type: string\n format: date-time\n scheduled: *a1\n contexts:\n type: array\n items:\n type: string\n projects:\n type: array\n items:\n type: string\n assignees:\n type: array\n items:\n type: string\n minLength: 1\n pattern: \\S\n uniqueItems: true\n attachments:\n type: array\n items:\n type: string\n minLength: 1\n uniqueItems: true\n timeEstimate:\n type: integer\n minimum: 0\n completedDate:\n type: string\n format: date\n dateCreated:\n type: string\n format: date-time\n dateModified:\n type: string\n format: date-time\n recurrence:\n type: string\n recurrence_anchor:\n enum:\n - scheduled\n - completion\n default: scheduled\n occurrence_materialization:\n enum:\n - manual\n - on_completion\n - rolling\n default: manual\n occurrence_next_trigger:\n enum:\n - completion\n - completion_or_skip\n default: completion\n occurrence_template:\n type: string\n occurrence_past_horizon:\n type: string\n occurrence_future_horizon:\n type: string\n recurrence_parent:\n type: string\n occurrence_date:\n type: string\n format: date\n tags:\n type: array\n items:\n type: string\n timeEntries:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n startTime:\n type: string\n format: date-time\n endTime:\n type: string\n format: date-time\n description:\n type: string\n duration:\n type: integer\n reminders:\n type: array\n items:\n oneOf:\n - type: object\n required:\n - id\n - type\n - absoluteTime\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: absolute\n description:\n type: string\n absoluteTime:\n type: string\n format: date-time\n - type: object\n required:\n - id\n - type\n - relatedTo\n - offset\n additionalProperties: false\n properties:\n id:\n type: string\n type:\n const: relative\n description:\n type: string\n relatedTo:\n enum:\n - due\n - scheduled\n offset:\n type: string\n blockedBy:\n type: array\n items:\n type: object\n additionalProperties: false\n properties:\n uid:\n type: string\n reltype:\n type: string\n gap:\n type: string\n required:\n - uid\n complete_instances:\n type: array\n items:\n type: string\n format: date\n skipped_instances:\n type: array\n items:\n type: string\n format: date\n icsEventId:\n type: array\n items:\n type: string\n googleCalendarEventId:\n type: string\n googleCalendarExceptionEventId:\n type: string\n googleCalendarExceptionOriginalScheduled:\n type: string\n format: date\n googleCalendarMovedOriginalDates:\n type: array\n items:\n type: string\n format: date\n tasknotes_manual_order:\n type: string\n allOf:\n - if:\n required:\n - status\n properties:\n status:\n enum: &a3\n - done\n not:\n required:\n - recurrence\n then:\n required:\n - completedDate\n required:\n - title\n - status\n - dateCreated\ncollection:\n read_defaults:\n status: open\n priority: normal\n recurrence_anchor: scheduled\n occurrence_materialization: manual\n occurrence_next_trigger: completion\n links:\n projects[]:\n target_type: any\n validate_exists: false\n assignees[]:\n validate_exists: false\n attachments[]:\n validate_exists: false\n occurrence_template:\n target_type: any\n validate_exists: false\n recurrence_parent:\n target_type: task\n validate_exists: false\n blockedBy[].uid:\n target_type: task\n validate_exists: false\n path:\n runtime: tasknotes\n template: \"{{zettel}}\"\n folder: tasks\n generated_by: tasknotes.filename.create\n display:\n name_field: title\n unique:\n - field: id\n scope: type\nlifecycle:\n on_create:\n set:\n id:\n uuid: true\n dateCreated:\n now: true\n dateModified:\n now: true\n on_update:\n set:\n dateModified:\n now: true\nimplements:\n - contract: tasknotes.task\n version: 0.3.0-rc.6\n fields:\n id: id\n title: title\n status: status\n priority: priority\n due: due\n scheduled: scheduled\n contexts: contexts\n projects: projects\n assignees: assignees\n attachments: attachments\n timeEstimate: timeEstimate\n completedDate: completedDate\n dateCreated: dateCreated\n dateModified: dateModified\n recurrence: recurrence\n recurrenceAnchor: recurrence_anchor\n occurrenceMaterialization: occurrence_materialization\n occurrenceNextTrigger: occurrence_next_trigger\n occurrenceTemplate: occurrence_template\n occurrencePastHorizon: occurrence_past_horizon\n occurrenceFutureHorizon: occurrence_future_horizon\n recurrenceParent: recurrence_parent\n occurrenceDate: occurrence_date\n tags: tags\n timeEntries: timeEntries\n reminders: reminders\n blockedBy: blockedBy\n completeInstances: complete_instances\n skippedInstances: skipped_instances\n icsEventId: icsEventId\n googleCalendarEventId: googleCalendarEventId\n googleCalendarExceptionEventId: googleCalendarExceptionEventId\n googleCalendarExceptionOriginalScheduled: googleCalendarExceptionOriginalScheduled\n googleCalendarMovedOriginalDates: googleCalendarMovedOriginalDates\n sortOrder: tasknotes_manual_order\n binding:\n profiles:\n - core-lite\n - recurrence\n - materialized-occurrences\n capabilities:\n - dependencies\n - reminders\n - attachments\n - links\n - time-tracking\n - materialized-occurrences\n - archive\n - templating\n title:\n storage: frontmatter\n filename_format: zettel\n status:\n values: *a2\n default: open\n completed_values: *a3\n skipped_values:\n - cancelled\n default_skipped: cancelled\n definitions:\n - value: none\n label: None\n color: \"#94a3b8\"\n is_completed: false\n is_skipped: false\n order: 0\n - value: open\n label: Open\n color: \"#64748b\"\n is_completed: false\n is_skipped: false\n order: 1\n - value: in-progress\n label: In progress\n color: \"#3b82f6\"\n is_completed: false\n is_skipped: false\n order: 2\n - value: done\n label: Done\n color: \"#22c55e\"\n is_completed: true\n is_skipped: false\n order: 3\n - value: cancelled\n label: Cancelled\n color: \"#94a3b8\"\n is_completed: false\n is_skipped: true\n order: 4\n priority:\n values: *a4\n default: normal\n definitions:\n - value: none\n label: None\n color: \"#94a3b8\"\n weight: 0\n - value: low\n label: Low\n color: \"#3b82f6\"\n weight: 1\n - value: normal\n label: Normal\n color: \"#f59e0b\"\n weight: 2\n - value: high\n label: High\n color: \"#ef4444\"\n weight: 3\n recurrence:\n syntax: tasknotes\n maintain_due_date_offset: true\n occurrences:\n identity_roles:\n - recurrenceParent\n - occurrenceDate\n default_materialization: manual\n default_next_trigger: completion\n past_horizon: P0D\n future_horizon: P14D\n links:\n accepted_formats:\n - wikilink\n - markdown\n archive:\n archived_tag: archived\nx-tasknotes-generator:\n managed_fields:\n - attachments\n - blockedBy\n - complete_instances\n - completedDate\n - contexts\n - dateCreated\n - dateModified\n - due\n - googleCalendarEventId\n - googleCalendarExceptionEventId\n - googleCalendarExceptionOriginalScheduled\n - googleCalendarMovedOriginalDates\n - icsEventId\n - id\n - occurrence_date\n - occurrence_future_horizon\n - occurrence_materialization\n - occurrence_next_trigger\n - occurrence_past_horizon\n - occurrence_template\n - priority\n - projects\n - recurrence\n - recurrence_anchor\n - recurrence_parent\n - reminders\n - scheduled\n - skipped_instances\n - status\n - tags\n - tasknotes_manual_order\n - timeEntries\n - timeEstimate\n - title\n---\n# Task\n\nTask records live under `tasks/`.\n" + }, + { + "source": "schemas/tasknotes.task/0.3.0-rc.6.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://tasknotes.dev/schemas/tasknotes-task.schema.json\",\n \"title\": \"TaskNotes portable task view\",\n \"description\": \"The storage-neutral record view exposed by the tasknotes.task 0.3.0-rc.6 record contract.\",\n \"type\": \"object\",\n \"required\": [\n \"status\",\n \"dateCreated\"\n ],\n \"additionalProperties\": false,\n \"properties\": {\n \"id\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"title\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"status\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"priority\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"due\": {\n \"anyOf\": [\n {\n \"type\": \"string\",\n \"format\": \"date\"\n },\n {\n \"type\": \"string\",\n \"format\": \"date-time\"\n }\n ]\n },\n \"scheduled\": {\n \"anyOf\": [\n {\n \"type\": \"string\",\n \"format\": \"date\"\n },\n {\n \"type\": \"string\",\n \"format\": \"date-time\"\n }\n ]\n },\n \"contexts\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"projects\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"assignees\": {\n \"type\": \"array\",\n \"uniqueItems\": true,\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"pattern\": \"\\\\S\"\n },\n \"description\": \"Links to records implementing mdbase.person, such as [[Alex Rivera]]. Implementing types declare this field in collection.links. These references never grant collection access.\"\n },\n \"attachments\": {\n \"type\": \"array\",\n \"uniqueItems\": true,\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1\n }\n },\n \"timeEstimate\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"completedDate\": {\n \"type\": \"string\",\n \"format\": \"date\"\n },\n \"dateCreated\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"dateModified\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"recurrence\": {\n \"type\": \"string\"\n },\n \"recurrenceAnchor\": {\n \"enum\": [\n \"scheduled\",\n \"completion\"\n ]\n },\n \"recurrenceParent\": {\n \"type\": \"string\"\n },\n \"occurrenceDate\": {\n \"type\": \"string\",\n \"format\": \"date\"\n },\n \"occurrenceMaterialization\": {\n \"enum\": [\n \"manual\",\n \"on_completion\",\n \"rolling\"\n ]\n },\n \"occurrenceNextTrigger\": {\n \"enum\": [\n \"completion\",\n \"completion_or_skip\"\n ]\n },\n \"occurrenceTemplate\": {\n \"type\": \"string\"\n },\n \"occurrencePastHorizon\": {\n \"type\": \"string\"\n },\n \"occurrenceFutureHorizon\": {\n \"type\": \"string\"\n },\n \"tags\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"timeEntries\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"reminders\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"blockedBy\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"completeInstances\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"format\": \"date\"\n }\n },\n \"skippedInstances\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"format\": \"date\"\n }\n },\n \"icsEventId\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"googleCalendarEventId\": {\n \"type\": \"string\"\n },\n \"googleCalendarExceptionEventId\": {\n \"type\": \"string\"\n },\n \"googleCalendarExceptionOriginalScheduled\": {\n \"type\": \"string\",\n \"format\": \"date\"\n },\n \"googleCalendarMovedOriginalDates\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"format\": \"date\"\n }\n },\n \"sortOrder\": {\n \"type\": \"string\"\n }\n }\n}\n" + }, + { + "source": "schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://tasknotes.dev/schemas/tasknotes-task-binding.schema.json\",\n \"title\": \"TaskNotes task data-contract binding\",\n \"description\": \"Semantic configuration supplied by an mdbase type that implements tasknotes.task 0.3.0-rc.6. App behaviour, such as templates, archive moves, status cycling and natural-language triggers, lives in the app's tasknotes.settings record instead.\",\n \"type\": \"object\",\n \"required\": [\n \"profiles\",\n \"capabilities\",\n \"title\",\n \"status\",\n \"priority\",\n \"recurrence\",\n \"occurrences\",\n \"links\",\n \"archive\"\n ],\n \"properties\": {\n \"profiles\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"uniqueItems\": true,\n \"items\": {\n \"enum\": [\n \"core-lite\",\n \"recurrence\",\n \"templating\",\n \"materialized-occurrences\",\n \"extended\"\n ]\n }\n },\n \"capabilities\": {\n \"type\": \"array\",\n \"uniqueItems\": true,\n \"items\": {\n \"enum\": [\n \"dependencies\",\n \"reminders\",\n \"attachments\",\n \"links\",\n \"time-tracking\",\n \"materialized-occurrences\",\n \"rename\",\n \"archive\",\n \"batch\",\n \"concurrency\",\n \"dry-run\",\n \"migration\",\n \"templating\"\n ]\n }\n },\n \"title\": {\n \"$ref\": \"#/$defs/titlePolicy\"\n },\n \"status\": {\n \"$ref\": \"#/$defs/statusPolicy\"\n },\n \"priority\": {\n \"$ref\": \"#/$defs/priorityPolicy\"\n },\n \"recurrence\": {\n \"$ref\": \"#/$defs/recurrencePolicy\"\n },\n \"occurrences\": {\n \"$ref\": \"#/$defs/occurrencePolicy\"\n },\n \"links\": {\n \"$ref\": \"#/$defs/linkPolicy\"\n },\n \"archive\": {\n \"$ref\": \"#/$defs/archivePolicy\"\n }\n },\n \"additionalProperties\": false,\n \"$defs\": {\n \"nonEmptyString\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"stringSet\": {\n \"type\": \"array\",\n \"uniqueItems\": true,\n \"items\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n }\n },\n \"titlePolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"storage\"\n ],\n \"properties\": {\n \"storage\": {\n \"enum\": [\n \"filename\",\n \"frontmatter\"\n ]\n },\n \"filename_format\": {\n \"enum\": [\n \"title\",\n \"zettel\",\n \"timestamp\",\n \"uuid\",\n \"custom\"\n ]\n },\n \"custom_filename_template\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n }\n },\n \"allOf\": [\n {\n \"if\": {\n \"properties\": {\n \"filename_format\": {\n \"const\": \"custom\"\n }\n },\n \"required\": [\n \"filename_format\"\n ]\n },\n \"then\": {\n \"properties\": {\n \"custom_filename_template\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n }\n },\n \"required\": [\n \"custom_filename_template\"\n ]\n }\n }\n ],\n \"additionalProperties\": true\n },\n \"statusDefinition\": {\n \"type\": \"object\",\n \"required\": [\n \"value\",\n \"label\",\n \"color\",\n \"is_completed\",\n \"is_skipped\",\n \"order\"\n ],\n \"properties\": {\n \"value\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"label\": {\n \"type\": \"string\"\n },\n \"color\": {\n \"type\": \"string\"\n },\n \"icon\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"is_completed\": {\n \"type\": \"boolean\"\n },\n \"is_skipped\": {\n \"type\": \"boolean\"\n },\n \"order\": {\n \"type\": \"number\"\n }\n },\n \"additionalProperties\": true\n },\n \"statusPolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"values\",\n \"default\",\n \"completed_values\",\n \"definitions\"\n ],\n \"properties\": {\n \"values\": {\n \"$ref\": \"#/$defs/stringSet\"\n },\n \"default\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"completed_values\": {\n \"$ref\": \"#/$defs/stringSet\"\n },\n \"skipped_values\": {\n \"$ref\": \"#/$defs/stringSet\"\n },\n \"default_skipped\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"definitions\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/statusDefinition\"\n }\n }\n },\n \"additionalProperties\": false\n },\n \"priorityDefinition\": {\n \"type\": \"object\",\n \"required\": [\n \"value\",\n \"label\",\n \"color\",\n \"weight\"\n ],\n \"properties\": {\n \"value\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"label\": {\n \"type\": \"string\"\n },\n \"color\": {\n \"type\": \"string\"\n },\n \"icon\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"weight\": {\n \"type\": \"number\"\n }\n },\n \"additionalProperties\": true\n },\n \"priorityPolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"values\",\n \"default\",\n \"definitions\"\n ],\n \"properties\": {\n \"values\": {\n \"$ref\": \"#/$defs/stringSet\"\n },\n \"default\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"definitions\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/priorityDefinition\"\n }\n }\n },\n \"additionalProperties\": false\n },\n \"recurrencePolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"syntax\",\n \"maintain_due_date_offset\"\n ],\n \"properties\": {\n \"syntax\": {\n \"const\": \"tasknotes\"\n },\n \"maintain_due_date_offset\": {\n \"type\": \"boolean\"\n }\n },\n \"additionalProperties\": false\n },\n \"occurrencePolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"identity_roles\",\n \"default_materialization\",\n \"default_next_trigger\"\n ],\n \"properties\": {\n \"identity_roles\": {\n \"const\": [\n \"recurrenceParent\",\n \"occurrenceDate\"\n ]\n },\n \"default_materialization\": {\n \"enum\": [\n \"manual\",\n \"on_completion\",\n \"rolling\"\n ]\n },\n \"default_next_trigger\": {\n \"enum\": [\n \"completion\",\n \"completion_or_skip\"\n ]\n },\n \"past_horizon\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"future_horizon\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n }\n },\n \"additionalProperties\": false\n },\n \"linkPolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"accepted_formats\"\n ],\n \"properties\": {\n \"accepted_formats\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"uniqueItems\": true,\n \"items\": {\n \"enum\": [\n \"wikilink\",\n \"markdown\"\n ]\n }\n }\n },\n \"additionalProperties\": false\n },\n \"archivePolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"archived_tag\"\n ],\n \"properties\": {\n \"archived_tag\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n }\n },\n \"additionalProperties\": false\n }\n }\n}\n" + }, + { + "source": "schemas/mdbase.app-settings/1.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"title\": \"mdbase.app-settings 1.0.0 record contract view\",\n \"description\": \"The reserved fields every app settings record shares. Everything else in the record belongs to the app and is described by the app's own settings contract.\",\n \"type\": \"object\",\n \"required\": [\"app\", \"scope\", \"settings_version\"],\n \"properties\": {\n \"app\": {\n \"type\": \"string\",\n \"pattern\": \"^[a-z0-9]+([.-][a-z0-9]+)*$\",\n \"description\": \"The app whose clients honour these settings, such as tasknotes or dev.mdbase.reader.\"\n },\n \"scope\": {\n \"enum\": [\"collection\", \"user\"],\n \"description\": \"Who the values apply to: everyone using the app in this collection, or one person.\"\n },\n \"user\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"A link to the mdbase.person record the values apply to. Present only when scope is user.\"\n },\n \"settings_version\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"The version of the app's settings schema that last wrote the record. A client that does not understand it treats the settings as read-only.\"\n }\n },\n \"allOf\": [\n {\n \"if\": { \"properties\": { \"scope\": { \"const\": \"user\" } }, \"required\": [\"scope\"] },\n \"then\": { \"required\": [\"user\"] },\n \"else\": { \"not\": { \"required\": [\"user\"] } }\n }\n ],\n \"additionalProperties\": true\n}\n" + }, + { + "source": "contracts/mdbase.app-settings/1.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.app-settings\nversion: 1.0.0\nname: App settings\ndescription: One record per app holding the policy that app's clients honour in this collection.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.app-settings/1.0.0.schema.json\n---\n\n# App settings\n\nAn app settings record holds values that every client of one app honours in this\ncollection, such as how new files are named. The values change client behaviour,\nnever what another record means.\n\n## Location and identity\n\nA collection-scope record lives at `_settings/.md`, where `` is the\nrecord's `app` field. Clients read it by that path, without a query. Each\nimplementing type declares `collection.unique` on `app` with `scope: type`, so a\ncollection holds at most one collection-scope record per app.\n\nThe record's `type` field names the app's own settings type, not a shared value.\nGeneric tools find every settings record through this contract.\n\n## Reserved fields\n\n- `app`: the app id.\n- `scope`: `collection`, or `user` for one person's overrides.\n- `user`: a link to an `mdbase.person` record, present only when `scope` is\n `user`.\n- `settings_version`: the version of the app's settings schema that last wrote\n the record.\n\nEvery other frontmatter field belongs to the app and is described by the app's\nown settings contract. The body is free Markdown for people; apps never parse it.\n\n## Client behaviour\n\n- A missing record means every setting has its default. Clients never create the\n record on read.\n- A missing or invalid field takes its default; valid fields are used as\n written. The record is not rewritten until someone saves.\n- A save creates the record at its fixed path the first time, and otherwise\n patches only the fields it changes, guarded by the record's revision.\n- A client that finds a `settings_version` newer than it understands treats the\n settings as read-only and uses them as written.\n\n## Authority\n\nThis artifact is passive. A settings record grants nothing and must never hold\nsecrets: anyone who can read or write records can read or edit it.\n" + }, + { + "source": "schemas/tasknotes.settings/1.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"title\": \"tasknotes.settings 1.0.0\",\n \"description\": \"Collection-wide behaviour that every TaskNotes client honours. Every field is optional and has a default, so a record with none of them behaves like no record at all.\",\n \"type\": \"object\",\n \"required\": [\n \"app\",\n \"scope\",\n \"settings_version\"\n ],\n \"properties\": {\n \"app\": {\n \"const\": \"dev.tasknotes\",\n \"description\": \"Marks this record as TaskNotes' settings.\"\n },\n \"scope\": {\n \"const\": \"collection\",\n \"description\": \"These settings apply to everyone using TaskNotes in this collection.\"\n },\n \"settings_version\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"The version of these settings that last wrote the record. TaskNotes writes 1.\"\n },\n \"nlp_triggers\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\n \"property_id\",\n \"trigger\",\n \"enabled\"\n ],\n \"properties\": {\n \"property_id\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"trigger\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"enabled\": {\n \"type\": \"boolean\"\n }\n },\n \"additionalProperties\": false\n },\n \"description\": \"Natural-language capture triggers, such as @ for contexts. Without the field each client uses its own defaults.\"\n },\n \"template_enabled\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Apply template_path to the body of new tasks.\"\n },\n \"template_path\": {\n \"type\": \"string\",\n \"description\": \"The template for new task bodies. Empty or absent means none.\"\n },\n \"occurrence_template_enabled\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Apply occurrence_template_path to new materialized occurrences.\"\n },\n \"occurrence_template_path\": {\n \"type\": \"string\",\n \"description\": \"The template for new occurrence bodies. Empty or absent means none.\"\n },\n \"template_failure_mode\": {\n \"enum\": [\n \"error\",\n \"warning_fallback\"\n ],\n \"description\": \"What a client does when a template cannot be applied.\"\n },\n \"template_unknown_variable_policy\": {\n \"enum\": [\n \"preserve\",\n \"empty\"\n ],\n \"description\": \"What a client writes for a template variable it does not know.\"\n },\n \"move_on_archive\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Move a task's file to archive_folder when it is archived.\"\n },\n \"archive_folder\": {\n \"type\": \"string\",\n \"description\": \"Where archived tasks move to. Empty or absent means the client's default.\"\n },\n \"auto_stop_time_tracking_on_complete\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Stop a running timer when its task is completed.\"\n },\n \"reset_body_checkboxes_on_recurrence\": {\n \"type\": \"boolean\",\n \"default\": false,\n \"description\": \"Uncheck body checkboxes when a recurring task moves to its next occurrence.\"\n },\n \"link_write_format\": {\n \"enum\": [\n \"wikilink\",\n \"markdown\"\n ],\n \"default\": \"wikilink\",\n \"description\": \"How clients write links into task frontmatter. Both formats are always read.\"\n },\n \"status_behavior\": {\n \"type\": \"object\",\n \"description\": \"Behaviour per status value. A status without an entry has no next status and no auto-archive, and is out of the status cycle exactly when it is a skipped status.\",\n \"additionalProperties\": {\n \"type\": \"object\",\n \"properties\": {\n \"next_status\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"The status the cycle moves to next.\"\n },\n \"exclude_from_cycle\": {\n \"type\": \"boolean\",\n \"description\": \"Leave this status out of the status cycle.\"\n },\n \"auto_archive\": {\n \"type\": \"boolean\",\n \"description\": \"Archive a task some time after it takes this status.\"\n },\n \"auto_archive_delay_minutes\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"description\": \"How long after taking this status a task is archived.\"\n }\n },\n \"additionalProperties\": false\n },\n \"default\": {}\n }\n },\n \"additionalProperties\": true\n}\n" + }, + { + "source": "contracts/tasknotes.settings/1.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: tasknotes.settings\nversion: 1.0.0\nname: TaskNotes settings\ndescription: Collection-wide TaskNotes behaviour, such as templates, archive moves and status cycling.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/tasknotes.settings/1.0.0.schema.json\n---\n\n# TaskNotes settings\n\nThe collection's settings record for TaskNotes, at `_settings/dev.tasknotes.md`.\nIt also implements `mdbase.app-settings`, whose reserved fields (`app`, `scope`,\n`settings_version`) it shares.\n\nThese settings change what TaskNotes clients do, never what a task record\nmeans: that stays in the `tasknotes.task` binding of each task type.\n`tasknotes.task` 0.3.0-rc.6 moved them here from the binding. A client reads\neach setting from this record, then from an earlier binding that still holds\nit, then uses its default, so a collection whose task type is still on rc.5\nkeeps its behaviour until it is upgraded.\n\n## Fields\n\n- `nlp_triggers`: natural-language capture triggers. Without it, each client\n uses its own defaults.\n- `template_enabled`, `template_path`, `occurrence_template_enabled`,\n `occurrence_template_path`, `template_failure_mode`,\n `template_unknown_variable_policy`: body templates for new tasks and\n materialized occurrences.\n- `move_on_archive`, `archive_folder`: whether archiving moves the file, and\n where to.\n- `auto_stop_time_tracking_on_complete`: stop a running timer on completion.\n- `reset_body_checkboxes_on_recurrence`: uncheck body checkboxes when a\n recurring task advances.\n- `link_write_format`: `wikilink` or `markdown` for links written to task\n frontmatter.\n- `status_behavior`: per status value, `next_status`, `exclude_from_cycle`,\n `auto_archive` and `auto_archive_delay_minutes`. A status without an entry\n has no next status and no auto-archive (5 minute delay), and is out of the\n cycle exactly when it is a skipped status.\n\n## Authority\n\nThis artifact is passive and grants nothing.\n" + }, + { + "source": "types/tasknotes-settings/1.md", + "document": "---\nkind: mdbase.type\nname: tasknotes-settings\nversion: 1\ndescription: TaskNotes' collection-wide settings, one record at _settings/dev.tasknotes.md.\nmatch:\n where:\n app:\n eq: dev.tasknotes\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: tasknotes.settings 1.0.0\n description: Collection-wide behaviour that every TaskNotes client honours. Every field is optional and has a default, so a record with none of them behaves like no record at all.\n type: object\n required:\n - app\n - scope\n - settings_version\n properties:\n app:\n const: dev.tasknotes\n description: Marks this record as TaskNotes' settings.\n scope:\n const: collection\n description: These settings apply to everyone using TaskNotes in this collection.\n settings_version:\n type: integer\n minimum: 1\n description: The version of these settings that last wrote the record. TaskNotes writes 1.\n nlp_triggers:\n type: array\n items:\n type: object\n required:\n - property_id\n - trigger\n - enabled\n properties:\n property_id:\n type: string\n minLength: 1\n trigger:\n type: string\n minLength: 1\n enabled:\n type: boolean\n additionalProperties: false\n description: Natural-language capture triggers, such as @ for contexts. Without the field each client uses its own defaults.\n template_enabled:\n type: boolean\n default: false\n description: Apply template_path to the body of new tasks.\n template_path:\n type: string\n description: The template for new task bodies. Empty or absent means none.\n occurrence_template_enabled:\n type: boolean\n default: false\n description: Apply occurrence_template_path to new materialized occurrences.\n occurrence_template_path:\n type: string\n description: The template for new occurrence bodies. Empty or absent means none.\n template_failure_mode:\n enum:\n - error\n - warning_fallback\n description: What a client does when a template cannot be applied.\n template_unknown_variable_policy:\n enum:\n - preserve\n - empty\n description: What a client writes for a template variable it does not know.\n move_on_archive:\n type: boolean\n default: false\n description: Move a task's file to archive_folder when it is archived.\n archive_folder:\n type: string\n description: Where archived tasks move to. Empty or absent means the client's default.\n auto_stop_time_tracking_on_complete:\n type: boolean\n default: false\n description: Stop a running timer when its task is completed.\n reset_body_checkboxes_on_recurrence:\n type: boolean\n default: false\n description: Uncheck body checkboxes when a recurring task moves to its next occurrence.\n link_write_format:\n enum:\n - wikilink\n - markdown\n default: wikilink\n description: How clients write links into task frontmatter. Both formats are always read.\n status_behavior:\n type: object\n description: Behaviour per status value. A status without an entry has no next status and no auto-archive, and is out of the status cycle exactly when it is a skipped status.\n additionalProperties:\n type: object\n properties:\n next_status:\n type: string\n minLength: 1\n description: The status the cycle moves to next.\n exclude_from_cycle:\n type: boolean\n description: Leave this status out of the status cycle.\n auto_archive:\n type: boolean\n description: Archive a task some time after it takes this status.\n auto_archive_delay_minutes:\n type: number\n minimum: 0\n description: How long after taking this status a task is archived.\n additionalProperties: false\n default: {}\n additionalProperties: true\ncollection:\n unique:\n - field: app\n scope: type\nimplements:\n - contract: mdbase.app-settings\n version: 1.0.0\n fields:\n app: app\n scope: scope\n settings_version: settings_version\n - contract: tasknotes.settings\n version: 1.0.0\n fields:\n app: app\n scope: scope\n settings_version: settings_version\n nlp_triggers: nlp_triggers\n template_enabled: template_enabled\n template_path: template_path\n occurrence_template_enabled: occurrence_template_enabled\n occurrence_template_path: occurrence_template_path\n template_failure_mode: template_failure_mode\n template_unknown_variable_policy: template_unknown_variable_policy\n move_on_archive: move_on_archive\n archive_folder: archive_folder\n auto_stop_time_tracking_on_complete: auto_stop_time_tracking_on_complete\n reset_body_checkboxes_on_recurrence: reset_body_checkboxes_on_recurrence\n link_write_format: link_write_format\n status_behavior: status_behavior\n---\n\n# TaskNotes settings\n\nSettings that every TaskNotes client honours in this collection, such as body\ntemplates, archive moves and status cycling. TaskNotes reads them from\n`_settings/dev.tasknotes.md` and writes only the fields a save changes.\n" + } + ], + "provides": [ + { + "id": "tasknotes.task", + "version": "0.3.0-rc.6", + "digest": "sha256:c400ead6e218b715d86ad31125bb3d4b2e276817da6ba8065449fd0947b24d67" + }, + { + "id": "tasknotes.settings", + "version": "1.0.0", + "digest": "sha256:a61d55535871d27e9599cb3588148a0590d9e2198d6ee7a0bf3197350b60dc53" + }, + { + "id": "mdbase.app-settings", + "version": "1.0.0", + "digest": "sha256:4ae872a56290e2739ff876df1ca8fdac428753c854d65fd8e8e62045bd643a4e" + } + ] +} diff --git a/dist/schemas/mdbase.app-settings/1.0.0.schema.json b/dist/schemas/mdbase.app-settings/1.0.0.schema.json new file mode 100644 index 0000000..d548b11 --- /dev/null +++ b/dist/schemas/mdbase.app-settings/1.0.0.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "mdbase.app-settings 1.0.0 record contract view", + "description": "The reserved fields every app settings record shares. Everything else in the record belongs to the app and is described by the app's own settings contract.", + "type": "object", + "required": ["app", "scope", "settings_version"], + "properties": { + "app": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$", + "description": "The app whose clients honour these settings, such as tasknotes or dev.mdbase.reader." + }, + "scope": { + "enum": ["collection", "user"], + "description": "Who the values apply to: everyone using the app in this collection, or one person." + }, + "user": { + "type": "string", + "minLength": 1, + "description": "A link to the mdbase.person record the values apply to. Present only when scope is user." + }, + "settings_version": { + "type": "integer", + "minimum": 1, + "description": "The version of the app's settings schema that last wrote the record. A client that does not understand it treats the settings as read-only." + } + }, + "allOf": [ + { + "if": { "properties": { "scope": { "const": "user" } }, "required": ["scope"] }, + "then": { "required": ["user"] }, + "else": { "not": { "required": ["user"] } } + } + ], + "additionalProperties": true +} diff --git a/dist/schemas/tasknotes.settings/1.0.0.schema.json b/dist/schemas/tasknotes.settings/1.0.0.schema.json new file mode 100644 index 0000000..c1bcb16 --- /dev/null +++ b/dist/schemas/tasknotes.settings/1.0.0.schema.json @@ -0,0 +1,141 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "tasknotes.settings 1.0.0", + "description": "Collection-wide behaviour that every TaskNotes client honours. Every field is optional and has a default, so a record with none of them behaves like no record at all.", + "type": "object", + "required": [ + "app", + "scope", + "settings_version" + ], + "properties": { + "app": { + "const": "dev.tasknotes", + "description": "Marks this record as TaskNotes' settings." + }, + "scope": { + "const": "collection", + "description": "These settings apply to everyone using TaskNotes in this collection." + }, + "settings_version": { + "type": "integer", + "minimum": 1, + "description": "The version of these settings that last wrote the record. TaskNotes writes 1." + }, + "nlp_triggers": { + "type": "array", + "items": { + "type": "object", + "required": [ + "property_id", + "trigger", + "enabled" + ], + "properties": { + "property_id": { + "type": "string", + "minLength": 1 + }, + "trigger": { + "type": "string", + "minLength": 1 + }, + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "description": "Natural-language capture triggers, such as @ for contexts. Without the field each client uses its own defaults." + }, + "template_enabled": { + "type": "boolean", + "default": false, + "description": "Apply template_path to the body of new tasks." + }, + "template_path": { + "type": "string", + "description": "The template for new task bodies. Empty or absent means none." + }, + "occurrence_template_enabled": { + "type": "boolean", + "default": false, + "description": "Apply occurrence_template_path to new materialized occurrences." + }, + "occurrence_template_path": { + "type": "string", + "description": "The template for new occurrence bodies. Empty or absent means none." + }, + "template_failure_mode": { + "enum": [ + "error", + "warning_fallback" + ], + "description": "What a client does when a template cannot be applied." + }, + "template_unknown_variable_policy": { + "enum": [ + "preserve", + "empty" + ], + "description": "What a client writes for a template variable it does not know." + }, + "move_on_archive": { + "type": "boolean", + "default": false, + "description": "Move a task's file to archive_folder when it is archived." + }, + "archive_folder": { + "type": "string", + "description": "Where archived tasks move to. Empty or absent means the client's default." + }, + "auto_stop_time_tracking_on_complete": { + "type": "boolean", + "default": false, + "description": "Stop a running timer when its task is completed." + }, + "reset_body_checkboxes_on_recurrence": { + "type": "boolean", + "default": false, + "description": "Uncheck body checkboxes when a recurring task moves to its next occurrence." + }, + "link_write_format": { + "enum": [ + "wikilink", + "markdown" + ], + "default": "wikilink", + "description": "How clients write links into task frontmatter. Both formats are always read." + }, + "status_behavior": { + "type": "object", + "description": "Behaviour per status value. A status without an entry has no next status and no auto-archive, and is out of the status cycle exactly when it is a skipped status.", + "additionalProperties": { + "type": "object", + "properties": { + "next_status": { + "type": "string", + "minLength": 1, + "description": "The status the cycle moves to next." + }, + "exclude_from_cycle": { + "type": "boolean", + "description": "Leave this status out of the status cycle." + }, + "auto_archive": { + "type": "boolean", + "description": "Archive a task some time after it takes this status." + }, + "auto_archive_delay_minutes": { + "type": "number", + "minimum": 0, + "description": "How long after taking this status a task is archived." + } + }, + "additionalProperties": false + }, + "default": {} + } + }, + "additionalProperties": true +} diff --git a/dist/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json b/dist/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json new file mode 100644 index 0000000..b817391 --- /dev/null +++ b/dist/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json @@ -0,0 +1,343 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://tasknotes.dev/schemas/tasknotes-task-binding.schema.json", + "title": "TaskNotes task data-contract binding", + "description": "Semantic configuration supplied by an mdbase type that implements tasknotes.task 0.3.0-rc.6. App behaviour, such as templates, archive moves, status cycling and natural-language triggers, lives in the app's tasknotes.settings record instead.", + "type": "object", + "required": [ + "profiles", + "capabilities", + "title", + "status", + "priority", + "recurrence", + "occurrences", + "links", + "archive" + ], + "properties": { + "profiles": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "enum": [ + "core-lite", + "recurrence", + "templating", + "materialized-occurrences", + "extended" + ] + } + }, + "capabilities": { + "type": "array", + "uniqueItems": true, + "items": { + "enum": [ + "dependencies", + "reminders", + "attachments", + "links", + "time-tracking", + "materialized-occurrences", + "rename", + "archive", + "batch", + "concurrency", + "dry-run", + "migration", + "templating" + ] + } + }, + "title": { + "$ref": "#/$defs/titlePolicy" + }, + "status": { + "$ref": "#/$defs/statusPolicy" + }, + "priority": { + "$ref": "#/$defs/priorityPolicy" + }, + "recurrence": { + "$ref": "#/$defs/recurrencePolicy" + }, + "occurrences": { + "$ref": "#/$defs/occurrencePolicy" + }, + "links": { + "$ref": "#/$defs/linkPolicy" + }, + "archive": { + "$ref": "#/$defs/archivePolicy" + } + }, + "additionalProperties": false, + "$defs": { + "nonEmptyString": { + "type": "string", + "minLength": 1 + }, + "stringSet": { + "type": "array", + "uniqueItems": true, + "items": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "titlePolicy": { + "type": "object", + "required": [ + "storage" + ], + "properties": { + "storage": { + "enum": [ + "filename", + "frontmatter" + ] + }, + "filename_format": { + "enum": [ + "title", + "zettel", + "timestamp", + "uuid", + "custom" + ] + }, + "custom_filename_template": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "allOf": [ + { + "if": { + "properties": { + "filename_format": { + "const": "custom" + } + }, + "required": [ + "filename_format" + ] + }, + "then": { + "properties": { + "custom_filename_template": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "required": [ + "custom_filename_template" + ] + } + } + ], + "additionalProperties": true + }, + "statusDefinition": { + "type": "object", + "required": [ + "value", + "label", + "color", + "is_completed", + "is_skipped", + "order" + ], + "properties": { + "value": { + "$ref": "#/$defs/nonEmptyString" + }, + "label": { + "type": "string" + }, + "color": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/nonEmptyString" + }, + "is_completed": { + "type": "boolean" + }, + "is_skipped": { + "type": "boolean" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": true + }, + "statusPolicy": { + "type": "object", + "required": [ + "values", + "default", + "completed_values", + "definitions" + ], + "properties": { + "values": { + "$ref": "#/$defs/stringSet" + }, + "default": { + "$ref": "#/$defs/nonEmptyString" + }, + "completed_values": { + "$ref": "#/$defs/stringSet" + }, + "skipped_values": { + "$ref": "#/$defs/stringSet" + }, + "default_skipped": { + "$ref": "#/$defs/nonEmptyString" + }, + "definitions": { + "type": "array", + "items": { + "$ref": "#/$defs/statusDefinition" + } + } + }, + "additionalProperties": false + }, + "priorityDefinition": { + "type": "object", + "required": [ + "value", + "label", + "color", + "weight" + ], + "properties": { + "value": { + "$ref": "#/$defs/nonEmptyString" + }, + "label": { + "type": "string" + }, + "color": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/nonEmptyString" + }, + "weight": { + "type": "number" + } + }, + "additionalProperties": true + }, + "priorityPolicy": { + "type": "object", + "required": [ + "values", + "default", + "definitions" + ], + "properties": { + "values": { + "$ref": "#/$defs/stringSet" + }, + "default": { + "$ref": "#/$defs/nonEmptyString" + }, + "definitions": { + "type": "array", + "items": { + "$ref": "#/$defs/priorityDefinition" + } + } + }, + "additionalProperties": false + }, + "recurrencePolicy": { + "type": "object", + "required": [ + "syntax", + "maintain_due_date_offset" + ], + "properties": { + "syntax": { + "const": "tasknotes" + }, + "maintain_due_date_offset": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "occurrencePolicy": { + "type": "object", + "required": [ + "identity_roles", + "default_materialization", + "default_next_trigger" + ], + "properties": { + "identity_roles": { + "const": [ + "recurrenceParent", + "occurrenceDate" + ] + }, + "default_materialization": { + "enum": [ + "manual", + "on_completion", + "rolling" + ] + }, + "default_next_trigger": { + "enum": [ + "completion", + "completion_or_skip" + ] + }, + "past_horizon": { + "$ref": "#/$defs/nonEmptyString" + }, + "future_horizon": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "additionalProperties": false + }, + "linkPolicy": { + "type": "object", + "required": [ + "accepted_formats" + ], + "properties": { + "accepted_formats": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "enum": [ + "wikilink", + "markdown" + ] + } + } + }, + "additionalProperties": false + }, + "archivePolicy": { + "type": "object", + "required": [ + "archived_tag" + ], + "properties": { + "archived_tag": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "additionalProperties": false + } + } +} diff --git a/dist/schemas/tasknotes.task/0.3.0-rc.6.schema.json b/dist/schemas/tasknotes.task/0.3.0-rc.6.schema.json new file mode 100644 index 0000000..7575372 --- /dev/null +++ b/dist/schemas/tasknotes.task/0.3.0-rc.6.schema.json @@ -0,0 +1,202 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://tasknotes.dev/schemas/tasknotes-task.schema.json", + "title": "TaskNotes portable task view", + "description": "The storage-neutral record view exposed by the tasknotes.task 0.3.0-rc.6 record contract.", + "type": "object", + "required": [ + "status", + "dateCreated" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "status": { + "type": "string", + "minLength": 1 + }, + "priority": { + "type": "string", + "minLength": 1 + }, + "due": { + "anyOf": [ + { + "type": "string", + "format": "date" + }, + { + "type": "string", + "format": "date-time" + } + ] + }, + "scheduled": { + "anyOf": [ + { + "type": "string", + "format": "date" + }, + { + "type": "string", + "format": "date-time" + } + ] + }, + "contexts": { + "type": "array", + "items": { + "type": "string" + } + }, + "projects": { + "type": "array", + "items": { + "type": "string" + } + }, + "assignees": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "pattern": "\\S" + }, + "description": "Links to records implementing mdbase.person, such as [[Alex Rivera]]. Implementing types declare this field in collection.links. These references never grant collection access." + }, + "attachments": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1 + } + }, + "timeEstimate": { + "type": "integer", + "minimum": 0 + }, + "completedDate": { + "type": "string", + "format": "date" + }, + "dateCreated": { + "type": "string", + "format": "date-time" + }, + "dateModified": { + "type": "string", + "format": "date-time" + }, + "recurrence": { + "type": "string" + }, + "recurrenceAnchor": { + "enum": [ + "scheduled", + "completion" + ] + }, + "recurrenceParent": { + "type": "string" + }, + "occurrenceDate": { + "type": "string", + "format": "date" + }, + "occurrenceMaterialization": { + "enum": [ + "manual", + "on_completion", + "rolling" + ] + }, + "occurrenceNextTrigger": { + "enum": [ + "completion", + "completion_or_skip" + ] + }, + "occurrenceTemplate": { + "type": "string" + }, + "occurrencePastHorizon": { + "type": "string" + }, + "occurrenceFutureHorizon": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "timeEntries": { + "type": "array", + "items": { + "type": "object" + } + }, + "reminders": { + "type": "array", + "items": { + "type": "object" + } + }, + "blockedBy": { + "type": "array", + "items": { + "type": "object" + } + }, + "completeInstances": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "skippedInstances": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "icsEventId": { + "type": "array", + "items": { + "type": "string" + } + }, + "googleCalendarEventId": { + "type": "string" + }, + "googleCalendarExceptionEventId": { + "type": "string" + }, + "googleCalendarExceptionOriginalScheduled": { + "type": "string", + "format": "date" + }, + "googleCalendarMovedOriginalDates": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "sortOrder": { + "type": "string" + } + } +} diff --git a/packs/tasknotes.task/0.3.0-rc.18.pack.yaml b/packs/tasknotes.task/0.3.0-rc.18.pack.yaml index ecc5c90..2614421 100644 --- a/packs/tasknotes.task/0.3.0-rc.18.pack.yaml +++ b/packs/tasknotes.task/0.3.0-rc.18.pack.yaml @@ -12,7 +12,7 @@ display: badges: - TaskNotes compatible installation: - visibility: default + visibility: hidden recommendation: integration-managed primary_type: task caution: Upgrades the previous starter type while preserving independent customizations. Conflicts or other references to the previous contract block the whole upgrade. diff --git a/packs/tasknotes.task/0.3.0-rc.19.pack.yaml b/packs/tasknotes.task/0.3.0-rc.19.pack.yaml new file mode 100644 index 0000000..125665d --- /dev/null +++ b/packs/tasknotes.task/0.3.0-rc.19.pack.yaml @@ -0,0 +1,77 @@ +kind: mdbase.catalog-pack +id: tasknotes.task +version: 0.3.0-rc.19 +name: TaskNotes task type pack +description: Portable tasks whose app behaviour (templates, archive moves, status cycling, time tracking and link format) lives in a TaskNotes settings record, with a reviewed, atomic upgrade from every TaskNotes starter published before. +display: + name: TaskNotes tasks + summary: Manage portable Markdown tasks, assignments, dates, recurrence, reminders, and time tracking. + category: work + audience: general + icon: square-check-big + badges: + - TaskNotes compatible +installation: + visibility: default + recommendation: integration-managed + primary_type: task + caution: Upgrades the previous starter type while preserving independent customizations. Conflicts block the whole upgrade. TaskNotes moves settings an edited type still holds into its settings record when it upgrades that type. +provides: + - id: tasknotes.task + version: 0.3.0-rc.6 + digest: sha256:c400ead6e218b715d86ad31125bb3d4b2e276817da6ba8065449fd0947b24d67 + - id: tasknotes.settings + version: 1.0.0 + - id: mdbase.app-settings + version: 1.0.0 +resources: + # Not provided for new installs: retained so task types still implementing + # rc.5 (customised, or written by TaskNotes before it upgrades them) keep the + # exact contract they implement. + - kind: contract + mode: managed + source: contracts/tasknotes.task/0.3.0-rc.5.md + target: _contracts/tasknotes.task.md + - kind: contract + mode: managed + source: contracts/tasknotes.task/0.3.0-rc.6.md + target: _contracts/tasknotes.task/0.3.0-rc.6.md + - kind: type + mode: seed + source: types/tasknotes-task/6.md + target: _types/task.md + # Every starter an earlier tasknotes.task pack seeded at _types/task.md. + upgrade_from: + - types/tasknotes-task/5.md + - types/tasknotes-task/4.md + - types/tasknotes-task/3.md + - types/tasknotes-task/2.md + - types/tasknotes-task/1.md + - kind: schema + mode: managed + source: schemas/tasknotes.task/0.3.0-rc.6.schema.json + target: _schemas/tasknotes/tasknotes-task.schema.json + - kind: schema + mode: managed + source: schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json + target: _schemas/tasknotes/tasknotes-task-binding.schema.json + - kind: schema + mode: managed + source: schemas/mdbase.app-settings/1.0.0.schema.json + target: schemas/mdbase.app-settings/1.0.0.schema.json + - kind: contract + mode: managed + source: contracts/mdbase.app-settings/1.0.0.md + target: _contracts/mdbase.app-settings/1.0.0.md + - kind: schema + mode: managed + source: schemas/tasknotes.settings/1.0.0.schema.json + target: schemas/tasknotes.settings/1.0.0.schema.json + - kind: contract + mode: managed + source: contracts/tasknotes.settings/1.0.0.md + target: _contracts/tasknotes.settings/1.0.0.md + - kind: type + mode: seed + source: types/tasknotes-settings/1.md + target: _types/tasknotes-settings.md diff --git a/schemas/mdbase.app-settings/1.0.0.schema.json b/schemas/mdbase.app-settings/1.0.0.schema.json new file mode 100644 index 0000000..d548b11 --- /dev/null +++ b/schemas/mdbase.app-settings/1.0.0.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "mdbase.app-settings 1.0.0 record contract view", + "description": "The reserved fields every app settings record shares. Everything else in the record belongs to the app and is described by the app's own settings contract.", + "type": "object", + "required": ["app", "scope", "settings_version"], + "properties": { + "app": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$", + "description": "The app whose clients honour these settings, such as tasknotes or dev.mdbase.reader." + }, + "scope": { + "enum": ["collection", "user"], + "description": "Who the values apply to: everyone using the app in this collection, or one person." + }, + "user": { + "type": "string", + "minLength": 1, + "description": "A link to the mdbase.person record the values apply to. Present only when scope is user." + }, + "settings_version": { + "type": "integer", + "minimum": 1, + "description": "The version of the app's settings schema that last wrote the record. A client that does not understand it treats the settings as read-only." + } + }, + "allOf": [ + { + "if": { "properties": { "scope": { "const": "user" } }, "required": ["scope"] }, + "then": { "required": ["user"] }, + "else": { "not": { "required": ["user"] } } + } + ], + "additionalProperties": true +} diff --git a/schemas/tasknotes.settings/1.0.0.schema.json b/schemas/tasknotes.settings/1.0.0.schema.json new file mode 100644 index 0000000..c1bcb16 --- /dev/null +++ b/schemas/tasknotes.settings/1.0.0.schema.json @@ -0,0 +1,141 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "tasknotes.settings 1.0.0", + "description": "Collection-wide behaviour that every TaskNotes client honours. Every field is optional and has a default, so a record with none of them behaves like no record at all.", + "type": "object", + "required": [ + "app", + "scope", + "settings_version" + ], + "properties": { + "app": { + "const": "dev.tasknotes", + "description": "Marks this record as TaskNotes' settings." + }, + "scope": { + "const": "collection", + "description": "These settings apply to everyone using TaskNotes in this collection." + }, + "settings_version": { + "type": "integer", + "minimum": 1, + "description": "The version of these settings that last wrote the record. TaskNotes writes 1." + }, + "nlp_triggers": { + "type": "array", + "items": { + "type": "object", + "required": [ + "property_id", + "trigger", + "enabled" + ], + "properties": { + "property_id": { + "type": "string", + "minLength": 1 + }, + "trigger": { + "type": "string", + "minLength": 1 + }, + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "description": "Natural-language capture triggers, such as @ for contexts. Without the field each client uses its own defaults." + }, + "template_enabled": { + "type": "boolean", + "default": false, + "description": "Apply template_path to the body of new tasks." + }, + "template_path": { + "type": "string", + "description": "The template for new task bodies. Empty or absent means none." + }, + "occurrence_template_enabled": { + "type": "boolean", + "default": false, + "description": "Apply occurrence_template_path to new materialized occurrences." + }, + "occurrence_template_path": { + "type": "string", + "description": "The template for new occurrence bodies. Empty or absent means none." + }, + "template_failure_mode": { + "enum": [ + "error", + "warning_fallback" + ], + "description": "What a client does when a template cannot be applied." + }, + "template_unknown_variable_policy": { + "enum": [ + "preserve", + "empty" + ], + "description": "What a client writes for a template variable it does not know." + }, + "move_on_archive": { + "type": "boolean", + "default": false, + "description": "Move a task's file to archive_folder when it is archived." + }, + "archive_folder": { + "type": "string", + "description": "Where archived tasks move to. Empty or absent means the client's default." + }, + "auto_stop_time_tracking_on_complete": { + "type": "boolean", + "default": false, + "description": "Stop a running timer when its task is completed." + }, + "reset_body_checkboxes_on_recurrence": { + "type": "boolean", + "default": false, + "description": "Uncheck body checkboxes when a recurring task moves to its next occurrence." + }, + "link_write_format": { + "enum": [ + "wikilink", + "markdown" + ], + "default": "wikilink", + "description": "How clients write links into task frontmatter. Both formats are always read." + }, + "status_behavior": { + "type": "object", + "description": "Behaviour per status value. A status without an entry has no next status and no auto-archive, and is out of the status cycle exactly when it is a skipped status.", + "additionalProperties": { + "type": "object", + "properties": { + "next_status": { + "type": "string", + "minLength": 1, + "description": "The status the cycle moves to next." + }, + "exclude_from_cycle": { + "type": "boolean", + "description": "Leave this status out of the status cycle." + }, + "auto_archive": { + "type": "boolean", + "description": "Archive a task some time after it takes this status." + }, + "auto_archive_delay_minutes": { + "type": "number", + "minimum": 0, + "description": "How long after taking this status a task is archived." + } + }, + "additionalProperties": false + }, + "default": {} + } + }, + "additionalProperties": true +} diff --git a/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json b/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json new file mode 100644 index 0000000..b817391 --- /dev/null +++ b/schemas/tasknotes.task.binding/0.3.0-rc.6.schema.json @@ -0,0 +1,343 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://tasknotes.dev/schemas/tasknotes-task-binding.schema.json", + "title": "TaskNotes task data-contract binding", + "description": "Semantic configuration supplied by an mdbase type that implements tasknotes.task 0.3.0-rc.6. App behaviour, such as templates, archive moves, status cycling and natural-language triggers, lives in the app's tasknotes.settings record instead.", + "type": "object", + "required": [ + "profiles", + "capabilities", + "title", + "status", + "priority", + "recurrence", + "occurrences", + "links", + "archive" + ], + "properties": { + "profiles": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "enum": [ + "core-lite", + "recurrence", + "templating", + "materialized-occurrences", + "extended" + ] + } + }, + "capabilities": { + "type": "array", + "uniqueItems": true, + "items": { + "enum": [ + "dependencies", + "reminders", + "attachments", + "links", + "time-tracking", + "materialized-occurrences", + "rename", + "archive", + "batch", + "concurrency", + "dry-run", + "migration", + "templating" + ] + } + }, + "title": { + "$ref": "#/$defs/titlePolicy" + }, + "status": { + "$ref": "#/$defs/statusPolicy" + }, + "priority": { + "$ref": "#/$defs/priorityPolicy" + }, + "recurrence": { + "$ref": "#/$defs/recurrencePolicy" + }, + "occurrences": { + "$ref": "#/$defs/occurrencePolicy" + }, + "links": { + "$ref": "#/$defs/linkPolicy" + }, + "archive": { + "$ref": "#/$defs/archivePolicy" + } + }, + "additionalProperties": false, + "$defs": { + "nonEmptyString": { + "type": "string", + "minLength": 1 + }, + "stringSet": { + "type": "array", + "uniqueItems": true, + "items": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "titlePolicy": { + "type": "object", + "required": [ + "storage" + ], + "properties": { + "storage": { + "enum": [ + "filename", + "frontmatter" + ] + }, + "filename_format": { + "enum": [ + "title", + "zettel", + "timestamp", + "uuid", + "custom" + ] + }, + "custom_filename_template": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "allOf": [ + { + "if": { + "properties": { + "filename_format": { + "const": "custom" + } + }, + "required": [ + "filename_format" + ] + }, + "then": { + "properties": { + "custom_filename_template": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "required": [ + "custom_filename_template" + ] + } + } + ], + "additionalProperties": true + }, + "statusDefinition": { + "type": "object", + "required": [ + "value", + "label", + "color", + "is_completed", + "is_skipped", + "order" + ], + "properties": { + "value": { + "$ref": "#/$defs/nonEmptyString" + }, + "label": { + "type": "string" + }, + "color": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/nonEmptyString" + }, + "is_completed": { + "type": "boolean" + }, + "is_skipped": { + "type": "boolean" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": true + }, + "statusPolicy": { + "type": "object", + "required": [ + "values", + "default", + "completed_values", + "definitions" + ], + "properties": { + "values": { + "$ref": "#/$defs/stringSet" + }, + "default": { + "$ref": "#/$defs/nonEmptyString" + }, + "completed_values": { + "$ref": "#/$defs/stringSet" + }, + "skipped_values": { + "$ref": "#/$defs/stringSet" + }, + "default_skipped": { + "$ref": "#/$defs/nonEmptyString" + }, + "definitions": { + "type": "array", + "items": { + "$ref": "#/$defs/statusDefinition" + } + } + }, + "additionalProperties": false + }, + "priorityDefinition": { + "type": "object", + "required": [ + "value", + "label", + "color", + "weight" + ], + "properties": { + "value": { + "$ref": "#/$defs/nonEmptyString" + }, + "label": { + "type": "string" + }, + "color": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/nonEmptyString" + }, + "weight": { + "type": "number" + } + }, + "additionalProperties": true + }, + "priorityPolicy": { + "type": "object", + "required": [ + "values", + "default", + "definitions" + ], + "properties": { + "values": { + "$ref": "#/$defs/stringSet" + }, + "default": { + "$ref": "#/$defs/nonEmptyString" + }, + "definitions": { + "type": "array", + "items": { + "$ref": "#/$defs/priorityDefinition" + } + } + }, + "additionalProperties": false + }, + "recurrencePolicy": { + "type": "object", + "required": [ + "syntax", + "maintain_due_date_offset" + ], + "properties": { + "syntax": { + "const": "tasknotes" + }, + "maintain_due_date_offset": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "occurrencePolicy": { + "type": "object", + "required": [ + "identity_roles", + "default_materialization", + "default_next_trigger" + ], + "properties": { + "identity_roles": { + "const": [ + "recurrenceParent", + "occurrenceDate" + ] + }, + "default_materialization": { + "enum": [ + "manual", + "on_completion", + "rolling" + ] + }, + "default_next_trigger": { + "enum": [ + "completion", + "completion_or_skip" + ] + }, + "past_horizon": { + "$ref": "#/$defs/nonEmptyString" + }, + "future_horizon": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "additionalProperties": false + }, + "linkPolicy": { + "type": "object", + "required": [ + "accepted_formats" + ], + "properties": { + "accepted_formats": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "enum": [ + "wikilink", + "markdown" + ] + } + } + }, + "additionalProperties": false + }, + "archivePolicy": { + "type": "object", + "required": [ + "archived_tag" + ], + "properties": { + "archived_tag": { + "$ref": "#/$defs/nonEmptyString" + } + }, + "additionalProperties": false + } + } +} diff --git a/schemas/tasknotes.task/0.3.0-rc.6.schema.json b/schemas/tasknotes.task/0.3.0-rc.6.schema.json new file mode 100644 index 0000000..7575372 --- /dev/null +++ b/schemas/tasknotes.task/0.3.0-rc.6.schema.json @@ -0,0 +1,202 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://tasknotes.dev/schemas/tasknotes-task.schema.json", + "title": "TaskNotes portable task view", + "description": "The storage-neutral record view exposed by the tasknotes.task 0.3.0-rc.6 record contract.", + "type": "object", + "required": [ + "status", + "dateCreated" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "status": { + "type": "string", + "minLength": 1 + }, + "priority": { + "type": "string", + "minLength": 1 + }, + "due": { + "anyOf": [ + { + "type": "string", + "format": "date" + }, + { + "type": "string", + "format": "date-time" + } + ] + }, + "scheduled": { + "anyOf": [ + { + "type": "string", + "format": "date" + }, + { + "type": "string", + "format": "date-time" + } + ] + }, + "contexts": { + "type": "array", + "items": { + "type": "string" + } + }, + "projects": { + "type": "array", + "items": { + "type": "string" + } + }, + "assignees": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "pattern": "\\S" + }, + "description": "Links to records implementing mdbase.person, such as [[Alex Rivera]]. Implementing types declare this field in collection.links. These references never grant collection access." + }, + "attachments": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1 + } + }, + "timeEstimate": { + "type": "integer", + "minimum": 0 + }, + "completedDate": { + "type": "string", + "format": "date" + }, + "dateCreated": { + "type": "string", + "format": "date-time" + }, + "dateModified": { + "type": "string", + "format": "date-time" + }, + "recurrence": { + "type": "string" + }, + "recurrenceAnchor": { + "enum": [ + "scheduled", + "completion" + ] + }, + "recurrenceParent": { + "type": "string" + }, + "occurrenceDate": { + "type": "string", + "format": "date" + }, + "occurrenceMaterialization": { + "enum": [ + "manual", + "on_completion", + "rolling" + ] + }, + "occurrenceNextTrigger": { + "enum": [ + "completion", + "completion_or_skip" + ] + }, + "occurrenceTemplate": { + "type": "string" + }, + "occurrencePastHorizon": { + "type": "string" + }, + "occurrenceFutureHorizon": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "timeEntries": { + "type": "array", + "items": { + "type": "object" + } + }, + "reminders": { + "type": "array", + "items": { + "type": "object" + } + }, + "blockedBy": { + "type": "array", + "items": { + "type": "object" + } + }, + "completeInstances": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "skippedInstances": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "icsEventId": { + "type": "array", + "items": { + "type": "string" + } + }, + "googleCalendarEventId": { + "type": "string" + }, + "googleCalendarExceptionEventId": { + "type": "string" + }, + "googleCalendarExceptionOriginalScheduled": { + "type": "string", + "format": "date" + }, + "googleCalendarMovedOriginalDates": { + "type": "array", + "items": { + "type": "string", + "format": "date" + } + }, + "sortOrder": { + "type": "string" + } + } +} diff --git a/scripts/sync-tasknotes-pack.mjs b/scripts/sync-tasknotes-pack.mjs index 9b45f85..aed8e05 100644 --- a/scripts/sync-tasknotes-pack.mjs +++ b/scripts/sync-tasknotes-pack.mjs @@ -8,7 +8,9 @@ const { buildTaskNotesMdbaseTypePack, TASKNOTES_TASK_CONTRACT_VERSION } = await // The published starter, not the model's plugin defaults: those omit the // cancelled status and declare profiles the starter does not implement. const { buildTaskNotesStarterResources, TASKNOTES_STARTER_REVISION } = await import(pathToFileURL(join(model, "dist/esm/starter.js")).href); +const { buildTaskNotesSettingsResources, TASKNOTES_SETTINGS_CONTRACT_VERSION, TASKNOTES_SETTINGS_TYPE_VERSION } = await import(pathToFileURL(join(model, "dist/esm/settings.js")).href); const resources = buildTaskNotesStarterResources(); +const settings = buildTaskNotesSettingsResources(); // Also verifies the model's pinned semantic digest before importing anything. await buildTaskNotesMdbaseTypePack(resources); const version = TASKNOTES_TASK_CONTRACT_VERSION; @@ -18,6 +20,10 @@ for (const [path, document] of [ [`schemas/tasknotes.task.binding/${version}.schema.json`, resources.bindingSchemaDocument], // Named by starter revision: a revision may keep the type version. [`types/tasknotes-task/${TASKNOTES_STARTER_REVISION}.md`, resources.typeDocument], + // The app settings record type (tasknotes.settings + mdbase.app-settings). + [`contracts/tasknotes.settings/${TASKNOTES_SETTINGS_CONTRACT_VERSION}.md`, settings.contractDocument], + [`schemas/tasknotes.settings/${TASKNOTES_SETTINGS_CONTRACT_VERSION}.schema.json`, settings.schemaDocument], + [`types/tasknotes-settings/${TASKNOTES_SETTINGS_TYPE_VERSION}.md`, settings.typeDocument], ]) { const destination = join(root, path); let previous; diff --git a/scripts/tasknotes-plugin-collections.test.mjs b/scripts/tasknotes-plugin-collections.test.mjs index 58c4ecb..536c5ba 100644 --- a/scripts/tasknotes-plugin-collections.test.mjs +++ b/scripts/tasknotes-plugin-collections.test.mjs @@ -9,7 +9,7 @@ import { packEngine } from "./pack-engine.mjs"; // TaskNotes 4.13.6 and the 5.0 betas, with default and customized settings). // Every TaskNotes pack must install over them, as TaskNotes App does through // Connect, without conflicts and without dropping statuses or touching records. -const LATEST = "0.3.0-rc.18"; +const LATEST = "0.3.0-rc.19"; const fixtures = new URL("./fixtures/tasknotes-5.0/", import.meta.url); async function reviewedInstall(engine) { @@ -50,13 +50,18 @@ for (const name of (await readdir(fixtures)).filter((file) => file.endsWith(".js if (starter) { assert.equal(planned.action, "update"); assert.equal(type, provision.resources.find(({ source }) => source === seed.source).document); + assert.match(type, /version: 0\.3\.0-rc\.6/); } else { + // A preserved type keeps implementing rc.5, whose contract the pack + // retains; TaskNotes upgrades it and writes the settings record. assert.equal(planned.action, "preserve"); assert.match(planned.reason, /no upgrade baseline applies/); assert.equal(type, files["_types/task.md"]); + assert.match(type, /version: 0\.3\.0-rc\.5/); + assert.match(await readFile(join(root, "_contracts/tasknotes.task.md"), "utf8"), /version: 0\.3\.0-rc\.5/); } if (files["_types/task.md"].includes("- cancelled")) assert.match(type, /- cancelled/); - assert.match(type, /version: 0\.3\.0-rc\.5/); + assert.match(await readFile(join(root, "_types/tasknotes-settings.md"), "utf8"), /name: tasknotes-settings/); for (const path of Object.keys(files).filter((path) => !path.startsWith("_") && !path.startsWith("mdbase"))) { assert.equal(await readFile(join(root, path), "utf8"), files[path], path); } diff --git a/scripts/tasknotes-upgrade.test.mjs b/scripts/tasknotes-upgrade.test.mjs index 7259e6c..a7d77e9 100644 --- a/scripts/tasknotes-upgrade.test.mjs +++ b/scripts/tasknotes-upgrade.test.mjs @@ -30,10 +30,28 @@ const targets = [ { pack: "0.3.0-rc.17", contract: /0\.3\.0-rc\.5/, links: /assignees\[\]:/, minimal: true, customMapping: true }, // rc.18 ships rc.17's starter and lists every earlier starter as a baseline. { pack: "0.3.0-rc.18", contract: /0\.3\.0-rc\.5/, links: /assignees\[\]:/, minimal: true, customMapping: true }, + // rc.19 (tasknotes.task rc.6) moves app behaviour out of the binding into + // the TaskNotes settings record; nothing else in the starter changes. + { pack: "0.3.0-rc.19", contract: /0\.3\.0-rc\.6/, links: /assignees\[\]:/, minimal: true, customMapping: true, settingsRecord: true }, ]; -// Everything an upgrade may change in the starter type: assignees and versions. -function withoutAssignees(document) { +// The binding settings tasknotes.task rc.6 moved to the TaskNotes settings record. +function withoutAppSettings(type) { + const binding = type.implements.find((entry) => entry.contract === "tasknotes.task").binding; + for (const key of ["nlp", "templating", "time_tracking"]) delete binding[key]; + delete binding.archive?.move_on_archive; + delete binding.archive?.folder; + delete binding.recurrence?.reset_body_checkboxes; + delete binding.links?.write_format; + for (const definition of binding.status?.definitions ?? []) { + for (const key of ["next_status", "exclude_from_cycle", "auto_archive", "auto_archive_delay_minutes"]) delete definition[key]; + } + return type; +} + +// Everything an upgrade may change in the starter type: assignees, versions +// and (from rc.19) the settings moved to the settings record. +function withoutAssignees(document, settingsRecord = false) { const type = parse(document.slice(4, document.indexOf("\n---", 4))); delete type.version; delete type.schema.value.properties.assignees; @@ -42,7 +60,7 @@ function withoutAssignees(document) { delete implementation.version; delete implementation.fields.assignees; type["x-tasknotes-generator"].managed_fields = type["x-tasknotes-generator"].managed_fields.filter((field) => field !== "assignees"); - return type; + return settingsRecord ? withoutAppSettings(type) : type; } for (const target of targets) for (const scenario of ["managed", "customized", "customized-without-origin", "generator-defaults", "custom-mapping", "unmanaged", "conflict", "other-reference"]) { if (scenario === "generator-defaults" && !target.minimal) continue; @@ -103,8 +121,16 @@ for (const target of targets) for (const scenario of ["managed", "customized", " // 05A) is never merged against a guessed baseline. It is preserved, and as // it still requires the replaced contract the whole upgrade is blocked, // exactly as for any other reference to that contract. - const success = !["conflict", "other-reference", "customized-without-origin"].includes(scenario); + // rc.19 changes the starter's status definitions (their behaviour moved + // to the settings record), and a collection that also edited them (here, + // colours) conflicts on that list: the upgrade is blocked, the collection + // keeps its rc.5 type, and TaskNotes upgrades it itself. + const definitionsConflict = target.settingsRecord && scenario === "generator-defaults"; + const success = !["conflict", "other-reference", "customized-without-origin"].includes(scenario) && !definitionsConflict; assert.equal(result.valid, success, JSON.stringify(result)); + if (definitionsConflict) { + assert.match(JSON.stringify(result.diagnostics), /binding\/status\/definitions/); + } if (scenario === "customized-without-origin") { assert.match(JSON.stringify(result.diagnostics), /tasknotes\.task.{1,4}0\.3\.0-rc\.3/); } @@ -117,9 +143,18 @@ for (const target of targets) for (const scenario of ["managed", "customized", " assert.match(upgraded, target.contract); if (target.links) assert.match(upgraded, target.links); if (target.minimal) { - assert.deepEqual(withoutAssignees(upgraded), withoutAssignees(new Map(before).get("_types/task.md"))); + assert.deepEqual( + withoutAssignees(upgraded, target.settingsRecord), + withoutAssignees(new Map(before).get("_types/task.md"), target.settingsRecord), + ); assert.match(upgraded, /- cancelled/); } + if (target.settingsRecord) { + // The settings type is seeded; the record itself is the app's to write. + assert.match(await readFile(join(root, "_types/tasknotes-settings.md"), "utf8"), /tasknotes\.settings/); + assert.doesNotMatch(upgraded, /move_on_archive|time_tracking|templating:/); + await assert.rejects(readFile(join(root, "_settings/dev.tasknotes.md"), "utf8"), { code: "ENOENT" }); + } if (scenario === "customized") { assert.match(upgraded, /title: heading/); assert.ok(upgraded.endsWith("Custom documentation.\n")); diff --git a/types/tasknotes-settings/1.md b/types/tasknotes-settings/1.md new file mode 100644 index 0000000..f4c7d80 --- /dev/null +++ b/types/tasknotes-settings/1.md @@ -0,0 +1,155 @@ +--- +kind: mdbase.type +name: tasknotes-settings +version: 1 +description: TaskNotes' collection-wide settings, one record at _settings/dev.tasknotes.md. +match: + where: + app: + eq: dev.tasknotes +schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + title: tasknotes.settings 1.0.0 + description: Collection-wide behaviour that every TaskNotes client honours. Every field is optional and has a default, so a record with none of them behaves like no record at all. + type: object + required: + - app + - scope + - settings_version + properties: + app: + const: dev.tasknotes + description: Marks this record as TaskNotes' settings. + scope: + const: collection + description: These settings apply to everyone using TaskNotes in this collection. + settings_version: + type: integer + minimum: 1 + description: The version of these settings that last wrote the record. TaskNotes writes 1. + nlp_triggers: + type: array + items: + type: object + required: + - property_id + - trigger + - enabled + properties: + property_id: + type: string + minLength: 1 + trigger: + type: string + minLength: 1 + enabled: + type: boolean + additionalProperties: false + description: Natural-language capture triggers, such as @ for contexts. Without the field each client uses its own defaults. + template_enabled: + type: boolean + default: false + description: Apply template_path to the body of new tasks. + template_path: + type: string + description: The template for new task bodies. Empty or absent means none. + occurrence_template_enabled: + type: boolean + default: false + description: Apply occurrence_template_path to new materialized occurrences. + occurrence_template_path: + type: string + description: The template for new occurrence bodies. Empty or absent means none. + template_failure_mode: + enum: + - error + - warning_fallback + description: What a client does when a template cannot be applied. + template_unknown_variable_policy: + enum: + - preserve + - empty + description: What a client writes for a template variable it does not know. + move_on_archive: + type: boolean + default: false + description: Move a task's file to archive_folder when it is archived. + archive_folder: + type: string + description: Where archived tasks move to. Empty or absent means the client's default. + auto_stop_time_tracking_on_complete: + type: boolean + default: false + description: Stop a running timer when its task is completed. + reset_body_checkboxes_on_recurrence: + type: boolean + default: false + description: Uncheck body checkboxes when a recurring task moves to its next occurrence. + link_write_format: + enum: + - wikilink + - markdown + default: wikilink + description: How clients write links into task frontmatter. Both formats are always read. + status_behavior: + type: object + description: Behaviour per status value. A status without an entry has no next status and no auto-archive, and is out of the status cycle exactly when it is a skipped status. + additionalProperties: + type: object + properties: + next_status: + type: string + minLength: 1 + description: The status the cycle moves to next. + exclude_from_cycle: + type: boolean + description: Leave this status out of the status cycle. + auto_archive: + type: boolean + description: Archive a task some time after it takes this status. + auto_archive_delay_minutes: + type: number + minimum: 0 + description: How long after taking this status a task is archived. + additionalProperties: false + default: {} + additionalProperties: true +collection: + unique: + - field: app + scope: type +implements: + - contract: mdbase.app-settings + version: 1.0.0 + fields: + app: app + scope: scope + settings_version: settings_version + - contract: tasknotes.settings + version: 1.0.0 + fields: + app: app + scope: scope + settings_version: settings_version + nlp_triggers: nlp_triggers + template_enabled: template_enabled + template_path: template_path + occurrence_template_enabled: occurrence_template_enabled + occurrence_template_path: occurrence_template_path + template_failure_mode: template_failure_mode + template_unknown_variable_policy: template_unknown_variable_policy + move_on_archive: move_on_archive + archive_folder: archive_folder + auto_stop_time_tracking_on_complete: auto_stop_time_tracking_on_complete + reset_body_checkboxes_on_recurrence: reset_body_checkboxes_on_recurrence + link_write_format: link_write_format + status_behavior: status_behavior +--- + +# TaskNotes settings + +Settings that every TaskNotes client honours in this collection, such as body +templates, archive moves and status cycling. TaskNotes reads them from +`_settings/dev.tasknotes.md` and writes only the fields a save changes. diff --git a/types/tasknotes-task/6.md b/types/tasknotes-task/6.md new file mode 100644 index 0000000..71bc380 --- /dev/null +++ b/types/tasknotes-task/6.md @@ -0,0 +1,444 @@ +--- +kind: mdbase.type +name: task +version: 5 +description: A task managed by TaskNotes. +match: + where: + tags: + contains: task +schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + type: object + additionalProperties: true + properties: + id: + type: string + minLength: 1 + title: + type: string + minLength: 1 + status: + enum: &a2 + - none + - open + - in-progress + - done + - cancelled + default: open + priority: + enum: &a4 + - none + - low + - normal + - high + default: normal + due: &a1 + anyOf: + - type: string + format: date + - type: string + format: date-time + scheduled: *a1 + contexts: + type: array + items: + type: string + projects: + type: array + items: + type: string + assignees: + type: array + items: + type: string + minLength: 1 + pattern: \S + uniqueItems: true + attachments: + type: array + items: + type: string + minLength: 1 + uniqueItems: true + timeEstimate: + type: integer + minimum: 0 + completedDate: + type: string + format: date + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + recurrence: + type: string + recurrence_anchor: + enum: + - scheduled + - completion + default: scheduled + occurrence_materialization: + enum: + - manual + - on_completion + - rolling + default: manual + occurrence_next_trigger: + enum: + - completion + - completion_or_skip + default: completion + occurrence_template: + type: string + occurrence_past_horizon: + type: string + occurrence_future_horizon: + type: string + recurrence_parent: + type: string + occurrence_date: + type: string + format: date + tags: + type: array + items: + type: string + timeEntries: + type: array + items: + type: object + additionalProperties: false + properties: + startTime: + type: string + format: date-time + endTime: + type: string + format: date-time + description: + type: string + duration: + type: integer + reminders: + type: array + items: + oneOf: + - type: object + required: + - id + - type + - absoluteTime + additionalProperties: false + properties: + id: + type: string + type: + const: absolute + description: + type: string + absoluteTime: + type: string + format: date-time + - type: object + required: + - id + - type + - relatedTo + - offset + additionalProperties: false + properties: + id: + type: string + type: + const: relative + description: + type: string + relatedTo: + enum: + - due + - scheduled + offset: + type: string + blockedBy: + type: array + items: + type: object + additionalProperties: false + properties: + uid: + type: string + reltype: + type: string + gap: + type: string + required: + - uid + complete_instances: + type: array + items: + type: string + format: date + skipped_instances: + type: array + items: + type: string + format: date + icsEventId: + type: array + items: + type: string + googleCalendarEventId: + type: string + googleCalendarExceptionEventId: + type: string + googleCalendarExceptionOriginalScheduled: + type: string + format: date + googleCalendarMovedOriginalDates: + type: array + items: + type: string + format: date + tasknotes_manual_order: + type: string + allOf: + - if: + required: + - status + properties: + status: + enum: &a3 + - done + not: + required: + - recurrence + then: + required: + - completedDate + required: + - title + - status + - dateCreated +collection: + read_defaults: + status: open + priority: normal + recurrence_anchor: scheduled + occurrence_materialization: manual + occurrence_next_trigger: completion + links: + projects[]: + target_type: any + validate_exists: false + assignees[]: + validate_exists: false + attachments[]: + validate_exists: false + occurrence_template: + target_type: any + validate_exists: false + recurrence_parent: + target_type: task + validate_exists: false + blockedBy[].uid: + target_type: task + validate_exists: false + path: + runtime: tasknotes + template: "{{zettel}}" + folder: tasks + generated_by: tasknotes.filename.create + display: + name_field: title + unique: + - field: id + scope: type +lifecycle: + on_create: + set: + id: + uuid: true + dateCreated: + now: true + dateModified: + now: true + on_update: + set: + dateModified: + now: true +implements: + - contract: tasknotes.task + version: 0.3.0-rc.6 + fields: + id: id + title: title + status: status + priority: priority + due: due + scheduled: scheduled + contexts: contexts + projects: projects + assignees: assignees + attachments: attachments + timeEstimate: timeEstimate + completedDate: completedDate + dateCreated: dateCreated + dateModified: dateModified + recurrence: recurrence + recurrenceAnchor: recurrence_anchor + occurrenceMaterialization: occurrence_materialization + occurrenceNextTrigger: occurrence_next_trigger + occurrenceTemplate: occurrence_template + occurrencePastHorizon: occurrence_past_horizon + occurrenceFutureHorizon: occurrence_future_horizon + recurrenceParent: recurrence_parent + occurrenceDate: occurrence_date + tags: tags + timeEntries: timeEntries + reminders: reminders + blockedBy: blockedBy + completeInstances: complete_instances + skippedInstances: skipped_instances + icsEventId: icsEventId + googleCalendarEventId: googleCalendarEventId + googleCalendarExceptionEventId: googleCalendarExceptionEventId + googleCalendarExceptionOriginalScheduled: googleCalendarExceptionOriginalScheduled + googleCalendarMovedOriginalDates: googleCalendarMovedOriginalDates + sortOrder: tasknotes_manual_order + binding: + profiles: + - core-lite + - recurrence + - materialized-occurrences + capabilities: + - dependencies + - reminders + - attachments + - links + - time-tracking + - materialized-occurrences + - archive + - templating + title: + storage: frontmatter + filename_format: zettel + status: + values: *a2 + default: open + completed_values: *a3 + skipped_values: + - cancelled + default_skipped: cancelled + definitions: + - value: none + label: None + color: "#94a3b8" + is_completed: false + is_skipped: false + order: 0 + - value: open + label: Open + color: "#64748b" + is_completed: false + is_skipped: false + order: 1 + - value: in-progress + label: In progress + color: "#3b82f6" + is_completed: false + is_skipped: false + order: 2 + - value: done + label: Done + color: "#22c55e" + is_completed: true + is_skipped: false + order: 3 + - value: cancelled + label: Cancelled + color: "#94a3b8" + is_completed: false + is_skipped: true + order: 4 + priority: + values: *a4 + default: normal + definitions: + - value: none + label: None + color: "#94a3b8" + weight: 0 + - value: low + label: Low + color: "#3b82f6" + weight: 1 + - value: normal + label: Normal + color: "#f59e0b" + weight: 2 + - value: high + label: High + color: "#ef4444" + weight: 3 + recurrence: + syntax: tasknotes + maintain_due_date_offset: true + occurrences: + identity_roles: + - recurrenceParent + - occurrenceDate + default_materialization: manual + default_next_trigger: completion + past_horizon: P0D + future_horizon: P14D + links: + accepted_formats: + - wikilink + - markdown + archive: + archived_tag: archived +x-tasknotes-generator: + managed_fields: + - attachments + - blockedBy + - complete_instances + - completedDate + - contexts + - dateCreated + - dateModified + - due + - googleCalendarEventId + - googleCalendarExceptionEventId + - googleCalendarExceptionOriginalScheduled + - googleCalendarMovedOriginalDates + - icsEventId + - id + - occurrence_date + - occurrence_future_horizon + - occurrence_materialization + - occurrence_next_trigger + - occurrence_past_horizon + - occurrence_template + - priority + - projects + - recurrence + - recurrence_anchor + - recurrence_parent + - reminders + - scheduled + - skipped_instances + - status + - tags + - tasknotes_manual_order + - timeEntries + - timeEstimate + - title +--- +# Task + +Task records live under `tasks/`.