From a946221ed03fc26f2fb00a53c28bec2cd1751753 Mon Sep 17 00:00:00 2001 From: callumalpass Date: Sat, 3 Oct 2026 18:07:42 +1000 Subject: [PATCH] Publish tasknotes.task rc.18 and mdbase.contact 1.4.0 contract packs --- public/contracts/artifacts/types/comment/2.md | 231 ++++++++++++ public/contracts/artifacts/types/person/3.md | 145 ++++++++ public/contracts/artifacts/types/view/2.md | 349 ++++++++++++++++++ public/contracts/catalog.json | 197 ++++++++++ .../contracts/packs/mdbase.comment/1.0.1.json | 57 +++ .../contracts/packs/mdbase.contact/1.3.0.json | 106 ++++++ .../contracts/packs/mdbase.contact/1.4.0.json | 114 ++++++ public/contracts/packs/mdbase.view/1.0.1.json | 57 +++ .../packs/tasknotes.task/0.3.0-rc.18.json | 86 +++++ site-sources.json | 2 +- src/data/contracts.json | 197 ++++++++++ 11 files changed, 1540 insertions(+), 1 deletion(-) create mode 100644 public/contracts/artifacts/types/comment/2.md create mode 100644 public/contracts/artifacts/types/person/3.md create mode 100644 public/contracts/artifacts/types/view/2.md create mode 100644 public/contracts/packs/mdbase.comment/1.0.1.json create mode 100644 public/contracts/packs/mdbase.contact/1.3.0.json create mode 100644 public/contracts/packs/mdbase.contact/1.4.0.json create mode 100644 public/contracts/packs/mdbase.view/1.0.1.json create mode 100644 public/contracts/packs/tasknotes.task/0.3.0-rc.18.json diff --git a/public/contracts/artifacts/types/comment/2.md b/public/contracts/artifacts/types/comment/2.md new file mode 100644 index 0000000..0917d01 --- /dev/null +++ b/public/contracts/artifacts/types/comment/2.md @@ -0,0 +1,231 @@ +--- +kind: mdbase.type +name: comment +version: 2 +description: A comment, reply or suggested edit on another note, anchored to a passage of its text. +match: + where: + type: comment +schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + title: Comment + description: A comment, reply or suggested edit on a Markdown record, stored as its own record. The comment's Markdown body is its text. + type: object + required: + - document + - created_at + properties: + document: + type: string + pattern: \S + description: Link to the commented record, such as [[chapters/method]]. Replies repeat their thread's document so one query finds a record's whole discussion. + in_reply_to: + type: string + pattern: \S + description: Link to the first comment of the thread this comment replies to. Absent on the first comment of a thread. + motivation: + enum: + - commenting + - replying + - editing + default: commenting + description: commenting starts a thread, replying answers one, and editing suggests replacing the target's text. + target: + type: object + description: Where in the document the thread is anchored. Absent means the whole record. Only the first comment of a thread has a target. + properties: + quote: + type: object + description: The anchored text and the text around it. The quote is authoritative; positions are a hint. + required: + - exact + properties: + exact: + type: string + description: The anchored text exactly as it appears in the record body. Empty for an insertion point, which prefix or suffix then locates. + prefix: + type: string + description: Text immediately before exact, to tell repeated occurrences apart. + suffix: + type: string + description: Text immediately after exact, to tell repeated occurrences apart. + if: + required: + - exact + properties: + exact: + type: string + maxLength: 0 + then: + anyOf: + - required: + - prefix + properties: + prefix: + type: string + minLength: 1 + - required: + - suffix + properties: + suffix: + type: string + minLength: 1 + additionalProperties: false + text_position: + type: object + description: Offsets of the quote in one revision of the record body. + required: + - basis + - unit + - start + - end + properties: + basis: + type: object + required: + - profile + - hash + properties: + profile: + const: markdown-body + description: Offsets count the record's Markdown body as stored, after the frontmatter, so frontmatter edits never move them. + hash: + type: string + pattern: ^sha256:[0-9a-f]{64}$ + description: SHA-256 of the UTF-8 body the offsets were measured in. + additionalProperties: false + unit: + const: unicode_code_point + start: + type: integer + minimum: 0 + end: + type: integer + minimum: 0 + additionalProperties: false + required: + - quote + additionalProperties: false + suggestion: + type: object + description: "The suggested edit of an editing comment: replace the target's quote with replacement." + required: + - replacement + properties: + replacement: + type: string + description: The text to put in place of the quote. Empty suggests deleting it. + outcome: + enum: + - accepted + - rejected + description: What happened to the suggestion once its thread was resolved. + additionalProperties: false + status: + enum: + - open + - resolved + default: open + description: Whether the thread is still open. Only meaningful on the first comment of a thread. + resolved_by: + type: string + pattern: \S + description: Link to the mdbase.person record of who resolved the thread. + resolved_at: + type: string + format: date-time + created_by: + type: string + pattern: \S + description: Link to the mdbase.person record of the comment's author. Absent when the author has no person record. + created_at: + type: string + format: date-time + modified_at: + type: string + format: date-time + deleted_at: + type: string + format: date-time + description: When the comment was withdrawn. The record stays so its thread and replies keep their shape; its body should be emptied. + allOf: + - if: + properties: + motivation: + const: editing + required: + - motivation + then: + required: + - target + - suggestion + properties: + target: + type: object + suggestion: + type: object + additionalProperties: true +collection: + links: + document: + target_type: any + validate_exists: false + in_reply_to: + target_type: comment + validate_exists: false + created_by: + target_type: any + validate_exists: false + resolved_by: + target_type: any + validate_exists: false + display: + description_field: document + icon: chat-circle +implements: + - contract: mdbase.comment + version: 1.0.0 + fields: + document: document + in_reply_to: in_reply_to + motivation: motivation + target: target + suggestion: suggestion + status: status + resolved_by: resolved_by + resolved_at: resolved_at + created_by: created_by + created_at: created_at + modified_at: modified_at + deleted_at: deleted_at +--- + +# Comment + +One note per comment, reply or suggested edit. Apps create these for you; the +commented note itself is never changed by commenting on it. + +```yaml +type: comment +document: "[[chapters/method]]" +target: + quote: { exact: "suggests strongly", prefix: "the evidence ", suffix: " that" } +created_by: "[[Alex Rivera]]" +created_at: 2026-09-29T10:00:00Z +``` + +The note's body is the comment's text. A reply is another Comment note whose +`in_reply_to` links to the thread's first comment. A suggested edit has +`motivation: editing` and a `suggestion.replacement`. + +`document`, `in_reply_to`, `created_by` and `resolved_by` are links, so +renaming or moving a note with a tool that updates references keeps them +current. Links to a note that has since been deleted are kept, not treated as +errors. `created_by` and `resolved_by` link to Person notes; they are +editable data, not proof of who wrote a comment. + +This type belongs to your collection once installed. You can add fields, or +rename fields and update the `implements` mapping; apps read comments through +the `mdbase.comment` contract, not through these local names. diff --git a/public/contracts/artifacts/types/person/3.md b/public/contracts/artifacts/types/person/3.md new file mode 100644 index 0000000..575a51d --- /dev/null +++ b/public/contracts/artifacts/types/person/3.md @@ -0,0 +1,145 @@ +--- +kind: mdbase.type +name: person +version: 3 +description: An individual that other notes link to, with a collection-owned display name and optional contact details and account associations. +match: + where: + type: person +schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + title: Person + description: One person represented by an ordinary note. Contact details and account associations are optional; this record never grants access or membership. + type: object + required: [name] + properties: + name: + type: string + minLength: 1 + pattern: '\S' + description: The display name to use in this collection. Use a full name, preferred name, or single name as appropriate; no first/last-name split is required. It can differ from an account's name and is not automatically synchronised with it. + identities: + type: array + description: Optional accounts associated with this person, each identified by an exact issuer and subject pair. Omit this field for someone without an account. These editable associations help applications find your person record; they are not proof of identity and never grant access. Avoid linking the same account to multiple person notes. + uniqueItems: true + items: + type: object + description: One account association supplied by its identity service. Both issuer and subject must match exactly; never infer them from a name or email. + required: [issuer, subject] + properties: + issuer: + type: string + format: uri + pattern: '^https?://' + description: The exact identity-service issuer URL reported for this account. Preserve its scheme, case, path, and trailing slash; do not guess it from the collection's hosting address. + subject: + type: string + pattern: '\S' + description: The opaque account identifier reported by that issuer, not a display name, email, password, or access token. Copy it exactly; a different issuer may use the same subject for a different account. + additionalProperties: false + kind: + const: individual + default: individual + description: This Person starter represents an individual. The organisation field describes their affiliation, not a different record kind. Existing organisation or group contacts can keep their own Contact-compatible type. + email: + type: string + format: email + description: The preferred email address for contacting this person. Optional contact information only; it does not establish an account association or grant access. + phone: + type: string + minLength: 1 + description: The preferred telephone number, stored as text so country codes, formatting, and extensions can be preserved. Include a country code when useful; omit if unknown. + organisation: + type: string + minLength: 1 + description: The person's main affiliation, such as an employer, school, or community. A collection-owned display label, not a membership or access-control setting; omit if not relevant. + birthday: + type: string + format: date + description: A known birthday as a full calendar date in YYYY-MM-DD form. Omit if unknown or if only the month and day are known; do not invent a year. Consider whether this collection needs this personal information. + additionalProperties: true +collection: + display: + name_field: name + description_field: organisation + icon: user +implements: + - contract: mdbase.person + version: 2.0.0 + fields: + name: name + identities: identities + - contract: mdbase.contact + version: 1.0.0 + fields: + name: name + kind: kind + primary_email: email + primary_phone: phone + organisation: organisation + birthday: birthday +--- + +# Person + +Use one note per individual, whether or not they have a Connect account. This +single type supplies both a Person record and optional Contact details. You do +not need a second Contact note for the same person. + +## Start with a name + +```yaml +type: person +name: Alex Rivera +``` + +Other notes refer to this person with an ordinary link to this note, such as +`[[Alex Rivera]]` in a task's `assignees`. Links to this note appear in its +backlinks. Rename or move the note with a tool that updates references, as mdbase +and Obsidian do, so those links stay current. Reusing a person's file name for +somebody else redirects existing links to the wrong person. + +The name is your collection's display label. Full names, preferred names and +single names are equally valid. There is no required first-name/last-name split. + +## Add only the contact details you need + +Email, phone, organisation and birthday are optional. Omit unknown values rather +than filling them with empty strings or guesses. Store phone numbers as text, +including an international prefix or extension when helpful. Birthday currently +requires a complete date; partial dates need a separately configured local field. +Keep free-form context in the Markdown body and be deliberate about sensitive +personal information in shared collections. + +This starter describes individuals. Existing organisation and group records can +continue using their Contact-compatible type; setting someone's affiliation does +not turn their Person note into an organisation record. + +## Link accounts deliberately + +The editor's **Link this record to me** action uses the authenticated account's +actual issuer and subject. If configuring these manually, copy both exact values +from the identity service. Do not guess them from an email, display name, or the +server hosting this collection. Multiple entries may represent the same person +at different identity services. Omit `identities` when there is no account to link. + +Associations are ordinary editable data, not authentication or proof of identity. +Linking never invites someone, grants access, or changes collection membership. +Never put credentials in a person record. Avoid linking the same account from +several notes: applications should report ambiguity, not guess which +record to use. Account deletion or recreation is not permission to reassign an +old association automatically. + +## Keep the collection's own shape + +The inline schema belongs to this collection. You may add local fields, or rename +fields and update their explicit `implements` mappings. Apps use those mappings +for the Person and Contact contracts; they need not assume your local field names. +Additional fields remain part of the note but do not automatically become shared +contract fields. Do not edit published contracts to customise this type. + +Installing a newer starter does not overwrite an existing customised type or +migrate your address book. Converting an existing individual Contact to Person +should be a reviewed edit of that one note, preserving its path, fields and body. diff --git a/public/contracts/artifacts/types/view/2.md b/public/contracts/artifacts/types/view/2.md new file mode 100644 index 0000000..1cb8344 --- /dev/null +++ b/public/contracts/artifacts/types/view/2.md @@ -0,0 +1,349 @@ +--- +kind: mdbase.type +name: view +version: 2 +description: 'Saved views: shared query scope and stable named views' +match: + where: + type: view +schema: + dialect: json-schema-2020-12 + value: + $schema: https://json-schema.org/draft/2020-12/schema + title: View + description: 'Saved views: shared query scope and stable named views.' + type: object + required: + - id + - version + - name + - views + properties: + id: + $ref: '#/$defs/identifier' + version: + type: integer + minimum: 1 + name: + type: string + minLength: 1 + description: + type: string + query: + $ref: '#/$defs/sharedQuery' + properties: + $ref: '#/$defs/propertyMetadataSet' + summary_functions: + $ref: '#/$defs/summaryFunctionSet' + views: + type: array + minItems: 1 + items: + $ref: '#/$defs/view' + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: true + $defs: + identifier: + type: string + pattern: ^[A-Za-z][A-Za-z0-9._:-]*$ + typeName: + type: string + pattern: ^[A-Za-z][A-Za-z0-9_-]{0,127}$ + fieldName: + type: string + pattern: ^[A-Za-z_][A-Za-z0-9_:-]*$ + expression: + type: string + minLength: 1 + extension: + type: object + additionalProperties: true + typeList: + type: array + minItems: 1 + uniqueItems: true + items: + $ref: '#/$defs/typeName' + sharedQuery: + type: object + properties: + types: + $ref: '#/$defs/typeList' + where: + $ref: '#/$defs/expression' + context: + $ref: '#/$defs/viewContext' + projections: + $ref: '#/$defs/projectionSet' + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false + viewContext: + type: object + required: + - this + properties: + this: + $ref: '#/$defs/thisContext' + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false + thisContext: + type: object + properties: + on_missing: + enum: + - view + - 'null' + - error + default: view + types: + $ref: '#/$defs/typeList' + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false + projectionSet: + type: object + propertyNames: + $ref: '#/$defs/fieldName' + additionalProperties: + $ref: '#/$defs/projection' + projection: + type: object + required: + - expr + properties: + expr: + $ref: '#/$defs/expression' + description: + type: string + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false + propertyMetadataSet: + type: object + propertyNames: + type: string + minLength: 1 + additionalProperties: + $ref: '#/$defs/propertyMetadata' + propertyMetadata: + type: object + properties: + label: + type: string + description: + type: string + format: + type: string + hidden: + type: boolean + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false + summaryFunctionSet: + type: object + propertyNames: + $ref: '#/$defs/fieldName' + additionalProperties: + $ref: '#/$defs/summaryFunction' + summaryFunction: + type: object + required: + - expr + properties: + expr: + $ref: '#/$defs/expression' + description: + type: string + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false + view: + type: object + required: + - id + - name + properties: + id: + $ref: '#/$defs/identifier' + name: + type: string + minLength: 1 + description: + type: string + types: + $ref: '#/$defs/typeList' + where: + $ref: '#/$defs/expression' + context: + $ref: '#/$defs/viewContext' + projections: + $ref: '#/$defs/projectionSet' + select: + $ref: '#/$defs/select' + order_by: + $ref: '#/$defs/orderBy' + group_by: + $ref: '#/$defs/groupBy' + summaries: + $ref: '#/$defs/summaries' + limit: + type: integer + minimum: 0 + offset: + type: integer + minimum: 0 + include_body: + type: boolean + default: false + frontmatter_mode: + enum: + - effective + - persisted + - both + default: effective + presentation: + $ref: '#/$defs/presentation' + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false + select: + type: array + minItems: 1 + items: + oneOf: + - type: string + minLength: 1 + - $ref: '#/$defs/selectExpression' + selectExpression: + type: object + required: + - name + - expr + properties: + name: + $ref: '#/$defs/fieldName' + expr: + $ref: '#/$defs/expression' + label: + type: string + description: + type: string + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false + orderBy: + type: array + minItems: 1 + items: + type: object + required: + - field + properties: + field: + type: string + minLength: 1 + direction: + enum: + - asc + - desc + default: asc + additionalProperties: false + groupBy: + type: array + minItems: 1 + items: + type: object + required: + - field + properties: + field: + type: string + minLength: 1 + direction: + enum: + - asc + - desc + default: asc + additionalProperties: false + summaries: + type: array + minItems: 1 + items: + $ref: '#/$defs/summary' + summary: + type: object + required: + - field + - function + properties: + field: + type: string + minLength: 1 + function: + $ref: '#/$defs/identifier' + name: + $ref: '#/$defs/fieldName' + label: + type: string + additionalProperties: false + presentation: + type: object + required: + - type + properties: + type: + $ref: '#/$defs/identifier' + fallback: + $ref: '#/$defs/identifier' + mappings: + type: object + propertyNames: + $ref: '#/$defs/fieldName' + additionalProperties: + type: string + minLength: 1 + options: + type: object + additionalProperties: true + patternProperties: + ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$: + $ref: '#/$defs/extension' + additionalProperties: false +implements: +- contract: mdbase.view + version: 1.0.0 + fields: + id: id + version: version + name: name + description: description + query: query + properties: properties + summary_functions: summary_functions + views: views +collection: + display: + name_field: name +--- + +# View + +A view record stores shared query scope and one or more stable named views. +Tools that support saved views discover these records through the `mdbase.view` +contract and run each named view as an ordinary query. + +This type belongs to your collection once installed. You can rename fields or +change how records are matched, as long as the `implements` mapping still +points each contract field at the right frontmatter field. diff --git a/public/contracts/catalog.json b/public/contracts/catalog.json index 174ca55..e9a079b 100644 --- a/public/contracts/catalog.json +++ b/public/contracts/catalog.json @@ -277,6 +277,44 @@ "Suggested edits" ] }, + "installation": { + "visibility": "hidden", + "recommendation": "optional", + "primary_type": "comment", + "types": [ + { + "name": "comment", + "label": "Comment" + } + ] + } + }, + { + "id": "mdbase.comment", + "version": "1.0.1", + "name": "Comments type pack", + "description": "Comments, replies and suggested edits anchored to text in Markdown records.", + "digest": "sha256:3b3940270e96876062d8fcdf293edb7eeb99985987b8821f8478acf9663d1e83", + "provision": "./packs/mdbase.comment/1.0.1.json", + "provides": [ + { + "id": "mdbase.comment", + "version": "1.0.0", + "digest": "sha256:c2c5b3f3013d10625310401e9f9149ffa2d09c5b7d91b4fc97688d3ac010bec5" + } + ], + "resource_count": 3, + "display": { + "name": "Comments", + "summary": "Discuss and suggest edits to notes without changing their text, in any app that reads comments.", + "category": "work", + "audience": "general", + "icon": "chat-circle", + "badges": [ + "Portable comments", + "Suggested edits" + ] + }, "installation": { "visibility": "default", "recommendation": "optional", @@ -402,6 +440,90 @@ "Portable person references" ] }, + "installation": { + "visibility": "hidden", + "recommendation": "user", + "primary_type": "person", + "types": [ + { + "name": "person", + "label": "Person" + } + ] + } + }, + { + "id": "mdbase.contact", + "version": "1.3.0", + "name": "People type pack", + "description": "Portable people, editable account identity associations, and familiar contact fields.", + "digest": "sha256:48fc070ae00c61ab5b20b9ffb385d20d2a468328da07e45e67c99602b05d02e8", + "provision": "./packs/mdbase.contact/1.3.0.json", + "provides": [ + { + "id": "mdbase.person", + "version": "2.0.0", + "digest": "sha256:f16c462a1fd422f44ed055002f8476ec53c164107647fec782aeb74adeab2f9d" + }, + { + "id": "mdbase.contact", + "version": "1.0.0", + "digest": "sha256:49cfe15403dfc741a693e89a2f4d2857de306f391d02cb03e67bfaf0aa1d6b0d" + } + ], + "resource_count": 7, + "display": { + "name": "People", + "summary": "Reference people across apps and collections without tying records to account membership.", + "category": "people", + "audience": "general", + "icon": "user", + "badges": [ + "Portable person references" + ] + }, + "installation": { + "visibility": "hidden", + "recommendation": "user", + "primary_type": "person", + "types": [ + { + "name": "person", + "label": "Person" + } + ] + } + }, + { + "id": "mdbase.contact", + "version": "1.4.0", + "name": "People type pack", + "description": "Portable people, editable account identity associations, and familiar contact fields.", + "digest": "sha256:741fcf0f50d13538eda1c9ee32df4d85e32549b8fb730350bb80b3323b09df93", + "provision": "./packs/mdbase.contact/1.4.0.json", + "provides": [ + { + "id": "mdbase.person", + "version": "2.0.0", + "digest": "sha256:f16c462a1fd422f44ed055002f8476ec53c164107647fec782aeb74adeab2f9d" + }, + { + "id": "mdbase.contact", + "version": "1.0.0", + "digest": "sha256:49cfe15403dfc741a693e89a2f4d2857de306f391d02cb03e67bfaf0aa1d6b0d" + } + ], + "resource_count": 7, + "display": { + "name": "People", + "summary": "Reference people across apps and collections without tying records to account membership.", + "category": "people", + "audience": "general", + "icon": "user", + "badges": [ + "Portable person references" + ] + }, "installation": { "visibility": "default", "recommendation": "user", @@ -558,6 +680,43 @@ "Portable views" ] }, + "installation": { + "visibility": "hidden", + "recommendation": "optional", + "primary_type": "view", + "types": [ + { + "name": "view", + "label": "View" + } + ] + } + }, + { + "id": "mdbase.view", + "version": "1.0.1", + "name": "Saved views", + "description": "The mdbase.view contract and an editable View type for saved, reusable queries.", + "digest": "sha256:e93db5cd8449eb3b1e3cb795b0bf0477fc90124363745dd9aef7a88b1fbc8752", + "provision": "./packs/mdbase.view/1.0.1.json", + "provides": [ + { + "id": "mdbase.view", + "version": "1.0.0", + "digest": "sha256:0918acefce08cddd778fab768fe4f2e4615d263a0eec3e5330b6897c686d744e" + } + ], + "resource_count": 3, + "display": { + "name": "Saved views", + "summary": "Save reusable queries that any view-aware app can list and run.", + "category": "work", + "audience": "general", + "icon": "table", + "badges": [ + "Portable views" + ] + }, "installation": { "visibility": "default", "recommendation": "optional", @@ -670,6 +829,44 @@ "TaskNotes compatible" ] }, + "installation": { + "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.", + "types": [ + { + "name": "task", + "label": "Task" + } + ] + } + }, + { + "id": "tasknotes.task", + "version": "0.3.0-rc.18", + "name": "TaskNotes task type pack", + "description": "Portable tasks whose assignments link to person records, with a reviewed, atomic upgrade from every TaskNotes starter published before.", + "digest": "sha256:9a9ebc26e6f63ad2fc3d92f87d38f6c140a3af90408de47d667ae7b9ba0dc9ef", + "provision": "./packs/tasknotes.task/0.3.0-rc.18.json", + "provides": [ + { + "id": "tasknotes.task", + "version": "0.3.0-rc.5", + "digest": "sha256:dde71d0d776aa0069ee627fe3c10b1a20f87ba36929a16790598ebfb4e8ebf04" + } + ], + "resource_count": 4, + "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", diff --git a/public/contracts/packs/mdbase.comment/1.0.1.json b/public/contracts/packs/mdbase.comment/1.0.1.json new file mode 100644 index 0000000..606bc5e --- /dev/null +++ b/public/contracts/packs/mdbase.comment/1.0.1.json @@ -0,0 +1,57 @@ +{ + "manifest": { + "kind": "mdbase.type-pack", + "id": "mdbase.comment", + "version": "1.0.1", + "name": "Comments type pack", + "description": "Comments, replies and suggested edits anchored to text in Markdown records.", + "resources": [ + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.comment/1.0.0.schema.json", + "target": "schemas/mdbase.comment/1.0.0.schema.json", + "digest": "sha256:b845720a44e3fcea2385ef33ae2803531f2fad655efdc2c262e51f92f24f0e74" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.comment/1.0.0.md", + "target": "_contracts/mdbase.comment/1.0.0.md", + "digest": "sha256:c85663fbb339d33e8e67825c81fc160fbac00285a1687cbe99187bad7f58878d" + }, + { + "kind": "type", + "mode": "seed", + "source": "types/comment/2.md", + "target": "_types/comment.md", + "digest": "sha256:a18cb5844d999730e39e9c756a6e0116b1d7d5c3082efe11d33cba3881957b1a", + "upgrade_from": { + "digest": "sha256:e8abf287b9d3df0035fd32a2a584d7a8d21eddd7b4a3201fd32a3babe6ac9d9e", + "document": "---\nkind: mdbase.type\nname: comment\nversion: 1\ndescription: A comment, reply or suggested edit on another note, anchored to a passage of its text.\nmatch:\n where:\n type: comment\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: Comment\n description: A comment, reply or suggested edit on a Markdown record, stored as its own record. The comment's Markdown body is its text.\n type: object\n required:\n - type\n - document\n - created_at\n properties:\n type:\n const: comment\n description: Identifies this note as a Comment. Set by the application that creates it.\n document:\n type: string\n pattern: \\S\n description: Link to the commented record, such as [[chapters/method]]. Replies repeat their thread's document so one query finds a record's whole discussion.\n in_reply_to:\n type: string\n pattern: \\S\n description: Link to the first comment of the thread this comment replies to. Absent on the first comment of a thread.\n motivation:\n enum:\n - commenting\n - replying\n - editing\n default: commenting\n description: commenting starts a thread, replying answers one, and editing suggests replacing the target's text.\n target:\n type: object\n description: Where in the document the thread is anchored. Absent means the whole record. Only the first comment of a thread has a target.\n properties:\n quote:\n type: object\n description: The anchored text and the text around it. The quote is authoritative; positions are a hint.\n required:\n - exact\n properties:\n exact:\n type: string\n description: The anchored text exactly as it appears in the record body. Empty for an insertion point, which prefix or suffix then locates.\n prefix:\n type: string\n description: Text immediately before exact, to tell repeated occurrences apart.\n suffix:\n type: string\n description: Text immediately after exact, to tell repeated occurrences apart.\n if:\n required:\n - exact\n properties:\n exact:\n type: string\n maxLength: 0\n then:\n anyOf:\n - required:\n - prefix\n properties:\n prefix:\n type: string\n minLength: 1\n - required:\n - suffix\n properties:\n suffix:\n type: string\n minLength: 1\n additionalProperties: false\n text_position:\n type: object\n description: Offsets of the quote in one revision of the record body.\n required:\n - basis\n - unit\n - start\n - end\n properties:\n basis:\n type: object\n required:\n - profile\n - hash\n properties:\n profile:\n const: markdown-body\n description: Offsets count the record's Markdown body as stored, after the frontmatter, so frontmatter edits never move them.\n hash:\n type: string\n pattern: ^sha256:[0-9a-f]{64}$\n description: SHA-256 of the UTF-8 body the offsets were measured in.\n additionalProperties: false\n unit:\n const: unicode_code_point\n start:\n type: integer\n minimum: 0\n end:\n type: integer\n minimum: 0\n additionalProperties: false\n required:\n - quote\n additionalProperties: false\n suggestion:\n type: object\n description: \"The suggested edit of an editing comment: replace the target's quote with replacement.\"\n required:\n - replacement\n properties:\n replacement:\n type: string\n description: The text to put in place of the quote. Empty suggests deleting it.\n outcome:\n enum:\n - accepted\n - rejected\n description: What happened to the suggestion once its thread was resolved.\n additionalProperties: false\n status:\n enum:\n - open\n - resolved\n default: open\n description: Whether the thread is still open. Only meaningful on the first comment of a thread.\n resolved_by:\n type: string\n pattern: \\S\n description: Link to the mdbase.person record of who resolved the thread.\n resolved_at:\n type: string\n format: date-time\n created_by:\n type: string\n pattern: \\S\n description: Link to the mdbase.person record of the comment's author. Absent when the author has no person record.\n created_at:\n type: string\n format: date-time\n modified_at:\n type: string\n format: date-time\n deleted_at:\n type: string\n format: date-time\n description: When the comment was withdrawn. The record stays so its thread and replies keep their shape; its body should be emptied.\n allOf:\n - if:\n properties:\n motivation:\n const: editing\n required:\n - motivation\n then:\n required:\n - target\n - suggestion\n properties:\n target:\n type: object\n suggestion:\n type: object\n additionalProperties: true\ncollection:\n links:\n document:\n target_type: any\n validate_exists: false\n in_reply_to:\n target_type: comment\n validate_exists: false\n created_by:\n target_type: any\n validate_exists: false\n resolved_by:\n target_type: any\n validate_exists: false\n display:\n description_field: document\n icon: chat-circle\nimplements:\n - contract: mdbase.comment\n version: 1.0.0\n fields:\n document: document\n in_reply_to: in_reply_to\n motivation: motivation\n target: target\n suggestion: suggestion\n status: status\n resolved_by: resolved_by\n resolved_at: resolved_at\n created_by: created_by\n created_at: created_at\n modified_at: modified_at\n deleted_at: deleted_at\n---\n\n# Comment\n\nOne note per comment, reply or suggested edit. Apps create these for you; the\ncommented note itself is never changed by commenting on it.\n\n```yaml\ntype: comment\ndocument: \"[[chapters/method]]\"\ntarget:\n quote: { exact: \"suggests strongly\", prefix: \"the evidence \", suffix: \" that\" }\ncreated_by: \"[[Alex Rivera]]\"\ncreated_at: 2026-09-29T10:00:00Z\n```\n\nThe note's body is the comment's text. A reply is another Comment note whose\n`in_reply_to` links to the thread's first comment. A suggested edit has\n`motivation: editing` and a `suggestion.replacement`.\n\n`document`, `in_reply_to`, `created_by` and `resolved_by` are links, so\nrenaming or moving a note with a tool that updates references keeps them\ncurrent. Links to a note that has since been deleted are kept, not treated as\nerrors. `created_by` and `resolved_by` link to Person notes; they are\neditable data, not proof of who wrote a comment.\n\nThis type belongs to your collection once installed. You can add fields, or\nrename fields and update the `implements` mapping; apps read comments through\nthe `mdbase.comment` contract, not through these local names.\n" + } + } + ] + }, + "resources": [ + { + "source": "schemas/mdbase.comment/1.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://mdbase.dev/contracts/schemas/mdbase.comment/1.0.0.schema.json\",\n \"title\": \"Comment\",\n \"description\": \"A comment, reply or suggested edit on a Markdown record, stored as its own record. The comment's Markdown body is its text.\",\n \"type\": \"object\",\n \"required\": [\n \"document\",\n \"created_at\"\n ],\n \"properties\": {\n \"document\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Link to the commented record, such as [[chapters/method]]. Replies repeat their thread's document so one query finds a record's whole discussion.\"\n },\n \"in_reply_to\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Link to the first comment of the thread this comment replies to. Absent on the first comment of a thread.\"\n },\n \"motivation\": {\n \"enum\": [\n \"commenting\",\n \"replying\",\n \"editing\"\n ],\n \"default\": \"commenting\",\n \"description\": \"commenting starts a thread, replying answers one, and editing suggests replacing the target's text.\"\n },\n \"target\": {\n \"type\": \"object\",\n \"description\": \"Where in the document the thread is anchored. Absent means the whole record. Only the first comment of a thread has a target.\",\n \"properties\": {\n \"quote\": {\n \"type\": \"object\",\n \"description\": \"The anchored text and the text around it. The quote is authoritative; positions are a hint.\",\n \"required\": [\n \"exact\"\n ],\n \"properties\": {\n \"exact\": {\n \"type\": \"string\",\n \"description\": \"The anchored text exactly as it appears in the record body. Empty for an insertion point, which prefix or suffix then locates.\"\n },\n \"prefix\": {\n \"type\": \"string\",\n \"description\": \"Text immediately before exact, to tell repeated occurrences apart.\"\n },\n \"suffix\": {\n \"type\": \"string\",\n \"description\": \"Text immediately after exact, to tell repeated occurrences apart.\"\n }\n },\n \"if\": {\n \"required\": [\n \"exact\"\n ],\n \"properties\": {\n \"exact\": {\n \"type\": \"string\",\n \"maxLength\": 0\n }\n }\n },\n \"then\": {\n \"anyOf\": [\n {\n \"required\": [\n \"prefix\"\n ],\n \"properties\": {\n \"prefix\": {\n \"type\": \"string\",\n \"minLength\": 1\n }\n }\n },\n {\n \"required\": [\n \"suffix\"\n ],\n \"properties\": {\n \"suffix\": {\n \"type\": \"string\",\n \"minLength\": 1\n }\n }\n }\n ]\n },\n \"additionalProperties\": false\n },\n \"text_position\": {\n \"type\": \"object\",\n \"description\": \"Offsets of the quote in one revision of the record body.\",\n \"required\": [\n \"basis\",\n \"unit\",\n \"start\",\n \"end\"\n ],\n \"properties\": {\n \"basis\": {\n \"type\": \"object\",\n \"required\": [\n \"profile\",\n \"hash\"\n ],\n \"properties\": {\n \"profile\": {\n \"const\": \"markdown-body\",\n \"description\": \"Offsets count the record's Markdown body as stored, after the frontmatter, so frontmatter edits never move them.\"\n },\n \"hash\": {\n \"type\": \"string\",\n \"pattern\": \"^sha256:[0-9a-f]{64}$\",\n \"description\": \"SHA-256 of the UTF-8 body the offsets were measured in.\"\n }\n },\n \"additionalProperties\": false\n },\n \"unit\": {\n \"const\": \"unicode_code_point\"\n },\n \"start\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"end\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"additionalProperties\": false\n }\n },\n \"required\": [\n \"quote\"\n ],\n \"additionalProperties\": false\n },\n \"suggestion\": {\n \"type\": \"object\",\n \"description\": \"The suggested edit of an editing comment: replace the target's quote with replacement.\",\n \"required\": [\n \"replacement\"\n ],\n \"properties\": {\n \"replacement\": {\n \"type\": \"string\",\n \"description\": \"The text to put in place of the quote. Empty suggests deleting it.\"\n },\n \"outcome\": {\n \"enum\": [\n \"accepted\",\n \"rejected\"\n ],\n \"description\": \"What happened to the suggestion once its thread was resolved.\"\n }\n },\n \"additionalProperties\": false\n },\n \"status\": {\n \"enum\": [\n \"open\",\n \"resolved\"\n ],\n \"default\": \"open\",\n \"description\": \"Whether the thread is still open. Only meaningful on the first comment of a thread.\"\n },\n \"resolved_by\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Link to the mdbase.person record of who resolved the thread.\"\n },\n \"resolved_at\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"created_by\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Link to the mdbase.person record of the comment's author. Absent when the author has no person record.\"\n },\n \"created_at\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"modified_at\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"deleted_at\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"When the comment was withdrawn. The record stays so its thread and replies keep their shape; its body should be emptied.\"\n }\n },\n \"allOf\": [\n {\n \"if\": {\n \"properties\": {\n \"motivation\": {\n \"const\": \"editing\"\n }\n },\n \"required\": [\n \"motivation\"\n ]\n },\n \"then\": {\n \"required\": [\n \"target\",\n \"suggestion\"\n ],\n \"properties\": {\n \"target\": {\n \"type\": \"object\"\n },\n \"suggestion\": {\n \"type\": \"object\"\n }\n }\n }\n }\n ],\n \"additionalProperties\": false\n}\n" + }, + { + "source": "contracts/mdbase.comment/1.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.comment\nversion: 1.0.0\nname: Comment\ndescription: Comments, replies and suggested edits anchored to text in Markdown records.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.comment/1.0.0.schema.json\n---\n\n# Comment\n\nA comment is its own record, never markup inside the commented record. The\ncommented record's Markdown stays exactly as its author wrote it, and comments\ncan be queried, linked to and validated like any other record. The comment's\nMarkdown body is its text; a link to a person in that text is a mention.\n\n## Threads\n\nThe first comment of a thread has no `in_reply_to`. It carries the thread's\nanchor (`target`) and state (`status`, `resolved_by`, `resolved_at`). Each reply\nis a separate record whose `in_reply_to` links to that first comment, so two\npeople replying at once write two records and never conflict. Replies repeat\nthe thread's `document`. Order a thread's replies by `created_at`.\n\nRefer to records only with ordinary mdbase links: `document` to the commented\nrecord, `in_reply_to` to the first comment, `created_by` and `resolved_by` to\nrecords implementing `mdbase.person`. Implementing types declare these fields in\n`collection.links` so rename reference updates keep them current. Never refer\nto an author by name, email or account subject.\n\n## Anchors\n\n`target.quote` is the source of truth: `exact` is the anchored text and\n`prefix` and `suffix` are the text around it. `target.text_position` records\nwhere the quote was in one revision of the body, in Unicode code points of the\nrecord's Markdown body as stored, after its frontmatter (profile\n`markdown-body`). `basis.hash` is `sha256:` and the hex SHA-256 of that body's\nUTF-8 bytes.\n\nTo find a thread's text:\n\n1. When the body at the recorded offsets is still `exact`, use them.\n2. Otherwise search the body for `exact`, preferring the occurrence whose\n surrounding text best matches `prefix` and `suffix`, then the one nearest\n the recorded offsets.\n3. When `exact` is not found, the thread is detached. Show it apart from the\n text rather than guessing a place. A detached thread is not an error.\n\nAn empty `exact` is an insertion point between `prefix` and `suffix`. A thread\nwithout a `target` is about the whole record. A consumer may rewrite\n`text_position` after finding the quote elsewhere; it must not change `quote`.\n\n## Suggested edits\n\nA comment with `motivation: editing` suggests replacing the target's quote with\n`suggestion.replacement`; an empty replacement suggests deleting it. Accepting\na suggestion first finds the quote as above and must refuse, leaving the\nthread open, when the quote cannot be found exactly. It then replaces the\nquote in the commented record and resolves the thread with\n`suggestion.outcome: accepted`. Rejecting resolves it with `rejected`.\n\n## Lifecycle\n\nA comment whose `document` no longer resolves is kept, not deleted: records\ncan be restored, and the discussion is still collection data. Consumers may\nhide such comments. Withdrawing a comment sets `deleted_at` and empties its\nbody rather than deleting the record, so replies to it keep their thread.\n\nAuthorship links are editable collection data with the same trust as any other\nfield. They never prove who wrote a comment or grant anyone access.\n" + }, + { + "source": "types/comment/2.md", + "document": "---\nkind: mdbase.type\nname: comment\nversion: 2\ndescription: A comment, reply or suggested edit on another note, anchored to a passage of its text.\nmatch:\n where:\n type: comment\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: Comment\n description: A comment, reply or suggested edit on a Markdown record, stored as its own record. The comment's Markdown body is its text.\n type: object\n required:\n - document\n - created_at\n properties:\n document:\n type: string\n pattern: \\S\n description: Link to the commented record, such as [[chapters/method]]. Replies repeat their thread's document so one query finds a record's whole discussion.\n in_reply_to:\n type: string\n pattern: \\S\n description: Link to the first comment of the thread this comment replies to. Absent on the first comment of a thread.\n motivation:\n enum:\n - commenting\n - replying\n - editing\n default: commenting\n description: commenting starts a thread, replying answers one, and editing suggests replacing the target's text.\n target:\n type: object\n description: Where in the document the thread is anchored. Absent means the whole record. Only the first comment of a thread has a target.\n properties:\n quote:\n type: object\n description: The anchored text and the text around it. The quote is authoritative; positions are a hint.\n required:\n - exact\n properties:\n exact:\n type: string\n description: The anchored text exactly as it appears in the record body. Empty for an insertion point, which prefix or suffix then locates.\n prefix:\n type: string\n description: Text immediately before exact, to tell repeated occurrences apart.\n suffix:\n type: string\n description: Text immediately after exact, to tell repeated occurrences apart.\n if:\n required:\n - exact\n properties:\n exact:\n type: string\n maxLength: 0\n then:\n anyOf:\n - required:\n - prefix\n properties:\n prefix:\n type: string\n minLength: 1\n - required:\n - suffix\n properties:\n suffix:\n type: string\n minLength: 1\n additionalProperties: false\n text_position:\n type: object\n description: Offsets of the quote in one revision of the record body.\n required:\n - basis\n - unit\n - start\n - end\n properties:\n basis:\n type: object\n required:\n - profile\n - hash\n properties:\n profile:\n const: markdown-body\n description: Offsets count the record's Markdown body as stored, after the frontmatter, so frontmatter edits never move them.\n hash:\n type: string\n pattern: ^sha256:[0-9a-f]{64}$\n description: SHA-256 of the UTF-8 body the offsets were measured in.\n additionalProperties: false\n unit:\n const: unicode_code_point\n start:\n type: integer\n minimum: 0\n end:\n type: integer\n minimum: 0\n additionalProperties: false\n required:\n - quote\n additionalProperties: false\n suggestion:\n type: object\n description: \"The suggested edit of an editing comment: replace the target's quote with replacement.\"\n required:\n - replacement\n properties:\n replacement:\n type: string\n description: The text to put in place of the quote. Empty suggests deleting it.\n outcome:\n enum:\n - accepted\n - rejected\n description: What happened to the suggestion once its thread was resolved.\n additionalProperties: false\n status:\n enum:\n - open\n - resolved\n default: open\n description: Whether the thread is still open. Only meaningful on the first comment of a thread.\n resolved_by:\n type: string\n pattern: \\S\n description: Link to the mdbase.person record of who resolved the thread.\n resolved_at:\n type: string\n format: date-time\n created_by:\n type: string\n pattern: \\S\n description: Link to the mdbase.person record of the comment's author. Absent when the author has no person record.\n created_at:\n type: string\n format: date-time\n modified_at:\n type: string\n format: date-time\n deleted_at:\n type: string\n format: date-time\n description: When the comment was withdrawn. The record stays so its thread and replies keep their shape; its body should be emptied.\n allOf:\n - if:\n properties:\n motivation:\n const: editing\n required:\n - motivation\n then:\n required:\n - target\n - suggestion\n properties:\n target:\n type: object\n suggestion:\n type: object\n additionalProperties: true\ncollection:\n links:\n document:\n target_type: any\n validate_exists: false\n in_reply_to:\n target_type: comment\n validate_exists: false\n created_by:\n target_type: any\n validate_exists: false\n resolved_by:\n target_type: any\n validate_exists: false\n display:\n description_field: document\n icon: chat-circle\nimplements:\n - contract: mdbase.comment\n version: 1.0.0\n fields:\n document: document\n in_reply_to: in_reply_to\n motivation: motivation\n target: target\n suggestion: suggestion\n status: status\n resolved_by: resolved_by\n resolved_at: resolved_at\n created_by: created_by\n created_at: created_at\n modified_at: modified_at\n deleted_at: deleted_at\n---\n\n# Comment\n\nOne note per comment, reply or suggested edit. Apps create these for you; the\ncommented note itself is never changed by commenting on it.\n\n```yaml\ntype: comment\ndocument: \"[[chapters/method]]\"\ntarget:\n quote: { exact: \"suggests strongly\", prefix: \"the evidence \", suffix: \" that\" }\ncreated_by: \"[[Alex Rivera]]\"\ncreated_at: 2026-09-29T10:00:00Z\n```\n\nThe note's body is the comment's text. A reply is another Comment note whose\n`in_reply_to` links to the thread's first comment. A suggested edit has\n`motivation: editing` and a `suggestion.replacement`.\n\n`document`, `in_reply_to`, `created_by` and `resolved_by` are links, so\nrenaming or moving a note with a tool that updates references keeps them\ncurrent. Links to a note that has since been deleted are kept, not treated as\nerrors. `created_by` and `resolved_by` link to Person notes; they are\neditable data, not proof of who wrote a comment.\n\nThis type belongs to your collection once installed. You can add fields, or\nrename fields and update the `implements` mapping; apps read comments through\nthe `mdbase.comment` contract, not through these local names.\n" + } + ], + "provides": [ + { + "id": "mdbase.comment", + "version": "1.0.0", + "digest": "sha256:c2c5b3f3013d10625310401e9f9149ffa2d09c5b7d91b4fc97688d3ac010bec5" + } + ] +} diff --git a/public/contracts/packs/mdbase.contact/1.3.0.json b/public/contracts/packs/mdbase.contact/1.3.0.json new file mode 100644 index 0000000..b6f6e4f --- /dev/null +++ b/public/contracts/packs/mdbase.contact/1.3.0.json @@ -0,0 +1,106 @@ +{ + "manifest": { + "kind": "mdbase.type-pack", + "id": "mdbase.contact", + "version": "1.3.0", + "name": "People type pack", + "description": "Portable people, editable account identity associations, and familiar contact fields.", + "resources": [ + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.person/1.0.0.schema.json", + "target": "schemas/mdbase.person/1.0.0.schema.json", + "digest": "sha256:3254afaa98c895e84fdc0aba299e67a0f3b594681c5581313ece5fcf4e2c6d93" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.person/1.0.0.md", + "target": "_contracts/mdbase.person/1.0.0.md", + "digest": "sha256:e2a9435ad01a2c06c151bf6af62a9d04aa30faa8e6128e4b5fe39378c767465c" + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.person/2.0.0.schema.json", + "target": "schemas/mdbase.person/2.0.0.schema.json", + "digest": "sha256:f9705e5869a2814086b907323749f63dce60de535728d6725601f02901ae60ac" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.person/2.0.0.md", + "target": "_contracts/mdbase.person/2.0.0.md", + "digest": "sha256:2899b149b1602bd4e51ff8e87c82dc92da3f690f4e89b1a6caf5b2b555540fe5" + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.contact/1.0.0.schema.json", + "target": "schemas/mdbase.contact/1.0.0.schema.json", + "digest": "sha256:bd8a011d18c71164b633f4e82cb33faa5b658cdba4f89312a34c13bf46a350d2" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.contact/1.0.0.md", + "target": "_contracts/mdbase.contact/1.0.0.md", + "digest": "sha256:e3634a35737ada5eb62e3e15f1c0c9d2e27c55a3f98dfab94bbc14c40404903d" + }, + { + "kind": "type", + "mode": "seed", + "source": "types/person/3.md", + "target": "_types/person.md", + "digest": "sha256:e74ebbce6c67e195a52d005c29ad63f93ae044800a857d33fb3bbc73135adb72", + "upgrade_from": { + "digest": "sha256:aa81c2964285ecc69fcb96bca4b6ae80bbddeb648908d840d7c7be50df15b362", + "document": "---\nkind: mdbase.type\nname: person\nversion: 2\ndescription: An individual that other notes link to, with a collection-owned display name and optional contact details and account associations.\nmatch:\n where:\n type: person\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: Person\n description: One person represented by an ordinary note. Contact details and account associations are optional; this record never grants access or membership.\n type: object\n required: [type, name]\n properties:\n type:\n const: person\n description: Identifies this note as a Person. Usually set by the application; changing it changes which type validates the note.\n name:\n type: string\n minLength: 1\n pattern: '\\S'\n description: The display name to use in this collection. Use a full name, preferred name, or single name as appropriate; no first/last-name split is required. It can differ from an account's name and is not automatically synchronised with it.\n identities:\n type: array\n description: Optional accounts associated with this person, each identified by an exact issuer and subject pair. Omit this field for someone without an account. These editable associations help applications find your person record; they are not proof of identity and never grant access. Avoid linking the same account to multiple person notes.\n uniqueItems: true\n items:\n type: object\n description: One account association supplied by its identity service. Both issuer and subject must match exactly; never infer them from a name or email.\n required: [issuer, subject]\n properties:\n issuer:\n type: string\n format: uri\n pattern: '^https?://'\n description: The exact identity-service issuer URL reported for this account. Preserve its scheme, case, path, and trailing slash; do not guess it from the collection's hosting address.\n subject:\n type: string\n pattern: '\\S'\n description: The opaque account identifier reported by that issuer, not a display name, email, password, or access token. Copy it exactly; a different issuer may use the same subject for a different account.\n additionalProperties: false\n kind:\n const: individual\n default: individual\n description: This Person starter represents an individual. The organisation field describes their affiliation, not a different record kind. Existing organisation or group contacts can keep their own Contact-compatible type.\n email:\n type: string\n format: email\n description: The preferred email address for contacting this person. Optional contact information only; it does not establish an account association or grant access.\n phone:\n type: string\n minLength: 1\n description: The preferred telephone number, stored as text so country codes, formatting, and extensions can be preserved. Include a country code when useful; omit if unknown.\n organisation:\n type: string\n minLength: 1\n description: The person's main affiliation, such as an employer, school, or community. A collection-owned display label, not a membership or access-control setting; omit if not relevant.\n birthday:\n type: string\n format: date\n description: A known birthday as a full calendar date in YYYY-MM-DD form. Omit if unknown or if only the month and day are known; do not invent a year. Consider whether this collection needs this personal information.\n additionalProperties: true\ncollection:\n display:\n name_field: name\n description_field: organisation\n icon: user\nimplements:\n - contract: mdbase.person\n version: 2.0.0\n fields:\n name: name\n identities: identities\n - contract: mdbase.contact\n version: 1.0.0\n fields:\n name: name\n kind: kind\n primary_email: email\n primary_phone: phone\n organisation: organisation\n birthday: birthday\n---\n\n# Person\n\nUse one note per individual, whether or not they have a Connect account. This\nsingle type supplies both a Person record and optional Contact details. You do\nnot need a second Contact note for the same person.\n\n## Start with a name\n\n```yaml\ntype: person\nname: Alex Rivera\n```\n\nOther notes refer to this person with an ordinary link to this note, such as\n`[[Alex Rivera]]` in a task's `assignees`. Links to this note appear in its\nbacklinks. Rename or move the note with a tool that updates references, as mdbase\nand Obsidian do, so those links stay current. Reusing a person's file name for\nsomebody else redirects existing links to the wrong person.\n\nThe name is your collection's display label. Full names, preferred names and\nsingle names are equally valid. There is no required first-name/last-name split.\n\n## Add only the contact details you need\n\nEmail, phone, organisation and birthday are optional. Omit unknown values rather\nthan filling them with empty strings or guesses. Store phone numbers as text,\nincluding an international prefix or extension when helpful. Birthday currently\nrequires a complete date; partial dates need a separately configured local field.\nKeep free-form context in the Markdown body and be deliberate about sensitive\npersonal information in shared collections.\n\nThis starter describes individuals. Existing organisation and group records can\ncontinue using their Contact-compatible type; setting someone's affiliation does\nnot turn their Person note into an organisation record.\n\n## Link accounts deliberately\n\nThe editor's **Link this record to me** action uses the authenticated account's\nactual issuer and subject. If configuring these manually, copy both exact values\nfrom the identity service. Do not guess them from an email, display name, or the\nserver hosting this collection. Multiple entries may represent the same person\nat different identity services. Omit `identities` when there is no account to link.\n\nAssociations are ordinary editable data, not authentication or proof of identity.\nLinking never invites someone, grants access, or changes collection membership.\nNever put credentials in a person record. Avoid linking the same account from\nseveral notes: applications should report ambiguity, not guess which\nrecord to use. Account deletion or recreation is not permission to reassign an\nold association automatically.\n\n## Keep the collection's own shape\n\nThe inline schema belongs to this collection. You may add local fields, or rename\nfields and update their explicit `implements` mappings. Apps use those mappings\nfor the Person and Contact contracts; they need not assume your local field names.\nAdditional fields remain part of the note but do not automatically become shared\ncontract fields. Do not edit published contracts to customise this type.\n\nInstalling a newer starter does not overwrite an existing customised type or\nmigrate your address book. Converting an existing individual Contact to Person\nshould be a reviewed edit of that one note, preserving its path, fields and body.\n" + } + } + ] + }, + "resources": [ + { + "source": "schemas/mdbase.person/1.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://mdbase.dev/contracts/schemas/mdbase.person/1.0.0.schema.json\",\n \"title\": \"Person\",\n \"description\": \"A portable person reference with editable account identity associations. Not an authentication or access-control assertion.\",\n \"type\": \"object\",\n \"required\": [\"id\", \"name\"],\n \"properties\": {\n \"id\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Stable person identifier used by references such as task assignments; independent of file path, name, account, and membership.\"\n },\n \"name\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Collection-owned display name, not a verified account name.\"\n },\n \"identities\": {\n \"type\": \"array\",\n \"uniqueItems\": true,\n \"description\": \"Editable identity associations. Missing or empty means this person has no linked account. Match issuer and subject exactly; never match by email or name.\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"issuer\", \"subject\"],\n \"properties\": {\n \"issuer\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"pattern\": \"^https?://\",\n \"description\": \"Stable issuer URL supplied by the identity service. Copy exactly; do not derive from a collection authority or relay URL.\"\n },\n \"subject\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Opaque, case-sensitive, account-wide identifier supplied by the issuer. Not an email, membership ID, or credential.\"\n }\n },\n \"additionalProperties\": false\n }\n }\n },\n \"additionalProperties\": false\n}\n" + }, + { + "source": "contracts/mdbase.person/1.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.person\nversion: 1.0.0\nname: Person\ndescription: A portable person reference with editable account identity associations.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.person/1.0.0.schema.json\n---\n\n# Person\n\nA person is collection data, independent of an account or collection membership.\nApplications reference the stable `id`, not a name, file path, email address,\naccount subject, or membership ID. Collections choose their own local type and\nfield names through explicit `implements` mappings.\n\n`name` is a collection-owned display label. `identities` optionally associates\nthis person with one or more accounts through issuer/subject pairs. A person\nwithout a Connect account is valid. The same record can travel between hosted,\nrelay, local, and exported collections without rewriting its identity references.\n\n## Identity matching\n\nAn identity service supplies the authenticated caller's issuer and subject.\nSubjects are opaque, account-wide identifiers, stable across email changes,\ncollection memberships, and removal/rejoining. Different identity issuers may\nuse the same subject; both fields must match exactly. Consumers must not trim,\ncase-fold, resolve redirects, or otherwise normalize either field when matching.\nCopy the issuer value supplied by the service, including its trailing-slash\nconvention. Never derive the issuer from the current collection authority URL.\nHTTP issuers support explicitly configured development and self-hosted instances;\nproduction deployments should use HTTPS.\n\nAn application resolves an identity across all implementing person records:\n\n- No matching person: unlinked, not anonymous authentication and not an error.\n- Exactly one matching record with an unambiguous person ID: linked.\n- Multiple matching records, or multiple records with that person's ID:\n ambiguous. Do not pick the first match, merge records, or overwrite a link.\n\nA partial or failed query cannot establish that a match is unique. Cross-record\nuniqueness is a collection/application invariant, not something this JSON Schema\ncan prove. Consumers must handle ambiguity even if a starter type has a local\nuniqueness constraint: several local types can implement this contract.\n\n## Editable data, not security authority\n\nIdentity associations have exactly the same trust as other editable collection\ndata. Editing one may change an application's \"Assigned to me\" view. It must\nnever change authentication, membership, permissions, authenticated audit\nattribution, or proof of identity to another service. Schema conformance proves\nshape, not that an identity association is truthful.\n\n\"Link this person to me\" is an ordinary record update using the authenticated\ncaller's identity. Never infer a link from a matching email or display name.\nMembership and current account display names come from the identity service,\nnot frontmatter. A person association must never invite someone or grant access.\n\n## Lifecycle and portability\n\nRenaming or moving a record does not change its ID. Removing a member does not\ndelete their person record or task assignments. Deleting a record leaves\nunresolved references; consumers should preserve these rather than silently\nunassigning work. Reusing an ID for a different person changes every reference\nand should not be treated as a routine rename.\n\nCopying records preserves account associations, but never copies collection\naccess. Multiple issuer/subject entries let one person represent accounts at\ndifferent identity services. Account deletion or an issuer migration may leave\nan unresolved identity association; do not automatically rebind it to a newly\ncreated account. Stored names and identity references remain collection data\nsubject to that collection's retention and editing policies.\n\nAccount-wide subjects deliberately allow correlation across collections. This\nis a portability trade-off, not an anonymity guarantee. Never store passwords,\naccess tokens, refresh tokens, or other credentials in these fields.\n\n## Contact information\n\nThis contract does not define another address book. A local type can also\nimplement `mdbase.contact` for compact contact semantics, or\n`mdbase.jscontact.card` when it intentionally stores that interchange shape.\nThe starter Person type implements both Person and Contact.\n" + }, + { + "source": "schemas/mdbase.person/2.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://mdbase.dev/contracts/schemas/mdbase.person/2.0.0.schema.json\",\n \"title\": \"Person\",\n \"description\": \"A person represented by a record, referenced by links to that record, with editable account identity associations. Not an authentication or access-control assertion.\",\n \"type\": \"object\",\n \"required\": [\n \"name\"\n ],\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Collection-owned display name, not a verified account name.\"\n },\n \"identities\": {\n \"type\": \"array\",\n \"uniqueItems\": true,\n \"description\": \"Editable identity associations. Missing or empty means this person has no linked account. Match issuer and subject exactly; never match by email or name.\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\n \"issuer\",\n \"subject\"\n ],\n \"properties\": {\n \"issuer\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"pattern\": \"^https?://\",\n \"description\": \"Stable issuer URL supplied by the identity service. Copy exactly; do not derive from a collection authority or relay URL.\"\n },\n \"subject\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Opaque, case-sensitive, account-wide identifier supplied by the issuer. Not an email, membership ID, or credential.\"\n }\n },\n \"additionalProperties\": false\n }\n }\n },\n \"additionalProperties\": false\n}\n" + }, + { + "source": "contracts/mdbase.person/2.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.person\nversion: 2.0.0\nname: Person\ndescription: A person record, referenced by links, with editable account identity associations.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.person/2.0.0.schema.json\n---\n\n# Person\n\nA person is collection data, independent of an account or collection membership.\nOther records refer to a person with an ordinary mdbase link to the person's\nrecord, such as `\"[[Alex Rivera]]\"`, declared in the referring type's\n`collection.links` and resolved with the collection's own link rules. Never\nrefer to a person by name text, email address, account subject, or membership\nID. Collections choose their own local type and field names through explicit\n`implements` mappings.\n\nVersion 2.0.0 removes the separate `id` field of 1.0.0. Link resolution already\nidentifies the record, and rename reference updates keep links current, so a\nsecond identifier only created a way for the two to disagree.\n\n`name` is a collection-owned display label. `identities` optionally associates\nthis person with one or more accounts through issuer/subject pairs. A person\nwithout a Connect account is valid. The same record can travel between hosted,\nrelay, local, and exported collections without rewriting its identity references.\n\n## Identity matching\n\nAn identity service supplies the authenticated caller's issuer and subject.\nSubjects are opaque, account-wide identifiers, stable across email changes,\ncollection memberships, and removal/rejoining. Different identity issuers may\nuse the same subject; both fields must match exactly. Consumers must not trim,\ncase-fold, resolve redirects, or otherwise normalize either field when matching.\nCopy the issuer value supplied by the service, including its trailing-slash\nconvention. Never derive the issuer from the current collection authority URL.\nHTTP issuers support explicitly configured development and self-hosted instances;\nproduction deployments should use HTTPS.\n\nAn application resolves an identity across all implementing person records:\n\n- No matching person: unlinked, not anonymous authentication and not an error.\n- Exactly one matching record: linked.\n- Multiple matching records: ambiguous. Do not pick the first match, merge\n records, or overwrite a link.\n\nA partial or failed query cannot establish that a match is unique. Consumers\nmust handle ambiguity: several records, possibly of several local types, can\nclaim the same identity.\n\n## Editable data, not security authority\n\nIdentity associations have exactly the same trust as other editable collection\ndata. Editing one may change an application's \"Assigned to me\" view. It must\nnever change authentication, membership, permissions, authenticated audit\nattribution, or proof of identity to another service. Schema conformance proves\nshape, not that an identity association is truthful.\n\n\"Link this person to me\" is an ordinary record update using the authenticated\ncaller's identity. Never infer a link from a matching email or display name.\nMembership and current account display names come from the identity service,\nnot frontmatter. A person association must never invite someone or grant access.\n\n## Lifecycle and portability\n\nRenaming or moving a person record through mdbase or an editor that updates\nreferences keeps links to it current. Removing a member does not delete their\nperson record or task assignments. Deleting a record leaves unresolved links;\nconsumers should preserve these rather than silently unassigning work. Giving a\ndifferent person's record the old record's name or path redirects existing\nlinks and should not be treated as a routine rename.\n\nCopying records preserves account associations, but never copies collection\naccess. Multiple issuer/subject entries let one person represent accounts at\ndifferent identity services. Account deletion or an issuer migration may leave\nan unresolved identity association; do not automatically rebind it to a newly\ncreated account. Stored names and identity references remain collection data\nsubject to that collection's retention and editing policies.\n\nAccount-wide subjects deliberately allow correlation across collections. This\nis a portability trade-off, not an anonymity guarantee. Never store passwords,\naccess tokens, refresh tokens, or other credentials in these fields.\n\n## Contact information\n\nThis contract does not define another address book. A local type can also\nimplement `mdbase.contact` for compact contact semantics, or\n`mdbase.jscontact.card` when it intentionally stores that interchange shape.\nThe starter Person type implements both Person and Contact.\n" + }, + { + "source": "schemas/mdbase.contact/1.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://mdbase.dev/contracts/schemas/mdbase.contact/1.0.0.schema.json\",\n \"title\": \"Contact\",\n \"description\": \"A compact application-facing contact view.\",\n \"type\": \"object\",\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"The name applications should use when presenting this contact.\"\n },\n \"kind\": {\n \"type\": \"string\",\n \"enum\": [\"individual\", \"organisation\", \"group\"],\n \"description\": \"The broad kind of contact when the collection distinguishes it.\"\n },\n \"primary_email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"description\": \"The preferred email address for this contact.\"\n },\n \"primary_phone\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"The preferred telephone number for this contact.\"\n },\n \"organisation\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"The organisation most closely associated with this contact.\"\n },\n \"birthday\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"The contact's birthday when known.\"\n }\n },\n \"additionalProperties\": false\n}\n" + }, + { + "source": "contracts/mdbase.contact/1.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.contact\nversion: 1.0.0\nname: Contact\ndescription: A compact application-facing view of a person or organisation.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.contact/1.0.0.schema.json\n---\n\n# Contact\n\nThis contract exposes the small set of contact semantics commonly shared by\naddress books, relationship tools, and other applications. A collection keeps\nits own field names and may store richer local data; the implementing type maps\nonly the fields it wants applications to see.\n\nThe contract is deliberately not an interchange format. Exporters can convert\nthis view to JSContact, vCard, or another wire representation without requiring\nMarkdown records to store that representation directly.\n" + }, + { + "source": "types/person/3.md", + "document": "---\nkind: mdbase.type\nname: person\nversion: 3\ndescription: An individual that other notes link to, with a collection-owned display name and optional contact details and account associations.\nmatch:\n where:\n type: person\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: Person\n description: One person represented by an ordinary note. Contact details and account associations are optional; this record never grants access or membership.\n type: object\n required: [name]\n properties:\n name:\n type: string\n minLength: 1\n pattern: '\\S'\n description: The display name to use in this collection. Use a full name, preferred name, or single name as appropriate; no first/last-name split is required. It can differ from an account's name and is not automatically synchronised with it.\n identities:\n type: array\n description: Optional accounts associated with this person, each identified by an exact issuer and subject pair. Omit this field for someone without an account. These editable associations help applications find your person record; they are not proof of identity and never grant access. Avoid linking the same account to multiple person notes.\n uniqueItems: true\n items:\n type: object\n description: One account association supplied by its identity service. Both issuer and subject must match exactly; never infer them from a name or email.\n required: [issuer, subject]\n properties:\n issuer:\n type: string\n format: uri\n pattern: '^https?://'\n description: The exact identity-service issuer URL reported for this account. Preserve its scheme, case, path, and trailing slash; do not guess it from the collection's hosting address.\n subject:\n type: string\n pattern: '\\S'\n description: The opaque account identifier reported by that issuer, not a display name, email, password, or access token. Copy it exactly; a different issuer may use the same subject for a different account.\n additionalProperties: false\n kind:\n const: individual\n default: individual\n description: This Person starter represents an individual. The organisation field describes their affiliation, not a different record kind. Existing organisation or group contacts can keep their own Contact-compatible type.\n email:\n type: string\n format: email\n description: The preferred email address for contacting this person. Optional contact information only; it does not establish an account association or grant access.\n phone:\n type: string\n minLength: 1\n description: The preferred telephone number, stored as text so country codes, formatting, and extensions can be preserved. Include a country code when useful; omit if unknown.\n organisation:\n type: string\n minLength: 1\n description: The person's main affiliation, such as an employer, school, or community. A collection-owned display label, not a membership or access-control setting; omit if not relevant.\n birthday:\n type: string\n format: date\n description: A known birthday as a full calendar date in YYYY-MM-DD form. Omit if unknown or if only the month and day are known; do not invent a year. Consider whether this collection needs this personal information.\n additionalProperties: true\ncollection:\n display:\n name_field: name\n description_field: organisation\n icon: user\nimplements:\n - contract: mdbase.person\n version: 2.0.0\n fields:\n name: name\n identities: identities\n - contract: mdbase.contact\n version: 1.0.0\n fields:\n name: name\n kind: kind\n primary_email: email\n primary_phone: phone\n organisation: organisation\n birthday: birthday\n---\n\n# Person\n\nUse one note per individual, whether or not they have a Connect account. This\nsingle type supplies both a Person record and optional Contact details. You do\nnot need a second Contact note for the same person.\n\n## Start with a name\n\n```yaml\ntype: person\nname: Alex Rivera\n```\n\nOther notes refer to this person with an ordinary link to this note, such as\n`[[Alex Rivera]]` in a task's `assignees`. Links to this note appear in its\nbacklinks. Rename or move the note with a tool that updates references, as mdbase\nand Obsidian do, so those links stay current. Reusing a person's file name for\nsomebody else redirects existing links to the wrong person.\n\nThe name is your collection's display label. Full names, preferred names and\nsingle names are equally valid. There is no required first-name/last-name split.\n\n## Add only the contact details you need\n\nEmail, phone, organisation and birthday are optional. Omit unknown values rather\nthan filling them with empty strings or guesses. Store phone numbers as text,\nincluding an international prefix or extension when helpful. Birthday currently\nrequires a complete date; partial dates need a separately configured local field.\nKeep free-form context in the Markdown body and be deliberate about sensitive\npersonal information in shared collections.\n\nThis starter describes individuals. Existing organisation and group records can\ncontinue using their Contact-compatible type; setting someone's affiliation does\nnot turn their Person note into an organisation record.\n\n## Link accounts deliberately\n\nThe editor's **Link this record to me** action uses the authenticated account's\nactual issuer and subject. If configuring these manually, copy both exact values\nfrom the identity service. Do not guess them from an email, display name, or the\nserver hosting this collection. Multiple entries may represent the same person\nat different identity services. Omit `identities` when there is no account to link.\n\nAssociations are ordinary editable data, not authentication or proof of identity.\nLinking never invites someone, grants access, or changes collection membership.\nNever put credentials in a person record. Avoid linking the same account from\nseveral notes: applications should report ambiguity, not guess which\nrecord to use. Account deletion or recreation is not permission to reassign an\nold association automatically.\n\n## Keep the collection's own shape\n\nThe inline schema belongs to this collection. You may add local fields, or rename\nfields and update their explicit `implements` mappings. Apps use those mappings\nfor the Person and Contact contracts; they need not assume your local field names.\nAdditional fields remain part of the note but do not automatically become shared\ncontract fields. Do not edit published contracts to customise this type.\n\nInstalling a newer starter does not overwrite an existing customised type or\nmigrate your address book. Converting an existing individual Contact to Person\nshould be a reviewed edit of that one note, preserving its path, fields and body.\n" + } + ], + "provides": [ + { + "id": "mdbase.person", + "version": "2.0.0", + "digest": "sha256:f16c462a1fd422f44ed055002f8476ec53c164107647fec782aeb74adeab2f9d" + }, + { + "id": "mdbase.contact", + "version": "1.0.0", + "digest": "sha256:49cfe15403dfc741a693e89a2f4d2857de306f391d02cb03e67bfaf0aa1d6b0d" + } + ] +} diff --git a/public/contracts/packs/mdbase.contact/1.4.0.json b/public/contracts/packs/mdbase.contact/1.4.0.json new file mode 100644 index 0000000..b58cbb5 --- /dev/null +++ b/public/contracts/packs/mdbase.contact/1.4.0.json @@ -0,0 +1,114 @@ +{ + "manifest": { + "kind": "mdbase.type-pack", + "id": "mdbase.contact", + "version": "1.4.0", + "name": "People type pack", + "description": "Portable people, editable account identity associations, and familiar contact fields.", + "resources": [ + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.person/1.0.0.schema.json", + "target": "schemas/mdbase.person/1.0.0.schema.json", + "digest": "sha256:3254afaa98c895e84fdc0aba299e67a0f3b594681c5581313ece5fcf4e2c6d93" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.person/1.0.0.md", + "target": "_contracts/mdbase.person/1.0.0.md", + "digest": "sha256:e2a9435ad01a2c06c151bf6af62a9d04aa30faa8e6128e4b5fe39378c767465c" + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.person/2.0.0.schema.json", + "target": "schemas/mdbase.person/2.0.0.schema.json", + "digest": "sha256:f9705e5869a2814086b907323749f63dce60de535728d6725601f02901ae60ac" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.person/2.0.0.md", + "target": "_contracts/mdbase.person/2.0.0.md", + "digest": "sha256:2899b149b1602bd4e51ff8e87c82dc92da3f690f4e89b1a6caf5b2b555540fe5" + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.contact/1.0.0.schema.json", + "target": "schemas/mdbase.contact/1.0.0.schema.json", + "digest": "sha256:bd8a011d18c71164b633f4e82cb33faa5b658cdba4f89312a34c13bf46a350d2" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.contact/1.0.0.md", + "target": "_contracts/mdbase.contact/1.0.0.md", + "digest": "sha256:e3634a35737ada5eb62e3e15f1c0c9d2e27c55a3f98dfab94bbc14c40404903d" + }, + { + "kind": "type", + "mode": "seed", + "source": "types/person/3.md", + "target": "_types/person.md", + "digest": "sha256:e74ebbce6c67e195a52d005c29ad63f93ae044800a857d33fb3bbc73135adb72", + "upgrade_from": [ + { + "digest": "sha256:aa81c2964285ecc69fcb96bca4b6ae80bbddeb648908d840d7c7be50df15b362", + "version": 2, + "document": "---\nkind: mdbase.type\nname: person\nversion: 2\ndescription: An individual that other notes link to, with a collection-owned display name and optional contact details and account associations.\nmatch:\n where:\n type: person\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: Person\n description: One person represented by an ordinary note. Contact details and account associations are optional; this record never grants access or membership.\n type: object\n required: [type, name]\n properties:\n type:\n const: person\n description: Identifies this note as a Person. Usually set by the application; changing it changes which type validates the note.\n name:\n type: string\n minLength: 1\n pattern: '\\S'\n description: The display name to use in this collection. Use a full name, preferred name, or single name as appropriate; no first/last-name split is required. It can differ from an account's name and is not automatically synchronised with it.\n identities:\n type: array\n description: Optional accounts associated with this person, each identified by an exact issuer and subject pair. Omit this field for someone without an account. These editable associations help applications find your person record; they are not proof of identity and never grant access. Avoid linking the same account to multiple person notes.\n uniqueItems: true\n items:\n type: object\n description: One account association supplied by its identity service. Both issuer and subject must match exactly; never infer them from a name or email.\n required: [issuer, subject]\n properties:\n issuer:\n type: string\n format: uri\n pattern: '^https?://'\n description: The exact identity-service issuer URL reported for this account. Preserve its scheme, case, path, and trailing slash; do not guess it from the collection's hosting address.\n subject:\n type: string\n pattern: '\\S'\n description: The opaque account identifier reported by that issuer, not a display name, email, password, or access token. Copy it exactly; a different issuer may use the same subject for a different account.\n additionalProperties: false\n kind:\n const: individual\n default: individual\n description: This Person starter represents an individual. The organisation field describes their affiliation, not a different record kind. Existing organisation or group contacts can keep their own Contact-compatible type.\n email:\n type: string\n format: email\n description: The preferred email address for contacting this person. Optional contact information only; it does not establish an account association or grant access.\n phone:\n type: string\n minLength: 1\n description: The preferred telephone number, stored as text so country codes, formatting, and extensions can be preserved. Include a country code when useful; omit if unknown.\n organisation:\n type: string\n minLength: 1\n description: The person's main affiliation, such as an employer, school, or community. A collection-owned display label, not a membership or access-control setting; omit if not relevant.\n birthday:\n type: string\n format: date\n description: A known birthday as a full calendar date in YYYY-MM-DD form. Omit if unknown or if only the month and day are known; do not invent a year. Consider whether this collection needs this personal information.\n additionalProperties: true\ncollection:\n display:\n name_field: name\n description_field: organisation\n icon: user\nimplements:\n - contract: mdbase.person\n version: 2.0.0\n fields:\n name: name\n identities: identities\n - contract: mdbase.contact\n version: 1.0.0\n fields:\n name: name\n kind: kind\n primary_email: email\n primary_phone: phone\n organisation: organisation\n birthday: birthday\n---\n\n# Person\n\nUse one note per individual, whether or not they have a Connect account. This\nsingle type supplies both a Person record and optional Contact details. You do\nnot need a second Contact note for the same person.\n\n## Start with a name\n\n```yaml\ntype: person\nname: Alex Rivera\n```\n\nOther notes refer to this person with an ordinary link to this note, such as\n`[[Alex Rivera]]` in a task's `assignees`. Links to this note appear in its\nbacklinks. Rename or move the note with a tool that updates references, as mdbase\nand Obsidian do, so those links stay current. Reusing a person's file name for\nsomebody else redirects existing links to the wrong person.\n\nThe name is your collection's display label. Full names, preferred names and\nsingle names are equally valid. There is no required first-name/last-name split.\n\n## Add only the contact details you need\n\nEmail, phone, organisation and birthday are optional. Omit unknown values rather\nthan filling them with empty strings or guesses. Store phone numbers as text,\nincluding an international prefix or extension when helpful. Birthday currently\nrequires a complete date; partial dates need a separately configured local field.\nKeep free-form context in the Markdown body and be deliberate about sensitive\npersonal information in shared collections.\n\nThis starter describes individuals. Existing organisation and group records can\ncontinue using their Contact-compatible type; setting someone's affiliation does\nnot turn their Person note into an organisation record.\n\n## Link accounts deliberately\n\nThe editor's **Link this record to me** action uses the authenticated account's\nactual issuer and subject. If configuring these manually, copy both exact values\nfrom the identity service. Do not guess them from an email, display name, or the\nserver hosting this collection. Multiple entries may represent the same person\nat different identity services. Omit `identities` when there is no account to link.\n\nAssociations are ordinary editable data, not authentication or proof of identity.\nLinking never invites someone, grants access, or changes collection membership.\nNever put credentials in a person record. Avoid linking the same account from\nseveral notes: applications should report ambiguity, not guess which\nrecord to use. Account deletion or recreation is not permission to reassign an\nold association automatically.\n\n## Keep the collection's own shape\n\nThe inline schema belongs to this collection. You may add local fields, or rename\nfields and update their explicit `implements` mappings. Apps use those mappings\nfor the Person and Contact contracts; they need not assume your local field names.\nAdditional fields remain part of the note but do not automatically become shared\ncontract fields. Do not edit published contracts to customise this type.\n\nInstalling a newer starter does not overwrite an existing customised type or\nmigrate your address book. Converting an existing individual Contact to Person\nshould be a reviewed edit of that one note, preserving its path, fields and body.\n" + }, + { + "digest": "sha256:18896ac3086c7fdcb64748babd7dd8263dbece4fcc6bcf43a53f74d51bcece5e", + "version": 1, + "document": "---\nkind: mdbase.type\nname: person\nversion: 1\ndescription: A portable person with optional account identities and contact information\nmatch:\n where:\n type: person\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: Person\n type: object\n required: [type, id, name]\n properties:\n type:\n const: person\n id:\n type: string\n pattern: '\\S'\n description: Stable person ID; keep this when moving or renaming the note.\n name:\n type: string\n minLength: 1\n pattern: '\\S'\n identities:\n type: array\n uniqueItems: true\n items:\n type: object\n required: [issuer, subject]\n properties:\n issuer:\n type: string\n format: uri\n pattern: '^https?://'\n subject:\n type: string\n pattern: '\\S'\n additionalProperties: false\n kind:\n const: individual\n default: individual\n email:\n type: string\n format: email\n phone:\n type: string\n minLength: 1\n organisation:\n type: string\n minLength: 1\n birthday:\n type: string\n format: date\n additionalProperties: true\ncollection:\n display:\n name_field: name\n description_field: organisation\n icon: user\n unique:\n - field: id\n scope: collection\nimplements:\n - contract: mdbase.person\n version: 1.0.0\n fields:\n id: id\n name: name\n identities: identities\n - contract: mdbase.contact\n version: 1.0.0\n fields:\n name: name\n kind: kind\n primary_email: email\n primary_phone: phone\n organisation: organisation\n birthday: birthday\n---\n\n# Person\n\nCreate a stable ID when adding a person, for example `person_` followed by a\nrandom UUID. Keep it when copying the note to another collection or renaming\nits file. Apps use this ID for assignments and other person references.\n\n```yaml\ntype: person\nid: person_2c1343ec-cac1-4d58-98c9-41736f4de7db\nname: Callum\nidentities:\n - issuer: https://connect.example\n subject: usr_789\n```\n\nUse the actual issuer and subject supplied by Connect, not the example values.\nOmit `identities` for people without accounts. Email is contact information,\nnot a way to establish an identity association. Linking a person does not\ninvite them or grant access to this collection.\n\nIdentity associations and contact labels are ordinary editable data. They are\nnot proof of authentication. Avoid duplicate person IDs or identity pairs\nacross person notes; applications must report ambiguity rather than guess.\n\nThe inline schema belongs to the collection. Add local fields or rename them\nand update the explicit contract mappings without editing published contracts.\n" + } + ] + } + ] + }, + "resources": [ + { + "source": "schemas/mdbase.person/1.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://mdbase.dev/contracts/schemas/mdbase.person/1.0.0.schema.json\",\n \"title\": \"Person\",\n \"description\": \"A portable person reference with editable account identity associations. Not an authentication or access-control assertion.\",\n \"type\": \"object\",\n \"required\": [\"id\", \"name\"],\n \"properties\": {\n \"id\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Stable person identifier used by references such as task assignments; independent of file path, name, account, and membership.\"\n },\n \"name\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Collection-owned display name, not a verified account name.\"\n },\n \"identities\": {\n \"type\": \"array\",\n \"uniqueItems\": true,\n \"description\": \"Editable identity associations. Missing or empty means this person has no linked account. Match issuer and subject exactly; never match by email or name.\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"issuer\", \"subject\"],\n \"properties\": {\n \"issuer\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"pattern\": \"^https?://\",\n \"description\": \"Stable issuer URL supplied by the identity service. Copy exactly; do not derive from a collection authority or relay URL.\"\n },\n \"subject\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Opaque, case-sensitive, account-wide identifier supplied by the issuer. Not an email, membership ID, or credential.\"\n }\n },\n \"additionalProperties\": false\n }\n }\n },\n \"additionalProperties\": false\n}\n" + }, + { + "source": "contracts/mdbase.person/1.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.person\nversion: 1.0.0\nname: Person\ndescription: A portable person reference with editable account identity associations.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.person/1.0.0.schema.json\n---\n\n# Person\n\nA person is collection data, independent of an account or collection membership.\nApplications reference the stable `id`, not a name, file path, email address,\naccount subject, or membership ID. Collections choose their own local type and\nfield names through explicit `implements` mappings.\n\n`name` is a collection-owned display label. `identities` optionally associates\nthis person with one or more accounts through issuer/subject pairs. A person\nwithout a Connect account is valid. The same record can travel between hosted,\nrelay, local, and exported collections without rewriting its identity references.\n\n## Identity matching\n\nAn identity service supplies the authenticated caller's issuer and subject.\nSubjects are opaque, account-wide identifiers, stable across email changes,\ncollection memberships, and removal/rejoining. Different identity issuers may\nuse the same subject; both fields must match exactly. Consumers must not trim,\ncase-fold, resolve redirects, or otherwise normalize either field when matching.\nCopy the issuer value supplied by the service, including its trailing-slash\nconvention. Never derive the issuer from the current collection authority URL.\nHTTP issuers support explicitly configured development and self-hosted instances;\nproduction deployments should use HTTPS.\n\nAn application resolves an identity across all implementing person records:\n\n- No matching person: unlinked, not anonymous authentication and not an error.\n- Exactly one matching record with an unambiguous person ID: linked.\n- Multiple matching records, or multiple records with that person's ID:\n ambiguous. Do not pick the first match, merge records, or overwrite a link.\n\nA partial or failed query cannot establish that a match is unique. Cross-record\nuniqueness is a collection/application invariant, not something this JSON Schema\ncan prove. Consumers must handle ambiguity even if a starter type has a local\nuniqueness constraint: several local types can implement this contract.\n\n## Editable data, not security authority\n\nIdentity associations have exactly the same trust as other editable collection\ndata. Editing one may change an application's \"Assigned to me\" view. It must\nnever change authentication, membership, permissions, authenticated audit\nattribution, or proof of identity to another service. Schema conformance proves\nshape, not that an identity association is truthful.\n\n\"Link this person to me\" is an ordinary record update using the authenticated\ncaller's identity. Never infer a link from a matching email or display name.\nMembership and current account display names come from the identity service,\nnot frontmatter. A person association must never invite someone or grant access.\n\n## Lifecycle and portability\n\nRenaming or moving a record does not change its ID. Removing a member does not\ndelete their person record or task assignments. Deleting a record leaves\nunresolved references; consumers should preserve these rather than silently\nunassigning work. Reusing an ID for a different person changes every reference\nand should not be treated as a routine rename.\n\nCopying records preserves account associations, but never copies collection\naccess. Multiple issuer/subject entries let one person represent accounts at\ndifferent identity services. Account deletion or an issuer migration may leave\nan unresolved identity association; do not automatically rebind it to a newly\ncreated account. Stored names and identity references remain collection data\nsubject to that collection's retention and editing policies.\n\nAccount-wide subjects deliberately allow correlation across collections. This\nis a portability trade-off, not an anonymity guarantee. Never store passwords,\naccess tokens, refresh tokens, or other credentials in these fields.\n\n## Contact information\n\nThis contract does not define another address book. A local type can also\nimplement `mdbase.contact` for compact contact semantics, or\n`mdbase.jscontact.card` when it intentionally stores that interchange shape.\nThe starter Person type implements both Person and Contact.\n" + }, + { + "source": "schemas/mdbase.person/2.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://mdbase.dev/contracts/schemas/mdbase.person/2.0.0.schema.json\",\n \"title\": \"Person\",\n \"description\": \"A person represented by a record, referenced by links to that record, with editable account identity associations. Not an authentication or access-control assertion.\",\n \"type\": \"object\",\n \"required\": [\n \"name\"\n ],\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Collection-owned display name, not a verified account name.\"\n },\n \"identities\": {\n \"type\": \"array\",\n \"uniqueItems\": true,\n \"description\": \"Editable identity associations. Missing or empty means this person has no linked account. Match issuer and subject exactly; never match by email or name.\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\n \"issuer\",\n \"subject\"\n ],\n \"properties\": {\n \"issuer\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"pattern\": \"^https?://\",\n \"description\": \"Stable issuer URL supplied by the identity service. Copy exactly; do not derive from a collection authority or relay URL.\"\n },\n \"subject\": {\n \"type\": \"string\",\n \"pattern\": \"\\\\S\",\n \"description\": \"Opaque, case-sensitive, account-wide identifier supplied by the issuer. Not an email, membership ID, or credential.\"\n }\n },\n \"additionalProperties\": false\n }\n }\n },\n \"additionalProperties\": false\n}\n" + }, + { + "source": "contracts/mdbase.person/2.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.person\nversion: 2.0.0\nname: Person\ndescription: A person record, referenced by links, with editable account identity associations.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.person/2.0.0.schema.json\n---\n\n# Person\n\nA person is collection data, independent of an account or collection membership.\nOther records refer to a person with an ordinary mdbase link to the person's\nrecord, such as `\"[[Alex Rivera]]\"`, declared in the referring type's\n`collection.links` and resolved with the collection's own link rules. Never\nrefer to a person by name text, email address, account subject, or membership\nID. Collections choose their own local type and field names through explicit\n`implements` mappings.\n\nVersion 2.0.0 removes the separate `id` field of 1.0.0. Link resolution already\nidentifies the record, and rename reference updates keep links current, so a\nsecond identifier only created a way for the two to disagree.\n\n`name` is a collection-owned display label. `identities` optionally associates\nthis person with one or more accounts through issuer/subject pairs. A person\nwithout a Connect account is valid. The same record can travel between hosted,\nrelay, local, and exported collections without rewriting its identity references.\n\n## Identity matching\n\nAn identity service supplies the authenticated caller's issuer and subject.\nSubjects are opaque, account-wide identifiers, stable across email changes,\ncollection memberships, and removal/rejoining. Different identity issuers may\nuse the same subject; both fields must match exactly. Consumers must not trim,\ncase-fold, resolve redirects, or otherwise normalize either field when matching.\nCopy the issuer value supplied by the service, including its trailing-slash\nconvention. Never derive the issuer from the current collection authority URL.\nHTTP issuers support explicitly configured development and self-hosted instances;\nproduction deployments should use HTTPS.\n\nAn application resolves an identity across all implementing person records:\n\n- No matching person: unlinked, not anonymous authentication and not an error.\n- Exactly one matching record: linked.\n- Multiple matching records: ambiguous. Do not pick the first match, merge\n records, or overwrite a link.\n\nA partial or failed query cannot establish that a match is unique. Consumers\nmust handle ambiguity: several records, possibly of several local types, can\nclaim the same identity.\n\n## Editable data, not security authority\n\nIdentity associations have exactly the same trust as other editable collection\ndata. Editing one may change an application's \"Assigned to me\" view. It must\nnever change authentication, membership, permissions, authenticated audit\nattribution, or proof of identity to another service. Schema conformance proves\nshape, not that an identity association is truthful.\n\n\"Link this person to me\" is an ordinary record update using the authenticated\ncaller's identity. Never infer a link from a matching email or display name.\nMembership and current account display names come from the identity service,\nnot frontmatter. A person association must never invite someone or grant access.\n\n## Lifecycle and portability\n\nRenaming or moving a person record through mdbase or an editor that updates\nreferences keeps links to it current. Removing a member does not delete their\nperson record or task assignments. Deleting a record leaves unresolved links;\nconsumers should preserve these rather than silently unassigning work. Giving a\ndifferent person's record the old record's name or path redirects existing\nlinks and should not be treated as a routine rename.\n\nCopying records preserves account associations, but never copies collection\naccess. Multiple issuer/subject entries let one person represent accounts at\ndifferent identity services. Account deletion or an issuer migration may leave\nan unresolved identity association; do not automatically rebind it to a newly\ncreated account. Stored names and identity references remain collection data\nsubject to that collection's retention and editing policies.\n\nAccount-wide subjects deliberately allow correlation across collections. This\nis a portability trade-off, not an anonymity guarantee. Never store passwords,\naccess tokens, refresh tokens, or other credentials in these fields.\n\n## Contact information\n\nThis contract does not define another address book. A local type can also\nimplement `mdbase.contact` for compact contact semantics, or\n`mdbase.jscontact.card` when it intentionally stores that interchange shape.\nThe starter Person type implements both Person and Contact.\n" + }, + { + "source": "schemas/mdbase.contact/1.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://mdbase.dev/contracts/schemas/mdbase.contact/1.0.0.schema.json\",\n \"title\": \"Contact\",\n \"description\": \"A compact application-facing contact view.\",\n \"type\": \"object\",\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"The name applications should use when presenting this contact.\"\n },\n \"kind\": {\n \"type\": \"string\",\n \"enum\": [\"individual\", \"organisation\", \"group\"],\n \"description\": \"The broad kind of contact when the collection distinguishes it.\"\n },\n \"primary_email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"description\": \"The preferred email address for this contact.\"\n },\n \"primary_phone\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"The preferred telephone number for this contact.\"\n },\n \"organisation\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"The organisation most closely associated with this contact.\"\n },\n \"birthday\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"The contact's birthday when known.\"\n }\n },\n \"additionalProperties\": false\n}\n" + }, + { + "source": "contracts/mdbase.contact/1.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.contact\nversion: 1.0.0\nname: Contact\ndescription: A compact application-facing view of a person or organisation.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.contact/1.0.0.schema.json\n---\n\n# Contact\n\nThis contract exposes the small set of contact semantics commonly shared by\naddress books, relationship tools, and other applications. A collection keeps\nits own field names and may store richer local data; the implementing type maps\nonly the fields it wants applications to see.\n\nThe contract is deliberately not an interchange format. Exporters can convert\nthis view to JSContact, vCard, or another wire representation without requiring\nMarkdown records to store that representation directly.\n" + }, + { + "source": "types/person/3.md", + "document": "---\nkind: mdbase.type\nname: person\nversion: 3\ndescription: An individual that other notes link to, with a collection-owned display name and optional contact details and account associations.\nmatch:\n where:\n type: person\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: Person\n description: One person represented by an ordinary note. Contact details and account associations are optional; this record never grants access or membership.\n type: object\n required: [name]\n properties:\n name:\n type: string\n minLength: 1\n pattern: '\\S'\n description: The display name to use in this collection. Use a full name, preferred name, or single name as appropriate; no first/last-name split is required. It can differ from an account's name and is not automatically synchronised with it.\n identities:\n type: array\n description: Optional accounts associated with this person, each identified by an exact issuer and subject pair. Omit this field for someone without an account. These editable associations help applications find your person record; they are not proof of identity and never grant access. Avoid linking the same account to multiple person notes.\n uniqueItems: true\n items:\n type: object\n description: One account association supplied by its identity service. Both issuer and subject must match exactly; never infer them from a name or email.\n required: [issuer, subject]\n properties:\n issuer:\n type: string\n format: uri\n pattern: '^https?://'\n description: The exact identity-service issuer URL reported for this account. Preserve its scheme, case, path, and trailing slash; do not guess it from the collection's hosting address.\n subject:\n type: string\n pattern: '\\S'\n description: The opaque account identifier reported by that issuer, not a display name, email, password, or access token. Copy it exactly; a different issuer may use the same subject for a different account.\n additionalProperties: false\n kind:\n const: individual\n default: individual\n description: This Person starter represents an individual. The organisation field describes their affiliation, not a different record kind. Existing organisation or group contacts can keep their own Contact-compatible type.\n email:\n type: string\n format: email\n description: The preferred email address for contacting this person. Optional contact information only; it does not establish an account association or grant access.\n phone:\n type: string\n minLength: 1\n description: The preferred telephone number, stored as text so country codes, formatting, and extensions can be preserved. Include a country code when useful; omit if unknown.\n organisation:\n type: string\n minLength: 1\n description: The person's main affiliation, such as an employer, school, or community. A collection-owned display label, not a membership or access-control setting; omit if not relevant.\n birthday:\n type: string\n format: date\n description: A known birthday as a full calendar date in YYYY-MM-DD form. Omit if unknown or if only the month and day are known; do not invent a year. Consider whether this collection needs this personal information.\n additionalProperties: true\ncollection:\n display:\n name_field: name\n description_field: organisation\n icon: user\nimplements:\n - contract: mdbase.person\n version: 2.0.0\n fields:\n name: name\n identities: identities\n - contract: mdbase.contact\n version: 1.0.0\n fields:\n name: name\n kind: kind\n primary_email: email\n primary_phone: phone\n organisation: organisation\n birthday: birthday\n---\n\n# Person\n\nUse one note per individual, whether or not they have a Connect account. This\nsingle type supplies both a Person record and optional Contact details. You do\nnot need a second Contact note for the same person.\n\n## Start with a name\n\n```yaml\ntype: person\nname: Alex Rivera\n```\n\nOther notes refer to this person with an ordinary link to this note, such as\n`[[Alex Rivera]]` in a task's `assignees`. Links to this note appear in its\nbacklinks. Rename or move the note with a tool that updates references, as mdbase\nand Obsidian do, so those links stay current. Reusing a person's file name for\nsomebody else redirects existing links to the wrong person.\n\nThe name is your collection's display label. Full names, preferred names and\nsingle names are equally valid. There is no required first-name/last-name split.\n\n## Add only the contact details you need\n\nEmail, phone, organisation and birthday are optional. Omit unknown values rather\nthan filling them with empty strings or guesses. Store phone numbers as text,\nincluding an international prefix or extension when helpful. Birthday currently\nrequires a complete date; partial dates need a separately configured local field.\nKeep free-form context in the Markdown body and be deliberate about sensitive\npersonal information in shared collections.\n\nThis starter describes individuals. Existing organisation and group records can\ncontinue using their Contact-compatible type; setting someone's affiliation does\nnot turn their Person note into an organisation record.\n\n## Link accounts deliberately\n\nThe editor's **Link this record to me** action uses the authenticated account's\nactual issuer and subject. If configuring these manually, copy both exact values\nfrom the identity service. Do not guess them from an email, display name, or the\nserver hosting this collection. Multiple entries may represent the same person\nat different identity services. Omit `identities` when there is no account to link.\n\nAssociations are ordinary editable data, not authentication or proof of identity.\nLinking never invites someone, grants access, or changes collection membership.\nNever put credentials in a person record. Avoid linking the same account from\nseveral notes: applications should report ambiguity, not guess which\nrecord to use. Account deletion or recreation is not permission to reassign an\nold association automatically.\n\n## Keep the collection's own shape\n\nThe inline schema belongs to this collection. You may add local fields, or rename\nfields and update their explicit `implements` mappings. Apps use those mappings\nfor the Person and Contact contracts; they need not assume your local field names.\nAdditional fields remain part of the note but do not automatically become shared\ncontract fields. Do not edit published contracts to customise this type.\n\nInstalling a newer starter does not overwrite an existing customised type or\nmigrate your address book. Converting an existing individual Contact to Person\nshould be a reviewed edit of that one note, preserving its path, fields and body.\n" + } + ], + "provides": [ + { + "id": "mdbase.person", + "version": "2.0.0", + "digest": "sha256:f16c462a1fd422f44ed055002f8476ec53c164107647fec782aeb74adeab2f9d" + }, + { + "id": "mdbase.contact", + "version": "1.0.0", + "digest": "sha256:49cfe15403dfc741a693e89a2f4d2857de306f391d02cb03e67bfaf0aa1d6b0d" + } + ] +} diff --git a/public/contracts/packs/mdbase.view/1.0.1.json b/public/contracts/packs/mdbase.view/1.0.1.json new file mode 100644 index 0000000..9920836 --- /dev/null +++ b/public/contracts/packs/mdbase.view/1.0.1.json @@ -0,0 +1,57 @@ +{ + "manifest": { + "kind": "mdbase.type-pack", + "id": "mdbase.view", + "version": "1.0.1", + "name": "Saved views", + "description": "The mdbase.view contract and an editable View type for saved, reusable queries.", + "resources": [ + { + "kind": "schema", + "mode": "managed", + "source": "schemas/mdbase.view/1.0.0.schema.json", + "target": "schemas/mdbase.view/1.0.0.schema.json", + "digest": "sha256:d58b8b691c14d59f0575fc1cc93ab5b46363c485e4469bc58039ec0cece7ca36" + }, + { + "kind": "contract", + "mode": "managed", + "source": "contracts/mdbase.view/1.0.0.md", + "target": "_contracts/mdbase.view/1.0.0.md", + "digest": "sha256:91eae42371c2d411b20d3c976aece3071bbd753963b77b6bcdc26137a8fdcded" + }, + { + "kind": "type", + "mode": "seed", + "source": "types/view/2.md", + "target": "_types/view.md", + "digest": "sha256:8d20e7fa19be79e5d4a1715397234123ffbcf65f575225d610873a7b9cd29372", + "upgrade_from": { + "digest": "sha256:480919f6f88f91592abb9fe7971f09e874d536c6883981616b181cf14cbe7ff4", + "document": "---\nkind: mdbase.type\nname: view\nversion: 1\ndescription: 'Saved views: shared query scope and stable named views'\nmatch:\n where:\n type: view\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: View\n description: 'Saved views: shared query scope and stable named views.'\n type: object\n required:\n - type\n - id\n - version\n - name\n - views\n properties:\n type:\n const: view\n id:\n $ref: '#/$defs/identifier'\n version:\n type: integer\n minimum: 1\n name:\n type: string\n minLength: 1\n description:\n type: string\n query:\n $ref: '#/$defs/sharedQuery'\n properties:\n $ref: '#/$defs/propertyMetadataSet'\n summary_functions:\n $ref: '#/$defs/summaryFunctionSet'\n views:\n type: array\n minItems: 1\n items:\n $ref: '#/$defs/view'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n $defs:\n identifier:\n type: string\n pattern: ^[A-Za-z][A-Za-z0-9._:-]*$\n typeName:\n type: string\n pattern: ^[A-Za-z][A-Za-z0-9_-]{0,127}$\n fieldName:\n type: string\n pattern: ^[A-Za-z_][A-Za-z0-9_:-]*$\n expression:\n type: string\n minLength: 1\n extension:\n type: object\n additionalProperties: true\n typeList:\n type: array\n minItems: 1\n uniqueItems: true\n items:\n $ref: '#/$defs/typeName'\n sharedQuery:\n type: object\n properties:\n types:\n $ref: '#/$defs/typeList'\n where:\n $ref: '#/$defs/expression'\n context:\n $ref: '#/$defs/viewContext'\n projections:\n $ref: '#/$defs/projectionSet'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n viewContext:\n type: object\n required:\n - this\n properties:\n this:\n $ref: '#/$defs/thisContext'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n thisContext:\n type: object\n properties:\n on_missing:\n enum:\n - view\n - 'null'\n - error\n default: view\n types:\n $ref: '#/$defs/typeList'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n projectionSet:\n type: object\n propertyNames:\n $ref: '#/$defs/fieldName'\n additionalProperties:\n $ref: '#/$defs/projection'\n projection:\n type: object\n required:\n - expr\n properties:\n expr:\n $ref: '#/$defs/expression'\n description:\n type: string\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n propertyMetadataSet:\n type: object\n propertyNames:\n type: string\n minLength: 1\n additionalProperties:\n $ref: '#/$defs/propertyMetadata'\n propertyMetadata:\n type: object\n properties:\n label:\n type: string\n description:\n type: string\n format:\n type: string\n hidden:\n type: boolean\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n summaryFunctionSet:\n type: object\n propertyNames:\n $ref: '#/$defs/fieldName'\n additionalProperties:\n $ref: '#/$defs/summaryFunction'\n summaryFunction:\n type: object\n required:\n - expr\n properties:\n expr:\n $ref: '#/$defs/expression'\n description:\n type: string\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n view:\n type: object\n required:\n - id\n - name\n properties:\n id:\n $ref: '#/$defs/identifier'\n name:\n type: string\n minLength: 1\n description:\n type: string\n types:\n $ref: '#/$defs/typeList'\n where:\n $ref: '#/$defs/expression'\n context:\n $ref: '#/$defs/viewContext'\n projections:\n $ref: '#/$defs/projectionSet'\n select:\n $ref: '#/$defs/select'\n order_by:\n $ref: '#/$defs/orderBy'\n group_by:\n $ref: '#/$defs/groupBy'\n summaries:\n $ref: '#/$defs/summaries'\n limit:\n type: integer\n minimum: 0\n offset:\n type: integer\n minimum: 0\n include_body:\n type: boolean\n default: false\n frontmatter_mode:\n enum:\n - effective\n - persisted\n - both\n default: effective\n presentation:\n $ref: '#/$defs/presentation'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n select:\n type: array\n minItems: 1\n items:\n oneOf:\n - type: string\n minLength: 1\n - $ref: '#/$defs/selectExpression'\n selectExpression:\n type: object\n required:\n - name\n - expr\n properties:\n name:\n $ref: '#/$defs/fieldName'\n expr:\n $ref: '#/$defs/expression'\n label:\n type: string\n description:\n type: string\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n orderBy:\n type: array\n minItems: 1\n items:\n type: object\n required:\n - field\n properties:\n field:\n type: string\n minLength: 1\n direction:\n enum:\n - asc\n - desc\n default: asc\n additionalProperties: false\n groupBy:\n type: array\n minItems: 1\n items:\n type: object\n required:\n - field\n properties:\n field:\n type: string\n minLength: 1\n direction:\n enum:\n - asc\n - desc\n default: asc\n additionalProperties: false\n summaries:\n type: array\n minItems: 1\n items:\n $ref: '#/$defs/summary'\n summary:\n type: object\n required:\n - field\n - function\n properties:\n field:\n type: string\n minLength: 1\n function:\n $ref: '#/$defs/identifier'\n name:\n $ref: '#/$defs/fieldName'\n label:\n type: string\n additionalProperties: false\n presentation:\n type: object\n required:\n - type\n properties:\n type:\n $ref: '#/$defs/identifier'\n fallback:\n $ref: '#/$defs/identifier'\n mappings:\n type: object\n propertyNames:\n $ref: '#/$defs/fieldName'\n additionalProperties:\n type: string\n minLength: 1\n options:\n type: object\n additionalProperties: true\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\nimplements:\n- contract: mdbase.view\n version: 1.0.0\n fields:\n id: id\n version: version\n name: name\n description: description\n query: query\n properties: properties\n summary_functions: summary_functions\n views: views\ncollection:\n display:\n name_field: name\n---\n\n# View\n\nA view record stores shared query scope and one or more stable named views.\nTools that support saved views discover these records through the `mdbase.view`\ncontract and run each named view as an ordinary query.\n\nThis type belongs to your collection once installed. You can rename fields or\nchange how records are matched, as long as the `implements` mapping still\npoints each contract field at the right frontmatter field.\n" + } + } + ] + }, + "resources": [ + { + "source": "schemas/mdbase.view/1.0.0.schema.json", + "document": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://mdbase.dev/schemas/v0.3/view.schema.json\",\n \"title\": \"mdbase.view 1.0.0 record contract view\",\n \"description\": \"The contract view of a saved-view record. A type implements mdbase.view by mapping these fields; the optional type property only lets the canonical view type validate its own membership value.\",\n \"type\": \"object\",\n \"required\": [\"id\", \"version\", \"name\", \"views\"],\n \"properties\": {\n \"type\": { \"type\": \"string\", \"minLength\": 1 },\n \"id\": { \"$ref\": \"#/$defs/identifier\" },\n \"version\": { \"type\": \"integer\", \"minimum\": 1 },\n \"name\": { \"type\": \"string\", \"minLength\": 1 },\n \"description\": { \"type\": \"string\" },\n \"query\": { \"$ref\": \"#/$defs/sharedQuery\" },\n \"properties\": { \"$ref\": \"#/$defs/propertyMetadataSet\" },\n \"summary_functions\": { \"$ref\": \"#/$defs/summaryFunctionSet\" },\n \"views\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/$defs/view\" }\n }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false,\n \"$defs\": {\n \"identifier\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Za-z][A-Za-z0-9._:-]*$\"\n },\n \"typeName\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Za-z][A-Za-z0-9_-]{0,127}$\"\n },\n \"fieldName\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Za-z_][A-Za-z0-9_:-]*$\"\n },\n \"expression\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"extension\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"typeList\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"uniqueItems\": true,\n \"items\": { \"$ref\": \"#/$defs/typeName\" }\n },\n \"sharedQuery\": {\n \"type\": \"object\",\n \"properties\": {\n \"types\": { \"$ref\": \"#/$defs/typeList\" },\n \"where\": { \"$ref\": \"#/$defs/expression\" },\n \"context\": { \"$ref\": \"#/$defs/viewContext\" },\n \"projections\": { \"$ref\": \"#/$defs/projectionSet\" }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n },\n \"viewContext\": {\n \"type\": \"object\",\n \"required\": [\"this\"],\n \"properties\": {\n \"this\": { \"$ref\": \"#/$defs/thisContext\" }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n },\n \"thisContext\": {\n \"type\": \"object\",\n \"properties\": {\n \"on_missing\": {\n \"enum\": [\"view\", \"null\", \"error\"],\n \"default\": \"view\"\n },\n \"types\": { \"$ref\": \"#/$defs/typeList\" }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n },\n \"projectionSet\": {\n \"type\": \"object\",\n \"propertyNames\": { \"$ref\": \"#/$defs/fieldName\" },\n \"additionalProperties\": { \"$ref\": \"#/$defs/projection\" }\n },\n \"projection\": {\n \"type\": \"object\",\n \"required\": [\"expr\"],\n \"properties\": {\n \"expr\": { \"$ref\": \"#/$defs/expression\" },\n \"description\": { \"type\": \"string\" }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n },\n \"propertyMetadataSet\": {\n \"type\": \"object\",\n \"propertyNames\": { \"type\": \"string\", \"minLength\": 1 },\n \"additionalProperties\": { \"$ref\": \"#/$defs/propertyMetadata\" }\n },\n \"propertyMetadata\": {\n \"type\": \"object\",\n \"properties\": {\n \"label\": { \"type\": \"string\" },\n \"description\": { \"type\": \"string\" },\n \"format\": { \"type\": \"string\" },\n \"hidden\": { \"type\": \"boolean\" }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n },\n \"summaryFunctionSet\": {\n \"type\": \"object\",\n \"propertyNames\": { \"$ref\": \"#/$defs/fieldName\" },\n \"additionalProperties\": { \"$ref\": \"#/$defs/summaryFunction\" }\n },\n \"summaryFunction\": {\n \"type\": \"object\",\n \"required\": [\"expr\"],\n \"properties\": {\n \"expr\": { \"$ref\": \"#/$defs/expression\" },\n \"description\": { \"type\": \"string\" }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n },\n \"view\": {\n \"type\": \"object\",\n \"required\": [\"id\", \"name\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/identifier\" },\n \"name\": { \"type\": \"string\", \"minLength\": 1 },\n \"description\": { \"type\": \"string\" },\n \"types\": { \"$ref\": \"#/$defs/typeList\" },\n \"where\": { \"$ref\": \"#/$defs/expression\" },\n \"context\": { \"$ref\": \"#/$defs/viewContext\" },\n \"projections\": { \"$ref\": \"#/$defs/projectionSet\" },\n \"select\": { \"$ref\": \"#/$defs/select\" },\n \"order_by\": { \"$ref\": \"#/$defs/orderBy\" },\n \"group_by\": { \"$ref\": \"#/$defs/groupBy\" },\n \"summaries\": { \"$ref\": \"#/$defs/summaries\" },\n \"limit\": { \"type\": \"integer\", \"minimum\": 0 },\n \"offset\": { \"type\": \"integer\", \"minimum\": 0 },\n \"include_body\": { \"type\": \"boolean\", \"default\": false },\n \"frontmatter_mode\": {\n \"enum\": [\"effective\", \"persisted\", \"both\"],\n \"default\": \"effective\"\n },\n \"presentation\": { \"$ref\": \"#/$defs/presentation\" }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n },\n \"select\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": {\n \"oneOf\": [\n { \"type\": \"string\", \"minLength\": 1 },\n { \"$ref\": \"#/$defs/selectExpression\" }\n ]\n }\n },\n \"selectExpression\": {\n \"type\": \"object\",\n \"required\": [\"name\", \"expr\"],\n \"properties\": {\n \"name\": { \"$ref\": \"#/$defs/fieldName\" },\n \"expr\": { \"$ref\": \"#/$defs/expression\" },\n \"label\": { \"type\": \"string\" },\n \"description\": { \"type\": \"string\" }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n },\n \"orderBy\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"field\"],\n \"properties\": {\n \"field\": { \"type\": \"string\", \"minLength\": 1 },\n \"direction\": { \"enum\": [\"asc\", \"desc\"], \"default\": \"asc\" }\n },\n \"additionalProperties\": false\n }\n },\n \"groupBy\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"field\"],\n \"properties\": {\n \"field\": { \"type\": \"string\", \"minLength\": 1 },\n \"direction\": { \"enum\": [\"asc\", \"desc\"], \"default\": \"asc\" }\n },\n \"additionalProperties\": false\n }\n },\n \"summaries\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/$defs/summary\" }\n },\n \"summary\": {\n \"type\": \"object\",\n \"required\": [\"field\", \"function\"],\n \"properties\": {\n \"field\": { \"type\": \"string\", \"minLength\": 1 },\n \"function\": { \"$ref\": \"#/$defs/identifier\" },\n \"name\": { \"$ref\": \"#/$defs/fieldName\" },\n \"label\": { \"type\": \"string\" }\n },\n \"additionalProperties\": false\n },\n \"presentation\": {\n \"type\": \"object\",\n \"required\": [\"type\"],\n \"properties\": {\n \"type\": { \"$ref\": \"#/$defs/identifier\" },\n \"fallback\": { \"$ref\": \"#/$defs/identifier\" },\n \"mappings\": {\n \"type\": \"object\",\n \"propertyNames\": { \"$ref\": \"#/$defs/fieldName\" },\n \"additionalProperties\": { \"type\": \"string\", \"minLength\": 1 }\n },\n \"options\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n }\n },\n \"patternProperties\": {\n \"^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$\": { \"$ref\": \"#/$defs/extension\" }\n },\n \"additionalProperties\": false\n }\n }\n}\n" + }, + { + "source": "contracts/mdbase.view/1.0.0.md", + "document": "---\nkind: mdbase.contract\ncontract_type: record\nid: mdbase.view\nversion: 1.0.0\nname: Saved view\ndescription: Shared query scope and stable named views executable through the Query profile.\nrecord_schema:\n dialect: json-schema-2020-12\n ref: ../../schemas/mdbase.view/1.0.0.schema.json\n---\n\n# Saved view\n\nA record exposed through `mdbase.view` stores shared query scope and one or more\nstable named views. Each named view resolves to the query model in Chapter 11.\nOptional `presentation` metadata is advisory and does not alter headless query\nresults.\n\nImplementing this contract is how a collection declares which of its records\nare saved views. A tool that advertises `view_records` discovers and executes\nviews through this contract's type implementations, not through a reserved type\nname, path, or frontmatter value.\n\nThis artifact is passive. Implementing it grants no authority to read, execute,\nor modify any record.\n" + }, + { + "source": "types/view/2.md", + "document": "---\nkind: mdbase.type\nname: view\nversion: 2\ndescription: 'Saved views: shared query scope and stable named views'\nmatch:\n where:\n type: view\nschema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n title: View\n description: 'Saved views: shared query scope and stable named views.'\n type: object\n required:\n - id\n - version\n - name\n - views\n properties:\n id:\n $ref: '#/$defs/identifier'\n version:\n type: integer\n minimum: 1\n name:\n type: string\n minLength: 1\n description:\n type: string\n query:\n $ref: '#/$defs/sharedQuery'\n properties:\n $ref: '#/$defs/propertyMetadataSet'\n summary_functions:\n $ref: '#/$defs/summaryFunctionSet'\n views:\n type: array\n minItems: 1\n items:\n $ref: '#/$defs/view'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: true\n $defs:\n identifier:\n type: string\n pattern: ^[A-Za-z][A-Za-z0-9._:-]*$\n typeName:\n type: string\n pattern: ^[A-Za-z][A-Za-z0-9_-]{0,127}$\n fieldName:\n type: string\n pattern: ^[A-Za-z_][A-Za-z0-9_:-]*$\n expression:\n type: string\n minLength: 1\n extension:\n type: object\n additionalProperties: true\n typeList:\n type: array\n minItems: 1\n uniqueItems: true\n items:\n $ref: '#/$defs/typeName'\n sharedQuery:\n type: object\n properties:\n types:\n $ref: '#/$defs/typeList'\n where:\n $ref: '#/$defs/expression'\n context:\n $ref: '#/$defs/viewContext'\n projections:\n $ref: '#/$defs/projectionSet'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n viewContext:\n type: object\n required:\n - this\n properties:\n this:\n $ref: '#/$defs/thisContext'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n thisContext:\n type: object\n properties:\n on_missing:\n enum:\n - view\n - 'null'\n - error\n default: view\n types:\n $ref: '#/$defs/typeList'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n projectionSet:\n type: object\n propertyNames:\n $ref: '#/$defs/fieldName'\n additionalProperties:\n $ref: '#/$defs/projection'\n projection:\n type: object\n required:\n - expr\n properties:\n expr:\n $ref: '#/$defs/expression'\n description:\n type: string\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n propertyMetadataSet:\n type: object\n propertyNames:\n type: string\n minLength: 1\n additionalProperties:\n $ref: '#/$defs/propertyMetadata'\n propertyMetadata:\n type: object\n properties:\n label:\n type: string\n description:\n type: string\n format:\n type: string\n hidden:\n type: boolean\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n summaryFunctionSet:\n type: object\n propertyNames:\n $ref: '#/$defs/fieldName'\n additionalProperties:\n $ref: '#/$defs/summaryFunction'\n summaryFunction:\n type: object\n required:\n - expr\n properties:\n expr:\n $ref: '#/$defs/expression'\n description:\n type: string\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n view:\n type: object\n required:\n - id\n - name\n properties:\n id:\n $ref: '#/$defs/identifier'\n name:\n type: string\n minLength: 1\n description:\n type: string\n types:\n $ref: '#/$defs/typeList'\n where:\n $ref: '#/$defs/expression'\n context:\n $ref: '#/$defs/viewContext'\n projections:\n $ref: '#/$defs/projectionSet'\n select:\n $ref: '#/$defs/select'\n order_by:\n $ref: '#/$defs/orderBy'\n group_by:\n $ref: '#/$defs/groupBy'\n summaries:\n $ref: '#/$defs/summaries'\n limit:\n type: integer\n minimum: 0\n offset:\n type: integer\n minimum: 0\n include_body:\n type: boolean\n default: false\n frontmatter_mode:\n enum:\n - effective\n - persisted\n - both\n default: effective\n presentation:\n $ref: '#/$defs/presentation'\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n select:\n type: array\n minItems: 1\n items:\n oneOf:\n - type: string\n minLength: 1\n - $ref: '#/$defs/selectExpression'\n selectExpression:\n type: object\n required:\n - name\n - expr\n properties:\n name:\n $ref: '#/$defs/fieldName'\n expr:\n $ref: '#/$defs/expression'\n label:\n type: string\n description:\n type: string\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\n orderBy:\n type: array\n minItems: 1\n items:\n type: object\n required:\n - field\n properties:\n field:\n type: string\n minLength: 1\n direction:\n enum:\n - asc\n - desc\n default: asc\n additionalProperties: false\n groupBy:\n type: array\n minItems: 1\n items:\n type: object\n required:\n - field\n properties:\n field:\n type: string\n minLength: 1\n direction:\n enum:\n - asc\n - desc\n default: asc\n additionalProperties: false\n summaries:\n type: array\n minItems: 1\n items:\n $ref: '#/$defs/summary'\n summary:\n type: object\n required:\n - field\n - function\n properties:\n field:\n type: string\n minLength: 1\n function:\n $ref: '#/$defs/identifier'\n name:\n $ref: '#/$defs/fieldName'\n label:\n type: string\n additionalProperties: false\n presentation:\n type: object\n required:\n - type\n properties:\n type:\n $ref: '#/$defs/identifier'\n fallback:\n $ref: '#/$defs/identifier'\n mappings:\n type: object\n propertyNames:\n $ref: '#/$defs/fieldName'\n additionalProperties:\n type: string\n minLength: 1\n options:\n type: object\n additionalProperties: true\n patternProperties:\n ^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$:\n $ref: '#/$defs/extension'\n additionalProperties: false\nimplements:\n- contract: mdbase.view\n version: 1.0.0\n fields:\n id: id\n version: version\n name: name\n description: description\n query: query\n properties: properties\n summary_functions: summary_functions\n views: views\ncollection:\n display:\n name_field: name\n---\n\n# View\n\nA view record stores shared query scope and one or more stable named views.\nTools that support saved views discover these records through the `mdbase.view`\ncontract and run each named view as an ordinary query.\n\nThis type belongs to your collection once installed. You can rename fields or\nchange how records are matched, as long as the `implements` mapping still\npoints each contract field at the right frontmatter field.\n" + } + ], + "provides": [ + { + "id": "mdbase.view", + "version": "1.0.0", + "digest": "sha256:0918acefce08cddd778fab768fe4f2e4615d263a0eec3e5330b6897c686d744e" + } + ] +} diff --git a/public/contracts/packs/tasknotes.task/0.3.0-rc.18.json b/public/contracts/packs/tasknotes.task/0.3.0-rc.18.json new file mode 100644 index 0000000..504c65a --- /dev/null +++ b/public/contracts/packs/tasknotes.task/0.3.0-rc.18.json @@ -0,0 +1,86 @@ +{ + "manifest": { + "kind": "mdbase.type-pack", + "id": "tasknotes.task", + "version": "0.3.0-rc.18", + "name": "TaskNotes task type pack", + "description": "Portable tasks whose assignments link to person records, 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": "type", + "mode": "seed", + "source": "types/tasknotes-task/5.md", + "target": "_types/task.md", + "digest": "sha256:b3cf8dbe8885b331c494d2eeb36abfb052890e06b757877d655c269e666487dc", + "upgrade_from": [ + { + "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.5.schema.json", + "target": "_schemas/tasknotes/tasknotes-task.schema.json", + "digest": "sha256:aec95578a093be95cbce0fb500964e7aeaeeacc611624fc2893074637dbd4125" + }, + { + "kind": "schema", + "mode": "managed", + "source": "schemas/tasknotes.task.binding/0.3.0-rc.5.schema.json", + "target": "_schemas/tasknotes/tasknotes-task-binding.schema.json", + "digest": "sha256:5b38e8a1c426b7f7fa92d8353fe35dd98e632305cbb15ffccde387473166b267" + } + ] + }, + "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": "types/tasknotes-task/5.md", + "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" + }, + { + "source": "schemas/tasknotes.task/0.3.0-rc.5.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.5 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.5.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.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 ],\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 \"time_tracking\": {\n \"$ref\": \"#/$defs/timeTrackingPolicy\"\n },\n \"templating\": {\n \"$ref\": \"#/$defs/templatingPolicy\"\n },\n \"nlp\": {\n \"$ref\": \"#/$defs/nlpPolicy\"\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 \"exclude_from_cycle\",\n \"order\",\n \"auto_archive\",\n \"auto_archive_delay_minutes\"\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 \"exclude_from_cycle\": {\n \"type\": \"boolean\"\n },\n \"next_status\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"order\": {\n \"type\": \"number\"\n },\n \"auto_archive\": {\n \"type\": \"boolean\"\n },\n \"auto_archive_delay_minutes\": {\n \"type\": \"number\",\n \"minimum\": 0\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 \"reset_body_checkboxes\"\n ],\n \"properties\": {\n \"syntax\": {\n \"const\": \"tasknotes\"\n },\n \"maintain_due_date_offset\": {\n \"type\": \"boolean\"\n },\n \"reset_body_checkboxes\": {\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 \"write_format\"\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 \"write_format\": {\n \"enum\": [\n \"wikilink\",\n \"markdown\"\n ]\n }\n },\n \"additionalProperties\": false\n },\n \"archivePolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"archived_tag\",\n \"move_on_archive\"\n ],\n \"properties\": {\n \"archived_tag\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"move_on_archive\": {\n \"type\": \"boolean\"\n },\n \"folder\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n }\n },\n \"additionalProperties\": false\n },\n \"timeTrackingPolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"auto_stop_on_complete\"\n ],\n \"properties\": {\n \"auto_stop_on_complete\": {\n \"type\": \"boolean\"\n }\n },\n \"additionalProperties\": false\n },\n \"templatingPolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"enabled\",\n \"occurrence_enabled\"\n ],\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\"\n },\n \"template_path\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"occurrence_enabled\": {\n \"type\": \"boolean\"\n },\n \"occurrence_template_path\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"failure_mode\": {\n \"enum\": [\n \"error\",\n \"warning_fallback\"\n ]\n },\n \"unknown_variable_policy\": {\n \"enum\": [\n \"preserve\",\n \"empty\"\n ]\n }\n },\n \"additionalProperties\": false\n },\n \"nlpTrigger\": {\n \"type\": \"object\",\n \"required\": [\n \"property_id\",\n \"trigger\",\n \"enabled\"\n ],\n \"properties\": {\n \"property_id\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"trigger\": {\n \"$ref\": \"#/$defs/nonEmptyString\"\n },\n \"enabled\": {\n \"type\": \"boolean\"\n }\n },\n \"additionalProperties\": false\n },\n \"nlpPolicy\": {\n \"type\": \"object\",\n \"required\": [\n \"triggers\"\n ],\n \"properties\": {\n \"triggers\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/nlpTrigger\"\n }\n }\n },\n \"additionalProperties\": false\n }\n }\n}\n" + } + ], + "provides": [ + { + "id": "tasknotes.task", + "version": "0.3.0-rc.5", + "digest": "sha256:dde71d0d776aa0069ee627fe3c10b1a20f87ba36929a16790598ebfb4e8ebf04" + } + ] +} diff --git a/site-sources.json b/site-sources.json index 8bc7fee..58879fc 100644 --- a/site-sources.json +++ b/site-sources.json @@ -9,7 +9,7 @@ }, "contracts": { "repository": "mdbase-dev/mdbase-contracts", - "ref": "6fee9ea66cf06a396aa064e67a4cd5159ecc2a92" + "ref": "5c06f1544db5b23380d6dac52c82ce9dac548ab8" }, "implementations": [ { diff --git a/src/data/contracts.json b/src/data/contracts.json index 174ca55..e9a079b 100644 --- a/src/data/contracts.json +++ b/src/data/contracts.json @@ -277,6 +277,44 @@ "Suggested edits" ] }, + "installation": { + "visibility": "hidden", + "recommendation": "optional", + "primary_type": "comment", + "types": [ + { + "name": "comment", + "label": "Comment" + } + ] + } + }, + { + "id": "mdbase.comment", + "version": "1.0.1", + "name": "Comments type pack", + "description": "Comments, replies and suggested edits anchored to text in Markdown records.", + "digest": "sha256:3b3940270e96876062d8fcdf293edb7eeb99985987b8821f8478acf9663d1e83", + "provision": "./packs/mdbase.comment/1.0.1.json", + "provides": [ + { + "id": "mdbase.comment", + "version": "1.0.0", + "digest": "sha256:c2c5b3f3013d10625310401e9f9149ffa2d09c5b7d91b4fc97688d3ac010bec5" + } + ], + "resource_count": 3, + "display": { + "name": "Comments", + "summary": "Discuss and suggest edits to notes without changing their text, in any app that reads comments.", + "category": "work", + "audience": "general", + "icon": "chat-circle", + "badges": [ + "Portable comments", + "Suggested edits" + ] + }, "installation": { "visibility": "default", "recommendation": "optional", @@ -402,6 +440,90 @@ "Portable person references" ] }, + "installation": { + "visibility": "hidden", + "recommendation": "user", + "primary_type": "person", + "types": [ + { + "name": "person", + "label": "Person" + } + ] + } + }, + { + "id": "mdbase.contact", + "version": "1.3.0", + "name": "People type pack", + "description": "Portable people, editable account identity associations, and familiar contact fields.", + "digest": "sha256:48fc070ae00c61ab5b20b9ffb385d20d2a468328da07e45e67c99602b05d02e8", + "provision": "./packs/mdbase.contact/1.3.0.json", + "provides": [ + { + "id": "mdbase.person", + "version": "2.0.0", + "digest": "sha256:f16c462a1fd422f44ed055002f8476ec53c164107647fec782aeb74adeab2f9d" + }, + { + "id": "mdbase.contact", + "version": "1.0.0", + "digest": "sha256:49cfe15403dfc741a693e89a2f4d2857de306f391d02cb03e67bfaf0aa1d6b0d" + } + ], + "resource_count": 7, + "display": { + "name": "People", + "summary": "Reference people across apps and collections without tying records to account membership.", + "category": "people", + "audience": "general", + "icon": "user", + "badges": [ + "Portable person references" + ] + }, + "installation": { + "visibility": "hidden", + "recommendation": "user", + "primary_type": "person", + "types": [ + { + "name": "person", + "label": "Person" + } + ] + } + }, + { + "id": "mdbase.contact", + "version": "1.4.0", + "name": "People type pack", + "description": "Portable people, editable account identity associations, and familiar contact fields.", + "digest": "sha256:741fcf0f50d13538eda1c9ee32df4d85e32549b8fb730350bb80b3323b09df93", + "provision": "./packs/mdbase.contact/1.4.0.json", + "provides": [ + { + "id": "mdbase.person", + "version": "2.0.0", + "digest": "sha256:f16c462a1fd422f44ed055002f8476ec53c164107647fec782aeb74adeab2f9d" + }, + { + "id": "mdbase.contact", + "version": "1.0.0", + "digest": "sha256:49cfe15403dfc741a693e89a2f4d2857de306f391d02cb03e67bfaf0aa1d6b0d" + } + ], + "resource_count": 7, + "display": { + "name": "People", + "summary": "Reference people across apps and collections without tying records to account membership.", + "category": "people", + "audience": "general", + "icon": "user", + "badges": [ + "Portable person references" + ] + }, "installation": { "visibility": "default", "recommendation": "user", @@ -558,6 +680,43 @@ "Portable views" ] }, + "installation": { + "visibility": "hidden", + "recommendation": "optional", + "primary_type": "view", + "types": [ + { + "name": "view", + "label": "View" + } + ] + } + }, + { + "id": "mdbase.view", + "version": "1.0.1", + "name": "Saved views", + "description": "The mdbase.view contract and an editable View type for saved, reusable queries.", + "digest": "sha256:e93db5cd8449eb3b1e3cb795b0bf0477fc90124363745dd9aef7a88b1fbc8752", + "provision": "./packs/mdbase.view/1.0.1.json", + "provides": [ + { + "id": "mdbase.view", + "version": "1.0.0", + "digest": "sha256:0918acefce08cddd778fab768fe4f2e4615d263a0eec3e5330b6897c686d744e" + } + ], + "resource_count": 3, + "display": { + "name": "Saved views", + "summary": "Save reusable queries that any view-aware app can list and run.", + "category": "work", + "audience": "general", + "icon": "table", + "badges": [ + "Portable views" + ] + }, "installation": { "visibility": "default", "recommendation": "optional", @@ -670,6 +829,44 @@ "TaskNotes compatible" ] }, + "installation": { + "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.", + "types": [ + { + "name": "task", + "label": "Task" + } + ] + } + }, + { + "id": "tasknotes.task", + "version": "0.3.0-rc.18", + "name": "TaskNotes task type pack", + "description": "Portable tasks whose assignments link to person records, with a reviewed, atomic upgrade from every TaskNotes starter published before.", + "digest": "sha256:9a9ebc26e6f63ad2fc3d92f87d38f6c140a3af90408de47d667ae7b9ba0dc9ef", + "provision": "./packs/tasknotes.task/0.3.0-rc.18.json", + "provides": [ + { + "id": "tasknotes.task", + "version": "0.3.0-rc.5", + "digest": "sha256:dde71d0d776aa0069ee627fe3c10b1a20f87ba36929a16790598ebfb4e8ebf04" + } + ], + "resource_count": 4, + "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",