From 4bbfc4fa6a094f65c199d2919d13fc839ce10d7d Mon Sep 17 00:00:00 2001 From: Alex Wild Date: Wed, 17 Jun 2026 08:27:06 +0200 Subject: [PATCH 1/3] feat(claude): Add TRN breaking-change & deprecation skills + format reference Introduce the canonical trn-format-reference.md and the write-trn-breaking-change and write-trn-deprecation skills for the AI-parsable TRN format. - Detect/Fix entry contract with greppable Detect lines (literal tokens to search for, not abstract dot-paths) - A **Code:** line linking each entry to its LivingdocsBreakingChange / LivingdocsDeprecation log code, so operators and agents can map a log line to the entry and its fix - Exhaustive prose with concrete before/after comparisons for these upgrade-critical sections - Skills carry only the workflow; the reference is the single source of truth for entry shape, tone, and rules Co-Authored-By: Claude Opus 4.8 (1M context) --- .../skills/write-trn-breaking-change/SKILL.md | 57 ++++++ .claude/skills/write-trn-deprecation/SKILL.md | 55 ++++++ .claude/trn-format-reference.md | 165 ++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 .claude/skills/write-trn-breaking-change/SKILL.md create mode 100644 .claude/skills/write-trn-deprecation/SKILL.md create mode 100644 .claude/trn-format-reference.md diff --git a/.claude/skills/write-trn-breaking-change/SKILL.md b/.claude/skills/write-trn-breaking-change/SKILL.md new file mode 100644 index 000000000..06041cefa --- /dev/null +++ b/.claude/skills/write-trn-breaking-change/SKILL.md @@ -0,0 +1,57 @@ +--- +name: write-trn-breaking-change +description: Write a Breaking Change entry for a Livingdocs Technical Release Note (TRN) and insert it into the correct release file. Use this skill whenever a developer wants to document a breaking change, mentions "write breaking change", "add breaking change to release notes", or provides PR URLs and asks to document a breaking change for a specific release (e.g. "write the breaking change for release-2026-05"). This skill handles the full workflow: gathering PR details, writing the entry with Detect/Fix sub-sections, and inserting it into the release file. +--- + +# Write TRN Breaking Change Entry + +Breaking changes are the most upgrade-critical section of the TRN. Each entry must be detectable and fixable from its own text — an AI agent or operator should be able to walk through Breaking Changes and apply each fix without consulting other documentation. + +This skill is the **workflow**. The entry's shape, tone, and rules live in `.claude/trn-format-reference.md`, which is the source of truth — read it before drafting and follow it rather than relying on memory. + +## Step 1: Gather inputs + +Ask **one question at a time** — wait for each answer before asking the next: + +1. **Release** — identifier in `release-YYYY-MM` format. Accept plain year/month and normalise it yourself. +2. **GitHub PR URLs** — ask whether they'd like to add all URLs at once or one at a time. If one at a time: ask for the first URL, then ask "Any more PRs? (say 'done' to continue)" and keep collecting until done. If all at once: accept a list of URLs in a single message. +3. **Notification code(s)** — the `LivingdocsBreakingChange` code(s) this change emits (e.g. `LIBREAKING000`). Collect all of them if there are several (e.g. one per affected property, like `LIBREAKING000-propertyOne`, `LIBREAKING000-propertyTwo`). Say "none" if the change emits no runtime warning (e.g. a static-only concern such as direct `lib/` imports). +4. **Notion requirement URL** — original requirement page (if available). Say "none" to skip. +5. **Additional context** — free-form notes from the developer about the breaking change. Optional. + +## Step 2: Read the sources + +- Fetch each GitHub PR: title, description, linked issues, code diff. Pay attention to: + - Which config properties, API endpoints, or source-level imports are affected. + - The old shape vs. the new shape (verbatim — Detect and Fix lines must use the exact property names from the code). + - Whether the change is mechanical (e.g. property rename, key move) or judgment-based (e.g. semantic conflict where the user must choose). +- If a Notion URL was provided, fetch it to understand the original motivation. +- **Check earlier releases for a matching deprecation.** Most breaking changes that remove a property, API, or behaviour were first announced as a deprecation in an earlier release — typically around three releases earlier, though this is not guaranteed. Look under `## Deprecations :warning:` in the earlier `content/operations/releases/release-YYYY-MM.md` files. If you find one, its prose, Detect, and Fix are a strong starting point — adapt them rather than writing from scratch. Still review it end to end: details may have changed between the deprecation announcement and the actual removal, and the deprecation entry may have surfaced edge cases worth carrying over. +- Read the existing `## Breaking Changes :fire:` section in `content/operations/releases/.md` to calibrate tone and to confirm the change isn't already documented. + +## Step 3: Write the breaking change entry + +Write the entry following the **Breaking Change entry shape** and its **Rules** in `.claude/trn-format-reference.md` — the source of truth for the title, the `**Code:**` line, the exhaustive prose intro with before/after, the greppable `Detect`, and the `Fix`. Read it now rather than restating it here. + +Skill-specific note: if you adapted an earlier deprecation entry (Step 2), carry over its still-accurate detail and update whatever changed between the deprecation and the removal. + +## Step 4: Ask for feedback + +Show the draft to the developer: + +> _"Here's the draft. Does it look right? Anything to adjust — wording, missing edge cases, or the Detect/Fix specificity?"_ + +Apply any requested changes. If the developer flags the entry as a deprecation rather than a breaking change, switch to the `write-trn-deprecation` skill instead. + +## Step 5: Insert into the release notes file + +1. Open `content/operations/releases/.md`. +2. Locate `## Breaking Changes :fire:`. +3. Append the entry at the end of that section, before the next `##` heading. +4. Save and confirm to the developer. + +## Step 6: Sanity-check after insertion + +Verify the finished entry against the **Rules** in `.claude/trn-format-reference.md` (icon-free `###` heading, `**Code:**` line with codes verbatim from the source, greppable Detect, both Detect and Fix present, no extra `####` sub-headings). Then confirm the insertion itself: the entry sits inside `## Breaking Changes :fire:`, before the next `##` heading. + +If any check fails, surface it to the developer and propose a fix before closing. diff --git a/.claude/skills/write-trn-deprecation/SKILL.md b/.claude/skills/write-trn-deprecation/SKILL.md new file mode 100644 index 000000000..4fe186a94 --- /dev/null +++ b/.claude/skills/write-trn-deprecation/SKILL.md @@ -0,0 +1,55 @@ +--- +name: write-trn-deprecation +description: Write a Deprecation entry for a Livingdocs Technical Release Note (TRN) and insert it into the correct release file. Use this skill whenever a developer wants to document a deprecation, mentions "write deprecation", "add deprecation to release notes", or provides PR URLs and asks to document a deprecation for a specific release (e.g. "write the deprecation for release-2026-05"). This skill handles the full workflow: gathering PR details, writing the entry with Detect/Fix sub-sections and a planned removal release, and inserting it into the release file. +--- + +# Write TRN Deprecation Entry + +Deprecations announce future removals. They share the structure of Breaking Changes (`Detect` / `Fix` sub-sections) and differ in one way: deprecations name a **planned removal release** so the reader can schedule the migration. + +This skill is the **workflow**. The entry's shape, tone, and rules — including the deprecation-specific and opt-in-default-behaviour cases — live in `.claude/trn-format-reference.md`, which is the source of truth. Read it before drafting and follow it rather than relying on memory. + +## Step 1: Gather inputs + +Ask **one question at a time** — wait for each answer before asking the next: + +1. **Release** — identifier in `release-YYYY-MM` format where the deprecation is being introduced. Accept plain year/month and normalise it yourself. +2. **Planned removal release** — when will the deprecated property / API / behaviour be removed? Accept `release-YYYY-MM` format, or "no fixed removal release" if the deprecation is open-ended (e.g. an opt-in API default-behaviour change). +3. **GitHub PR URLs** — ask whether they'd like to add all URLs at once or one at a time. If one at a time: ask for the first URL, then ask "Any more PRs? (say 'done' to continue)" and keep collecting until done. If all at once: accept a list of URLs in a single message. +4. **Notification code(s)** — the `LivingdocsDeprecation` code(s) this deprecation emits (e.g. `LIDEP000`). Collect all of them if there are several. Say "none" if it emits no runtime warning. +5. **Notion requirement URL** — original requirement page (if available). Say "none" to skip. +6. **Additional context** — free-form notes from the developer. Optional. + +## Step 2: Read the sources + +- Fetch each GitHub PR: title, description, linked issues, code diff. Pay attention to: + - Which config property, API endpoint, or behaviour is being deprecated. + - What the replacement is (different shape, opt-in flag, alternative property, etc.). + - Whether the migration is mechanical (a property rename or move) or discretionary (the user chooses how to map the old usage to the new model). +- If a Notion URL was provided, fetch it to understand the original motivation. +- Read the existing `## Deprecations :warning:` section in `content/operations/releases/.md` to calibrate tone and to confirm the deprecation isn't already documented. + +## Step 3: Write the deprecation entry + +Write the entry following the **Deprecation entry shape** and its **Rules** in `.claude/trn-format-reference.md` — the source of truth for the title, the `**Code:**` line, the exhaustive prose intro (which must name the planned removal release) with before/after, the greppable `Detect`, and the `Fix`. Read it now rather than restating it here. + +## Step 4: Ask for feedback + +Show the draft to the developer: + +> _"Here's the draft. Does it look right? Anything to adjust — wording, the planned removal release, or the Detect/Fix specificity?"_ + +Apply any requested changes. If the developer flags the entry as a breaking change rather than a deprecation, switch to the `write-trn-breaking-change` skill instead. + +## Step 5: Insert into the release notes file + +1. Open `content/operations/releases/.md`. +2. Locate `## Deprecations :warning:`. +3. Append the entry at the end of that section, before the next `##` heading. +4. Save and confirm to the developer. + +## Step 6: Sanity-check after insertion + +Verify the finished entry against the **Rules** in `.claude/trn-format-reference.md` (icon-free `###` heading, `**Code:**` line with codes verbatim from the source, prose names a planned removal release or states none, greppable Detect, both Detect and Fix present, no extra `####` sub-headings). Then confirm the insertion itself: the entry sits inside `## Deprecations :warning:`, before the next `##` heading. + +If any check fails, surface it to the developer and propose a fix before closing. diff --git a/.claude/trn-format-reference.md b/.claude/trn-format-reference.md new file mode 100644 index 000000000..88c36f917 --- /dev/null +++ b/.claude/trn-format-reference.md @@ -0,0 +1,165 @@ +# TRN Format Reference + +Canonical content shape for Livingdocs Technical Release Notes (TRN). Consulted by the `write-trn-*` and `cleanup-trn` skills. Not user-facing. + +## Audience + +TRN entries are read by two audiences: + +- **Operators** doing the upgrade — humans who need to know what to change and why. +- **AI agents** driving an upgrade from the TRN content — they parse Breaking Changes and Deprecations to derive a checklist of actions. + +Write for both. Plain prose carries the explanation; structured sub-headings carry the action contract. + +## Top-level section structure + +A clean TRN has the following sections in this order. Sections may be empty (e.g. "No migrations are required") but should be present. + +``` +## Webinar +## System Requirements +## Deployment +## Breaking Changes :fire: +## Deprecations :warning: +## Features :gift: +## Vulnerability Patches +## Patches +``` + +### The fixed sections + +`## Webinar`, `## System Requirements`, `## Deployment`, `## Vulnerability Patches`, and `## Patches` follow the standard scaffold in `content/operations/releases/_release-template.md` — copy it and fill in the release's specifics rather than re-deriving the structure. Two things worth knowing: + +- **`## System Requirements`** is rendered from the page's `systemRequirements` front matter via `{{< system-versions list="…" >}}` — edit the front matter, not the rendered list. +- **`## Deployment`** is action-bearing (migrations and ordering live here). Keep all four sub-sections and state "No … required" explicitly when one is empty. + +### Icon rules + +Icons appear on the section heading (`##`), never on individual entry headings (`###`). + +- `:fire:` — `## Breaking Changes` +- `:warning:` — `## Deprecations` +- `:gift:` — `## Features` + +Putting the icon on the entry heading is wrong and creates noise. The section heading carries the semantic. + +## Breaking Change entry shape + +```markdown +### Title in Sentence Case + +**Code:** `LIBREAKING000` + +Prose explaining what changed and why (the same content that would appear in a human-facing newsletter). Be exhaustive: a breaking change is the most upgrade-critical content, so include enough detail, examples, and references that an operator can act without asking follow-up questions. Include a concrete before/after comparison (old shape → new shape) as an inline code snippet or table whenever the change alters a config, API, or code shape. + +#### Detect + +A statement an agent (or human) can turn into a real search: the location plus a literal pattern. Lead with the location when the property path doesn't make it obvious. Examples: + +- "In the server config, `mediaLibrary.use2025Behavior` is `true` AND any of `failOn`, `convert`, `lossy`, or `lossless` is set under `mediaLibrary.images.processing`. Search for `(failOn|convert|lossy|lossless)\s*:` and confirm each hit sits under `processing`." +- "In server project source code, a `require()` or `import` referencing `@livingdocs//lib/`. Search for `@livingdocs/[^'\"]+/lib/`." + +#### Fix + +Mechanical instructions when possible. Use a table for property-rename mappings. Flag judgment calls in plain advice form ("Which option is correct depends on the meaning of the field, so review each conflict before changing it"). Never address the agent directly ("surface to the user", "do not auto-rewrite") — instead describe the constraint as advice the human reader would also benefit from. +``` + +### Rules + +- Title is plain text, no icon, sentence case. Name the affected thing concretely (`Removal of li-target-length UI Config Properties`, not `UI Improvements`). +- Two `####` sub-headings only: `Detect` and `Fix`. No `Applies to` or other fields — the location lives in the Detect line. +- Both Detect and Fix are required for every entry. +- **Detect must be greppable.** A dot-path like `mediaTypes[].editor.dashboard` describes structure, not a search string — searching `.dashboard` won't find the `dashboard:` key. State the literal token that actually appears in the config (usually the leaf key as written) plus the context needed to disambiguate it from unrelated matches, and give a ready-to-run grep/ripgrep regex when the match is non-obvious. +- When more than one condition triggers the issue, list them as bullets under an "either of" / "any of" clause in the Detect line. +- **Code line.** Most entries emit a runtime notification — a `LivingdocsBreakingChange` (code prefix `LIBREAKING`) for breaking changes, or a `LivingdocsDeprecation` (code prefix `LIDEP`) for deprecations. Put the code on a `**Code:**` line directly below the heading, before the prose. This is the identifier operators see in server logs, and the key an agent uses to map a log line to this entry. Take the value verbatim from the `create({type, code})` call in the source (or from the developer) — don't invent one. Some changes emit several related codes (e.g. one per affected property: `LIBREAKING064-failOn`, `LIBREAKING064-convert`, …); list them all on a `**Codes:**` line, or express the shared pattern. Omit the line entirely when there is no runtime code (e.g. static-only concerns like direct `lib/` imports). +- The prose intro should include the inline code samples / tables / config examples that illustrate the change, and a before/after comparison whenever the change alters a config, API, or code shape. Detect and Fix should not duplicate those — they refer back to the prose. +- Favour exhaustiveness over brevity here (unlike Feature entries, which stay minimal): include the detail, examples, and references needed to act without follow-up questions. +- Link to the relevant guide or reference page when one exists (e.g. a replacement's documentation) — as a supplement to, not a substitute for, the self-contained Detect/Fix. +- For a mechanical Fix, spell out the old → new mapping (use a table when it has more than two rows). If a Fix requires a data migration, say so explicitly and point at Livingdocs support when appropriate. +- "Risk if skipped" is implicit: every entry under `## Breaking Changes :fire:` is upgrade-blocking. No need to restate. + +## Deprecation entry shape + +A deprecation is a breaking change announced ahead of time: identical `Detect` / `Fix` structure, with one addition — the prose intro names the **planned removal release** (e.g. "will be removed in `release-2026-11`") so the reader can act before it breaks. + +```markdown +### Title in Sentence Case + +**Code:** `LIDEP000` + +Project config property `X` is deprecated and will be removed in `release-YYYY-MM`. . + +#### Detect + +. + +#### Fix + +. +``` + +### Rules + +- All Breaking Change rules above apply (title, greppable Detect, Code line, before/after, exhaustiveness). +- Always name the planned removal release in the prose intro. Open-ended deprecations (no fixed removal release announced) state that explicitly. + +## Feature entry shape + +```markdown +### Feature Name + +A short, value-first intro — what users can now do and why it matters. State whether the feature is auto-available or needs configuration. + +[Config or API diff — only when activation/config is required; show only the diff, in a `js`/`json` block.] + +[{{< img src="release-YYYY-MM-description.png" alt="…" width="600" >}} — for UI-facing features.] + +For more information, see the [Label]({{< ref "/path/to/doc" >}}) documentation. +``` + +For features with several distinct parts or steps, use `####` sub-sections. Include a before/after when the feature changes existing familiar behaviour. + +### Rules + +- Title is plain text, sentence case, no icon. +- Lead with user value; keep the intro high-level and link to docs rather than repeating them. +- Always state activation status (auto-available vs requires config) — getting this wrong misleads readers. Show only the config diff when activation is needed. +- Use screenshots for UI-facing features (`{{< img >}}` with meaningful alt text). Include a before/after when the feature changes existing behaviour. +- If the feature replaces something deprecated, say so briefly and link it (`{{< ref "/path" >}}` for internal docs, `{{< release "release-YYYY-MM" >}}` for other releases). +- For non-trivial setup, add: _"Reach out to your customer solutions contact for help getting started."_ +- Tone: "more Sales, less Packungsbeilage" — short, punchy, value-focused. Use regular hyphens (`-`). + +## Vulnerability Patches and Patches sections + +Both are **informational only** — no per-entry action is required from the reader beyond keeping the deployment on a current patch version. Don't extract upgrade actions from either. (Their structure lives in the release template; this is the semantic contract.) + +`## Vulnerability Patches` lists security advisories (CVE / GHSA), split into `### Livingdocs Server` and `### Livingdocs Editor`. Each entry is either a vulnerability patched in this release or one we are aware of but have not patched, with a short note on impact (e.g. why it is not exploitable in Livingdocs). Use "No known vulnerabilities. :tada:" for a component with none. + +`## Patches` lists bug fixes and improvements shipped as patch versions after the release was announced, split into `### Livingdocs Server Patches` and `### Livingdocs Editor Patches`, each entry linking the version tag and its PR/commit title. + +Patch commit messages occasionally read like breaking changes (e.g. "add breaking change to not use X"). The standard explanation is that the patch implements a breaking change already announced in this release's Breaking Changes section, or — rarely — a real breaking change merged when no customers were affected. Do not extract upgrade actions from the Patches section. + +## Tone conventions across all sections + +- **Address the human reader, not the agent.** Write "review each conflict before changing it," not "surface the conflict to the user." +- **Use plain English for judgment calls.** "This is not a mechanical rename" reads like instructions for an agent. Prefer descriptive framing like "Because this replaces one property with a reference to a separate dashboard definition, each affected content type needs a deliberate choice of which dashboard to point at." +- **Lead with what changed, not the change history.** The TRN is the record; the change log is in commit history. + +## Anchor links + +Hugo has `enableEmoji: true`, and the auto-generated heading slug keeps the icon's name (the colons are dropped, the word stays). So **section** headings, which keep their icon, generate a suffixed slug: + +- `## Breaking Changes :fire:` → `#breaking-changes-fire` +- `## Deprecations :warning:` → `#deprecations-warning` +- `## Features :gift:` → `#features-gift` + +When linking to a section, include that suffix — it is part of the slug. **Entry** headings (`###`) carry no icon, so their slugs are clean: `#removal-of-li-target-length-ui-config-properties`. + +A `-fire` / `-gift` / `-warning` suffix on a link is valid only if the target heading still carries that icon. Check each link against its actual target before changing it — don't strip the suffix blindly. + +## What to leave out + +- Per-entry "Risk if skipped" or "Applies to" sub-headings — redundant with the `:fire:` / `:warning:` icon and the Detect line. +- Full JSON / schema dumps in Feature entries — show only the relevant config diff and link to the reference for the rest. +- Notes that are essentially commit-message rot ("introduced in PR #123", "see issue X"). The PR list and patches section already cover this. +- Emoji in entry headings. From 0de75b8e7bee9a0dcd5e448b0d1e1c810633da0c Mon Sep 17 00:00:00 2001 From: Alex Wild Date: Wed, 17 Jun 2026 08:27:34 +0200 Subject: [PATCH 2/3] refactor(claude): Drop :gift: from feature entry titles Align write-trn-feature-section with the format reference: feature entry headings carry no icon (the :gift: lives on the ## Features section heading only), matching the icon-free entry convention used for breaking changes and deprecations. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/write-trn-feature-section/SKILL.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.claude/skills/write-trn-feature-section/SKILL.md b/.claude/skills/write-trn-feature-section/SKILL.md index 430b9c4d7..5f3096461 100644 --- a/.claude/skills/write-trn-feature-section/SKILL.md +++ b/.claude/skills/write-trn-feature-section/SKILL.md @@ -28,7 +28,7 @@ Ask **one question at a time** — wait for each answer before asking the next: **Example 1 - Simple (auto-available, no config):** ```markdown -### Optimized Media Library Modal :gift: +### Optimized Media Library Modal We've optimized the image selection modal to display more images by increasing its width. The modal now shows up to 6 images per row (depending on screen size), compared to the previous layout. This makes better use of available screen space. @@ -38,7 +38,7 @@ For more information, see the [Media Library]({{< ref "/reference/media-library" **Example 2 - Complex (sub-sections, config, before/after):** ```markdown -### Distribution Dates UI Improvements :gift: +### Distribution Dates UI Improvements Editors use the planning board to manage articles scheduled for publishing and distribution. Setting distribution dates quickly and accurately is essential for efficient workflow management. @@ -78,7 +78,7 @@ For more information, see the [Distribution Dates]({{< ref "/reference/distribut Use this format: ``` -### FEATURE NAME :gift: +### FEATURE NAME INTRO_PARAGRAPH @@ -104,7 +104,7 @@ INTRO_PARAGRAPH - **Complex topics**: add _"Reach out to your customer solutions contact for help getting started."_ if setup is non-trivial. - **Sub-sections**: use `####` headings for multiple distinct sub-features or steps. - **Links**: `{{< ref "/path" >}}` for internal docs. `{{< release "release-YYYY-MM" >}}` for other releases. -- **`:gift:` emoji**: always append to the `###` heading. +- **No emoji on the entry heading**: the `:gift:` lives on the `## Features` section heading only (see `.claude/trn-format-reference.md`). #### Tone & style From 385e81c9a4855e511ebebd1de733f455916dd96d Mon Sep 17 00:00:00 2001 From: Alex Wild Date: Wed, 17 Jun 2026 08:33:04 +0200 Subject: [PATCH 3/3] docs(release-template): Align deprecations icon with format reference Add the :warning: icon to the `## Deprecations` section heading to match the TRN format reference, and remove the icon legend (no longer useful). Co-Authored-By: Claude Opus 4.8 (1M context) --- content/operations/releases/_release-template.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/content/operations/releases/_release-template.md b/content/operations/releases/_release-template.md index fb7712e84..23d083c5b 100644 --- a/content/operations/releases/_release-template.md +++ b/content/operations/releases/_release-template.md @@ -108,7 +108,7 @@ No rollback steps are required for this release. ## Breaking Changes :fire: -## Deprecations +## Deprecations :warning: ## Features :gift: @@ -143,10 +143,3 @@ Here is a list of all patches after the release has been announced. ### Livingdocs Server Patches ### Livingdocs Editor Patches - ---- - -**Icon Legend** - -- Breaking changes: :fire: -- Feature: :gift: