release-post
Create professional package release blog posts following Tidyverse or Shiny blog conventions. Use when the user needs to: (1) Write a release announcement blog post for an R or Python package for tidyverse.org or shiny.posit.co, (2) Transform NEWS/changelog content into blog form
Install
npx skills add https://github.com/posit-dev/skills/tree/main/open-source/release-post
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install posit-dev-skills@llmmart
git clone https://github.com/posit-dev/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole posit-dev/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Package Release Post
Create professional R/Python package release blog posts following Tidyverse or Shiny blog conventions.
Quick Start
- Identify the blog platform: Tidyverse (tidyverse.org) or Shiny (shiny.posit.co)
- Verify NEWS.md or changelog exists for the package
- Gather package info: name, version, repository (e.g., "tidyverse/dplyr")
- Follow the workflow below
- Use
scripts/get_contributors.Rto generate acknowledgments - Reference the appropriate formatting guide for final polish
Platform Selection
This skill supports two blog platforms with different formatting requirements:
Tidyverse blog (tidyverse.org)
- Uses hugodown
- R packages primarily
- More rigid structure and conventions
- See
references/tidyverse-formatting.md
Shiny blog (shiny.posit.co)
- Uses Quarto
- R and Python packages
- More flexible, feature-focused structure
- See
references/shiny-formatting.md
First, determine which platform the post is for, then follow the general workflow and apply platform-specific formatting.
General Workflow
These steps apply to both platforms. Content guidelines are based on Tidyverse best practices but adapt them as needed for Shiny posts.
Step 1: Gather Information
Collect required information:
- Platform: Tidyverse or Shiny blog?
- Package name and version: e.g., "dplyr 1.2.0" or "shiny 1.9.0"
- Repository: GitHub repo in "owner/repo" format
- Package language: R or Python
- NEWS content: Read the package's NEWS.md, CHANGELOG, or NEWS
- Package description: One-sentence core purpose
- Previous release tag: For contributor fetching (optional)
- Featured image: For frontmatter (optional but recommended)
Step 2: Structure the Post
Create the post outline following this order:
Frontmatter: Platform-specific YAML (see formatting references)
Title and Opening:
- Title: Package name and version
- Opening: Announcement with one-sentence package description
- Installation: Code block with installation command
- Overview: Brief summary with link to full release notes
Main Content (choose appropriate sections):
- Migration guide (if breaking changes) - Always first when present
- Lifecycle changes (deprecations, soft-deprecations, defunct)
- Feature sections (one per major feature, descriptive headings)
- Minor improvements (bulleted list)
Acknowledgements (when appropriate):
- Use
scripts/get_contributors.R - Format: "A big thank you to all the folks who helped make this release happen:"
- Comma-separated GitHub links
- Use
Step 3: Apply Content Guidelines
Follow the best practices in references/content-guidelines.md:
- Opening style: "We're [random adjective expressing excitement] to announce the release of..."
- Section organization: Migration → Lifecycle → Features → Improvements → Acknowledgements
- Tone: Conversational, professional, enthusiastic but authentic
- Technical precision: Use exact function names in backticks
- Focus on benefits: Explain "why" not just "what"
- Code examples: Realistic, well-commented, properly formatted
Step 4: Transform NEWS Content
Convert NEWS.md bullets to blog-friendly content:
- Research features thoroughly: Don't just copy NEWS bullets—read function docs, check PRs, understand the context
- Expand context: Why changes matter, not just what changed
- Add complete code examples: Show realistic usage with full workflows, not just function signatures
- Explain concepts first: For unfamiliar features, explain what they are and how they work before showing code
- Group thematically: Combine related NEWS items into coherent sections
- Use conversational tone: Transform terse bullets into prose
- Link documentation: Add relevant links to docs and resources
- Highlight breaking changes: Make migration paths clear
- Multi-language parity (Shiny only): For R+Python packages on the Shiny blog, ensure all examples show both languages in tabsets
Step 5: Apply Platform-Specific Formatting
For Tidyverse posts, read references/tidyverse-formatting.md and apply:
- hugodown frontmatter with
slug,photo.url,photo.author - Specific slug format:
packagename-x-y-z(hyphens replace dots) - R code blocks with
rlanguage identifier - Acknowledgements always included as final section
For Shiny posts, read references/shiny-formatting.md and apply:
- Quarto frontmatter with YAML anchors for social media
- Flexible title formatting
- Use tabsets for Python/R or Express/Core variations
- Platform-specific code block attributes
- Acknowledgements optional, varies by post type
- May use lead paragraphs, callouts, embedded media
Step 6: Generate Acknowledgements
Run the contributor script:
Rscript scripts/get_contributors.R "owner/repo"
Or with a specific starting tag for the previous version (or tag used for last release post):
Rscript scripts/get_contributors.R "owner/repo" "v1.0.0"
Copy the markdown output into the Acknowledgements section.
Step 7: Review and Polish
Platform-agnostic checklist:
- Frontmatter complete with all required fields
- Opening clearly states package purpose
- Installation code block present (both languages if applicable)
- Sections organized logically
- Code examples use proper syntax highlighting
- Function names in backticks with parentheses:
`function()` - Package names are not backticked or otherwise styled
- Tone is conversational but not marketing-speak
- No superlatives ("powerful", "rich", "seamless", etc.)
- Features explained with context, not just listed
- Concepts explained before showing code
- All examples show R and Python variants (if applicable)
- Links to full release notes included
Platform-specific checklist:
Tidyverse:
- Slug format:
package-x-y-z(hyphens, not dots) - Photo URL and author included
- Acknowledgements section is final section
- All contributors listed alphabetically
Shiny:
- YAML anchors used for description (
&desc,*desc) - Social media cards configured (
open-graph,twitter-card) - Appropriate filters specified if using tabsets/shinylive
- Tabsets used for showing paired variants (Python/R, Express/Core)
- Multi-language tabsets used consistently (for R+Python packages only)
Reference Documentation
Load these as needed for detailed guidance:
Content Guidelines
references/content-guidelines.md - General best practices for all release posts:
- Post structure and organization
- Opening style and tone
- Section hierarchy and organization
- Code examples and formatting
- Before/after patterns
- Acknowledgments conventions
Platform-Specific Formatting
references/tidyverse-formatting.md - Tidyverse blog requirements:
- hugodown frontmatter structure
- Slug and title conventions
- Photo attribution
- Code block formatting
- Lifecycle section structure
- Acknowledgements format
references/shiny-formatting.md - Shiny blog requirements:
- Quarto frontmatter with YAML anchors
- Social media card configuration
- Lead paragraphs and callouts
- Tabsets for variants
- Line highlighting and annotations
- Video embedding
- Flexible acknowledgements
Resources
scripts/get_contributors.R: Fetch formatted contributor list usingusethis::use_tidy_thanks()references/content-guidelines.md: General content best practices (platform-agnostic)references/tidyverse-formatting.md: Tidyverse-specific formatting requirementsreferences/shiny-formatting.md: Shiny-specific formatting requirements
Platform-Specific Quick Reference
Tidyverse Post Template
---
output: hugodown::hugo_document
slug: package-x-y-z
title: package x.y.z
date: YYYY-MM-DD
author: Your Name
description: >
Brief description
photo:
url: https://unsplash.com/photos/id
author: Photographer Name
categories: [package]
tags: [package]
---
# package x.y.z
We're pleased to announce the release of package x.y.z...
```r
install.packages("package")
```
...
## Acknowledgements
A big thank you to all the folks who helped make this release happen:
[Contributors from get_contributors.R]
Shiny Post Template
---
title: Package Name x.y.z
description: &desc |
Brief description of the release.
author: "Your Name"
date: "YYYY-MM-DD"
image: feature.png
open-graph:
image: feature.png
description: *desc
twitter-card:
image: feature.png
description: *desc
---
# package x.y.z
We're excited to announce package x.y.z...
[Installation for Python or R]
...
Tips
- Breaking changes first: Put migration guides before features
- Highlight the wins: Lead with the most exciting features
- Show don't tell: Use code examples liberally
- Link generously: Help readers find more information
- Keep it conversational: Write like you're explaining to a colleague
- Be authentic: Enthusiasm should feel genuine, not marketing-speak
Files (skills)
-
references
-
content-guidelines.md 11.9 KB
# Content Guidelines for Release Posts General best practices for release post content, regardless of blog platform. These guidelines are based primarily on Tidyverse blog conventions, which provide a principled approach to announcing package updates. ## Table of Contents 1. [Post Structure](#post-structure) 2. [Opening Style](#opening-style) 3. [Section Organization](#section-organization) 4. [Tone and Voice](#tone-and-voice) 5. [Code Examples](#code-examples) 6. [Acknowledgments](#acknowledgments) ## Post Structure Standard structure for release posts: ```markdown [Frontmatter - see formatting guides] # Package Version [Opening paragraph with package description] [Installation instructions] [Overview paragraph about the release] ## Major Feature 1 [Content...] ## Major Feature 2 [Content...] ## Minor improvements [Bulleted list...] ## Acknowledgements [Contributor list] ``` ## Opening Style ### Opening Paragraph Pattern Start with an announcement that establishes the package's core purpose: > "We're [pleased/chuffed/stoked/thrilled/delighted/excited/...] to announce the release of [package] [version]. [Package] [core purpose description in one sentence]." **Examples:** - "We're chuffed to announce the release of testthat 3.3.0. testthat makes it easy to turn your existing informal tests into formal, automated tests" - "We're pleased to announce the release of pkgdown 2.2.0. pkgdown is designed to make it quick and easy to build a beautiful and accessible website" - "We're excited to announce the new Shiny extension for VS Code!" **Vocabulary variations:** - Choose an upbeat and random adjective with connotations of excitement. - Be interesting and bold, but above all positive and fun. ### Installation Instructions Follow the opening with installation instructions as a code block: **R packages:** ```r install.packages("packagename") ``` For multiple packages: ```r install.packages(c("shiny", "bslib")) ``` **Python packages:** ```bash pip install packagename ``` With extras: ```bash pip install "packagename[extra]" ``` ### Overview Paragraph Brief overview of the release following installation: - Link to full release notes when available - Highlight focus areas: "This release focuses on [key themes]" - Set expectations: "This is a [major/minor] release with [X main features]" - Acknowledge breaking changes: "This release includes a number of new features... Some of these changes may require you to update your existing code" ## Section Organization ### Standard Section Hierarchy Organize content in this order: 1. **Migration guide** (if breaking changes) - Put this first when there are breaking changes - Use clear before/after examples - Explain the rationale for changes 2. **Lifecycle changes** (if applicable but not breaking) - Soft deprecations - Deprecations - Defunct (removed) functions - Non-breaking behavioral changes 3. **Major new features** (primary content) - One section per major feature or theme - Use descriptive headings - Lead with what the feature does and why it matters - Include examples 4. **Minor improvements** or **Other new features** - Bulleted list of smaller enhancements - Brief explanations - Can group related items 5. **Acknowledgements** (always final) - Thank contributors - List all contributors with GitHub links ### Section Heading Style - Use sentence case: "Lifecycle changes" not "Lifecycle Changes" - Be descriptive: "Easier `in_parallel()`" not just "New feature" - Include function names in backticks when relevant - Make headings scannable and informative ### Content Organization Within Sections **For migration guides:** ```markdown ## Migrating to vX.Y.Z ### Setting the app theme Prior to vX.Y.Z, you could... [Before example] **With packagename vX.Y.Z,** you now need to... [After example] Read about [the feature](#feature) below to learn why this change was needed. ``` **For lifecycle changes:** ```markdown ## Lifecycle changes * **Fully removed** after 5+ years of deprecation: * `function1()` - use `replacement1()` instead * `function2()` - use `replacement2()` instead * **Newly deprecated** (soft-deprecation): * `function3()` is superseded by `function4()` * `function5()` is no longer recommended * **Breaking changes**: * Brief description of the change and impact ``` **For feature sections:** - Lead with a clear description of what the feature does - Provide context on why it's useful or what problem it solves - Include code examples showing usage - Explain configuration options if relevant - Link to relevant documentation ### Deep Dives on Features Don't just list features from NEWS—research them and provide comprehensive explanations: **Transform NEWS bullets into complete sections:** 1. **Research the feature**: - Read function documentation - Check related PRs and issues for context - Understand the motivation and use cases 2. **Add complete code examples**: - Show realistic usage, not just function signatures - Include comments explaining what's happening - Demonstrate the full workflow, not just isolated calls 3. **Explain the context**: - Why was this feature added? - What problem does it solve? - What are the practical use cases? - How does it fit into typical workflows? 4. **Show use cases and applications**: - Provide examples of when users would need this - Explain different configuration options - Show how features work together **Example transformation:** ❌ **NEWS bullet approach:** ```markdown ## Bookmarking - Added `chat_restore()` for bookmarking support (#82) ``` ✅ **Deep dive approach:** ```markdown ### Bookmarking support shinychat now supports Shiny's bookmarking feature for saving and restoring chat sessions. The new `chat_restore()` function saves the chat client state and restores the message history: [Complete code example showing actual usage] By default, `chat_restore()` automatically updates the bookmark when users submit messages and when the LLM completes its response. This means users can refresh the page or share a URL and pick up right where they left off. For apps with large chat histories, you can use `enableBookmarking = "server"` to store state server-side without URL size limitations. ``` **Research sources:** - Use `r-btw` tools to read R function documentation - Read GitHub PRs/issues linked in NEWS - Check package vignettes and articles - Look at example apps in the repository **For improvements:** ```markdown ## Minor improvements * Brief description of improvement with function name in backticks * Another improvement with relevant technical details * Performance gains quantified when possible (e.g., "2x faster") ``` ## Tone and Voice ### Writing Style - **Conversational but professional**: "We're excited to announce" rather than "It is announced" - **Inclusive**: Use "we" and "you" rather than passive voice - **Enthusiastic but authentic**: Avoid over-the-top marketing language - **Technical precision**: Use exact function names, parameter names, and technical terms - **Focus on benefits**: Explain the "why" not just the "what" ### Avoiding Marketing Speak Release posts should be friendly and instructional, not advertising. Watch for and remove: **Superlatives and promotional adjectives:** - ❌ "powerful set of features", "rich, interactive displays", "beautiful interface" - ✅ "set of features", "interactive displays", "interface" **Exaggerated benefit claims:** - ❌ "handles all the complexity of persisting state" - ✅ "saves the chat client state and restores the message history" **Generic enthusiasm:** - ❌ "opens up exciting possibilities for building transparent, user-friendly AI applications" - ✅ Direct description of what the feature does **Over-hyped capability statements:** - ❌ "give you fine-grained control over every aspect" - ✅ "lets you control the chat interface" **Tone review checklist:** - [ ] Remove words like "powerful", "robust", "seamless", "elegant", "revolutionary" - [ ] Replace "makes it easy to" with direct descriptions of functionality - [ ] Prefer descriptive statements focusing on what the function does - [ ] Avoid overuse of phrases that sound like product marketing ("best-in-class", "production-ready") ### Common Phrases - "We're [emotion] to announce..." - "A big thank you to all the folks who helped make this release happen" - "You can see a full list of changes in the release notes" - "This makes it easier to..." - "We've improved..." - "This release focuses on..." - "Prior to vX.Y.Z, you had to..." - "With this release, you can now..." ### Technical Voice - Use backticks for all code elements: `` `function()` ``, `` `argument` ``, `` `"value"` `` - Link to relevant documentation when helpful - Be specific about behavior: "returns `NULL`" not "returns nothing" - Explain technical decisions when they impact users - Acknowledge tradeoffs when present ## Code Examples ### Explain Concepts Before Code For features that introduce new or unfamiliar concepts, explain the concept first before showing code: **Pattern: Concept → How it works → Why it matters → Code** 1. **What is the feature/concept?** (1-2 sentences) 2. **How does it work?** (Especially non-obvious aspects) 3. **Why does it matter?** (Practical implications) 4. **Show the code** (With examples) **Key principles:** - Assume readers may not be familiar with the concept - Explain non-obvious aspects clearly - Connect concepts to practical outcomes - Use plain language before technical language ### Inline Code - Function names: `` `map_chr()` `` - Arguments: `` `na.rm = TRUE` `` - Values: `` `NULL` ``, `` `TRUE` ``, `` `"string"` `` - File paths: `` `app.py` `` ### Code Block Principles - Use realistic but simple examples - Include expected output when relevant - Show error messages for examples of better error handling - Format multi-line function calls with proper indentation - Add comments for clarity when needed: `# This does X` - Keep examples focused on the feature being demonstrated ### Before/After Examples When showing improvements, use clear before/after structure: ```markdown Previously, you had to write: [Code block showing old approach] Now you can write: [Code block showing new approach] ``` Or for migration guides: ```markdown **Before:** [Old code] **After:** [New code] ``` ## Acknowledgments ### When to Include - **Always include** for package releases with external contributors - Optional for internal tooling announcements - Include at the end as the final section ### Section Format ```markdown ## Acknowledgements A big thank you to all [the folks/everyone] who [helped make this release happen/contributed to this release]: [@username1](https://github.com/username1), [@username2](https://github.com/username2), ... ``` ### Fetching Contributors Use `usethis::use_tidy_thanks()` in R: ```r # From last release to current usethis::use_tidy_thanks("owner/repo") # From specific tag/SHA usethis::use_tidy_thanks("owner/repo", from = "v1.0.0") ``` This generates properly formatted markdown for the contributor list that can be included verbatim. ## Transforming NEWS to Blog Content When converting NEWS.md entries to blog post format: 1. **Expand context**: Technical bullets become paragraphs explaining why changes matter 2. **Add examples**: Include code demonstrating new features or changes 3. **Group thematically**: Combine scattered NEWS items into coherent sections 4. **Use conversational tone**: Transform terse bullets into readable prose 5. **Link proactively**: Add links to relevant documentation and resources 6. **Focus on user impact**: Explain how changes affect typical usage 7. **Highlight breaking changes**: Make migration paths clear and prominent ## Release Notes Link Always include a link to full release notes: ```markdown You can see a full list of changes in the [release notes](url). ``` This allows readers to find exhaustive details while keeping the blog post focused and readable. -
shiny-formatting.md 11.8 KB
# Shiny Blog Formatting Conventions Shiny-specific formatting requirements for blog posts on shiny.posit.co. These conventions are for the Quarto-based Shiny blog. ## Frontmatter Format Shiny blog posts use Quarto YAML frontmatter with this structure: ```yaml --- title: Package Name Version description: &desc | Brief description of the package and release. author: "Author Name" date: "YYYY-MM-DD" image: &img feature.png open-graph: image: *img description: *desc twitter-card: image: *img description: *desc --- ``` ### Required Fields - **`title`**: Display title (no specific format required, flexible) - Can be: `"packagename version"`, `"Package Name x.y.z"`, or descriptive - Examples: - `"shinyswatch 0.7.0"` - `"Reintroducing the Shiny Extension for VS Code"` - `"Branded theming for Shiny for Python apps"` - **`description`**: Brief summary with YAML anchor for reuse - Use `&desc` anchor and `|` for multi-line - Reuse in social media cards with `*desc` - **`author`**: Author name in quotes (can be single string or array) - Single: `"Garrick Aden-Buie"` - Multiple: `["Author One", "Author Two"]` - **`date`**: ISO format in quotes `"YYYY-MM-DD"` - **`image`**: Path to featured image (relative to post directory) ### Social Media Cards Use YAML anchors to avoid repeating the description: ```yaml description: &desc | Your description here that will be reused. open-graph: description: *desc twitter-card: description: *desc ``` The `&desc` creates an anchor, and `*desc` references it. ### Optional But Common Fields - **`filters`**: Quarto filters to use - `shinylive` - For embedding Shinylive apps - `line-highlight` - For highlighting specific lines - **`engine`**: Quarto engine (`knitr`, `markdown`, `jupyter`) - **`freeze`**: Set to `true` if the post includes *any* computational output - **`format`**: HTML format options - `code-link: true` - Enable code linking - `anchor-sections: true` - Enable section anchors - `reference-location: document` or `section` - Where to place footnotes - **`code-annotations`**: Set to `hover` for hover annotations - **`editor`**: Editor options like `render-on-save: true` ### Image Options Additional image control fields: ```yaml image: feature.svg imagealt: "Alternative text for image" image-header-disable: true # Don't show image in header ``` ### What's NOT Included Unlike Tidyverse posts, Shiny posts do **not** include: - `output: hugodown::hugo_document` - `slug` (filename determines URL) - `photo.url` and `photo.author` (different image structure) - Consistent `categories` field (optional, varies by post) ## Title Format The main title can be flexible: ```markdown # packagename version ``` Or more descriptive: ```markdown # Reintroducing the Shiny Extension for VS Code ``` There's less rigid formatting for titles in Shiny posts. ## Lead Paragraphs Shiny posts may use a lead paragraph div for emphasis: ```markdown ::: lead **We're excited to announce the new Shiny extension for VS Code!** ::: ``` This creates a larger, emphasized opening paragraph. ## Code Formatting ### For Python Packages Use bash code blocks for installation: ````markdown ```bash pip install packagename ``` ```` With extras: ````markdown ```bash pip install "packagename[extra]" ``` ```` ### For R Packages Use R code blocks: ````markdown ```r install.packages("packagename") ``` ```` For multiple packages: ````markdown ```r install.packages(c("shiny", "bslib")) ``` ```` ### Code Block Attributes Shiny posts use Quarto code block attributes: ````markdown ```{.python filename="app.py"} from shiny import App # code here ``` ```` ````markdown ```{r install-bslib} #| eval: false install.packages("bslib") ``` ```` ### Line Highlighting Use `# <<` comments to highlight lines (requires `line-highlight` filter): ````markdown ```{.python filename="app.py"} from shiny.express import ui import shinyswatch ui.page_opts(theme=shinyswatch.theme.darkly) # << # rest of code... ``` ```` ### Code Annotations With `code-annotations: hover` in frontmatter, you can add annotations: ```python result = some_function() # <1> ``` ```markdown 1. This annotation explains the line above ``` ## Tabsets for Multiple Variants Shiny posts frequently use tabsets to show Express vs Core mode or Python vs R: ````markdown ::: {.panel-tabset .shiny-mode-tabset group="shiny-app-mode"} #### Express ```{.python filename="app.py"} from shiny.express import ui # Express code ``` #### Core ```{.python filename="app.py"} from shiny import ui # Core code ``` ::: ```` ### Nested Tabsets You can nest tabsets for Before/After within Express/Core: ````markdown ::: {.panel-tabset group="shiny-app-mode"} #### Express ::: {.panel-tabset} ##### Before ```python # old code ``` ##### After ```python # new code ``` ::: #### Core ::: {.panel-tabset} ##### Before ```python # old code ``` ##### After ```python # new code ``` ::: ::: ```` ## Callouts Quarto callouts for notes, tips, warnings: ```markdown ::: {.callout-tip title="Writing brand.yml with the help of an LLM"} We know that writing YAML isn't everyone's cup of tea! ... ::: ``` Types: `note`, `tip`, `warning`, `caution`, `important` ## Embedded Media ### Videos ````markdown ::: column-page ```{=html} <video controls> <source src="videos/demo.webm" type="video/webm"> <source src="videos/demo.mp4" type="video/mp4"> </video> ``` ::: ```` ### Images with Attributes ```markdown {.shadow} ``` Or with more attributes: ```markdown {fig-alt="Detailed alt text" fig-align="center" width="100%"} ``` ## Shinylive Examples With the `shinylive` filter, you can embed live examples: ````markdown ```{shinylive-python} #| standalone: true #| components: [editor, viewer] ## file: app.py from shiny.express import input, render, ui # App code here ``` ```` Or link to examples: ```markdown We've added a [complete branded theming example](https://shinylive.io/py/examples/#branded-theming) to shinylive.io. ``` ## Acknowledgements Section Less consistent in Shiny posts. When present, variations include: ### Variation 1: Simple Thanks ```markdown ## Thanks! Thank you for trying out the Shiny extension for VS Code! If you find it helpful, please rate the extension on [the marketplace][Shiny extension]. ``` ### Variation 2: Multiple Package Releases ```markdown ## Release notes **Big shout out to everyone involved!** 💙 We'd want to extend a huge thank you to everyone who contributed pull requests, bug reports and feature requests. #### bslib [v0.7.0](https://rstudio.github.io/bslib/news/index.html#bslib-070) [List of contributors] #### shiny [v1.8.1](https://shiny.posit.co/r/reference/shiny/1.8.1/upgrade.html) [List of contributors] ``` ### Variation 3: Omitted Some Shiny posts don't include acknowledgements, especially for announcements of tools rather than package releases. ### When Acknowledgements Are Included Use similar format to Tidyverse: ```markdown ## Acknowledgements We'd like to thank everyone who contributed to this release: [@user1](https://github.com/user1), [@user2](https://github.com/user2), and [@user3](https://github.com/user3). ``` Or just reference the generator in code: ```markdown ```{r} #| echo: false #| eval: false usethis::use_tidy_thanks("rstudio/bslib", from = "v0.6.1") ``` ``` ## CSS Customization Shiny posts may include custom CSS in HTML blocks: ````markdown ```{=html} <style> img { border-radius: 8px; } video { max-width: 100%; margin-bottom: 1rem; } </style> ``` ```` ## Column Layouts Use Quarto's column classes for wider content: ```markdown ::: column-page [Wide content here] ::: ::: column-body-outset [Slightly wider content] ::: ``` ## Footnotes Use standard markdown footnotes: ```markdown Text with a footnote[^footnote-key]. [^footnote-key]: This is the footnote text. ``` With `reference-location: document` or `section` in frontmatter to control placement. ## Links and References Define link references at the top or bottom of the file: ```markdown [brand.yml]: https://posit-dev.github.io/brand-yml [quarto]: https://quarto.org [shiny]: https://shiny.posit.co ``` Then use them inline: ```markdown We're excited about [brand.yml] support! ``` ## Multi-Language Support (R and Python) The Shiny blog often covers packages released for both R and Python (e.g., shiny, shinychat). Unlike Tidyverse posts which are language-specific, Shiny posts should show examples in both languages using Quarto tabsets. ### Use Tabsets Consistently Every code example should include both R and Python variants using Quarto tabsets: ```markdown ::: {.panel-tabset group="language"} ## R ```r # R code here ``` ## Python ```python # Python code here ``` ::: ``` **Guidelines:** - Use `group="language"` to sync all language tabsets on the page - Provide equivalent functionality in both languages - Don't show R-only or Python-only examples unless the feature is language-specific - Keep examples parallel—if the R example shows 5 lines, the Python example should be similar ### Installation Instructions Always show installation for both languages at the start of the post: ```markdown ::: {.panel-tabset group="language"} ## R ```r install.packages("packagename") ``` ## Python ```bash pip install packagename ``` ::: ``` ### Language-Specific Features When features differ between languages, be explicit about the differences: ```markdown ::: {.panel-tabset group="language"} ## R In R, use `tool_annotations()` to customize display: ```r tool_annotations(title = "My Tool", icon = bsicons::bs_icon("star")) ``` ## Python In Python, use the `._display` attribute: ```python my_tool._display = {"title": "My Tool", "icon": "star"} ``` ::: ``` ### Version Information Package versions often differ between R and Python. Be explicit: - "Available in shinychat for R (v0.3.0) and shinychat for Python (v0.2.0 or later)" - Link to both language-specific documentation - Include separate release notes links: ```markdown You can see the full list of changes in the [R release notes](url) and [Python release notes](url). ``` ### When to Use Multi-Language Tabsets - **Always use** for packages that have both R and Python versions (shiny, shinychat, querychat, etc.) - **Don't use** for Python-only packages (shinyswatch) or R-only packages - **Don't use** for Tidyverse blog posts (which are built with hugodown/Hugo, not Quarto) ## Example Complete Frontmatter ### Python Package ```yaml --- title: shinyswatch 0.7.0 description: &desc Customizable shinyswatch themes and an improved theme picker round out shinyswatch v0.7.0. author: "Garrick Aden-Buie" date: "2024-07-19" image: feature.jpg open-graph: image: feature.jpg description: *desc twitter-card: image: feature.png description: *desc filters: - line-highlight --- ``` ### R Package with Full Options ```yaml --- title: "Shiny for R updates: Extended tasks, JavaScript errors, and many bslib improvements" description: &desc | An overview of recent Shiny for R updates, including extended tasks, JavaScript errors, and many bslib improvements. author: - Carson Sievert date: "2024-03-27" image: feature.png open-graph: image: feature.png description: *desc twitter-card: image: feature.png description: *desc editor: render-on-save: true engine: knitr filters: - shinylive freeze: true format: html: code-link: true anchor-sections: true reference-location: section code-annotations: hover --- ``` ## Examples of Well-Formatted Posts Reference these posts for formatting examples: - [shinyswatch 0.7.0](https://shiny.posit.co/blog/posts/shinyswatch-0.7.0/) - [Shiny Extension for VS Code 1.0.0](https://shiny.posit.co/blog/posts/shiny-vscode-1.0.0/) - [Shiny for R 1.8.1](https://shiny.posit.co/blog/posts/shiny-r-1.8.1/) - [Branded theming for Shiny for Python](https://shiny.posit.co/blog/posts/shiny-python-1.2-brand-yml/) -
tidyverse-formatting.md 7.1 KB
# Tidyverse Blog Formatting Conventions Tidyverse-specific formatting requirements for blog posts on tidyverse.org. These conventions are for the hugodown-based Tidyverse blog. ## Workflow for tidyverse.org Blog When creating a blog post for the official `tidyverse/tidyverse.org` repository, follow these steps: 1. **Install hugodown** (if not already installed): ```r pak::pkg_install("r-lib/hugodown") ``` 2. **Create a new post**: ```r hugodown::use_tidy_post("short-name") ``` This creates `content/blog/short-name/` containing an `index.Rmd` file. Common patterns for `"short-name"`: - Package release: `lifecycle-1-0-0`, `parsnip-0-1-2` - Package release with specific topic: `dplyr-1-0-0-rowwise`, `parsnip-adjacent`, `dplyr-1-0-4-if-any` - Topic only: `self-cleaning-test-fixtures`, `taking-control-of-plot-scaling` 3. **Write and knit**: - Edit the generated `index.Rmd` file - Knit `index.Rmd` to generate `index.md` - Note: `.Rmd` files are only rendered when you explicitly knit them 4. **Preview the site**: ```r hugodown::hugo_start() ``` This runs once per session and continues in the background to turn `.md` into `.html`. 5. **Check for outdated files** (if concerned): ```r hugodown::site_outdated() ``` Lists all `.Rmd`s that need to be re-rendered. 6. **Add a photo**: Every blog post must be accompanied by a photo. If you don't have one in mind, try: - <https://unsplash.com> - <https://pexels.com> - Jenny Bryan's [free photo](https://github.com/jennybc/free-photos) link collection 7. **Submit PR**: - Every PR gets an automatic live preview via Netlify - Once merged, the preview becomes the live site ### Important Notes - The site uses **hugodown** (not blogdown), which separates building into two steps: - hugodown generates `.md` from `.Rmd` - hugo generates `.html` from `.md` - Use `.Rmd` files (not `.Rmarkdown`) - Output should be `output: hugodown::hugo_document` - If updating an old post to use hugodown: - Rename from `.Rmarkdown` to `.Rmd` - Delete the `.markdown` file - Set `output: hugodown::hugo_document` in YAML metadata ### For Additional Context If you need more details about the workflow or encounter issues, consult the `README.md` in the `tidyverse/tidyverse.org` repository. ## Frontmatter Format Tidyverse blog posts use YAML frontmatter with this structure: ```yaml --- output: hugodown::hugo_document slug: package-name-version title: package-name version date: YYYY-MM-DD author: Author Name description: > Brief description of the package and release photo: url: https://unsplash.com/photos/photo-id author: Photographer Name categories: [package-name] tags: [package-name, category] --- ``` ### Required Fields - **`output`**: Always `hugodown::hugo_document` - **`slug`**: URL slug using hyphens - Format: `packagename-x-y-z` (e.g., `ellmer-0-4-0`) - Replace dots with hyphens in version numbers - **`title`**: Display title with spaces - Format: `packagename x.y.z` (e.g., `ellmer 0.4.0`) - **`date`**: ISO format `YYYY-MM-DD` - **`author`**: Full name of primary author - **`description`**: Brief summary (can use `>` for multi-line) - **`photo`**: Featured image with attribution - `url`: Full URL to image (often Unsplash) - `author`: Photographer name for attribution - **`categories`**: Array with package name - **`tags`**: Array with package name and related tags ### Slug vs Title Convention The slug is used in URLs and must be URL-safe: - Slug: `purrr-1-2-0` (hyphens, no dots) - Title: `purrr 1.2.0` (space, dots in version) ### Image Attribution Featured images are typically from Unsplash with proper photographer attribution: ```yaml photo: url: https://unsplash.com/photos/abc123 author: John Doe ``` ## Title Format The main title uses a simple format with space between package name and version: ```markdown # packagename 1.2.0 ``` No "released" or "version" prefix. Just the package name and version number. ## Code Formatting ### Language Identifiers Use triple backticks with `r` language identifier for R code: ````markdown ```r library(packagename) result <- function_name( arg1 = "value", arg2 = TRUE ) ``` ```` For installation: ````markdown ```r install.packages("packagename") ``` ```` ### Inline Code Elements - Function names: `` `function()` `` - Packages: `` `{packagename}` `` when emphasizing it's a package - Arguments: `` `arg = value` `` - Values: `` `NULL` ``, `` `TRUE` ``, `` `"string"` `` ### Function Links When linking to function documentation, use markdown links: ```markdown [`function_name()`](https://url-to-docs) ``` ## Section Structure ### Lifecycle Section Format When including lifecycle changes, use this structure: ```markdown ## Lifecycle changes * **Fully removed** after 5+ years of deprecation: * `function1()` - use `replacement1()` instead * `function2()` - use `replacement2()` instead * **Newly deprecated** (soft-deprecation): * `function3()` is superseded by `function4()` * `function5()` is no longer recommended * **Breaking changes**: * Description of what changed and why ``` Use bold for the lifecycle stage labels. ### Feature Sections Use sentence case in headings: ```markdown ## Easier `in_parallel()` [Description of the feature...] ``` Include function names in backticks when they're part of the heading. ## Acknowledgements Section Always include as the final section: ```markdown ## Acknowledgements A big thank you to all the folks who helped make this release happen: [@username1](https://github.com/username1), [@username2](https://github.com/username2), [@username3](https://github.com/username3), and [@username4](https://github.com/username4). ``` ### Formatting Rules - Single paragraph format (not bulleted list) - GitHub handles as markdown links - Alphabetical order - Comma-separated with "and" before the last name - Period at the end ### Generating the List Use `usethis::use_tidy_thanks()`: ```r # Fetch contributors since last release usethis::use_tidy_thanks("tidyverse/packagename") # Or from specific tag usethis::use_tidy_thanks("tidyverse/packagename", from = "v1.0.0") ``` This function outputs properly formatted markdown that can be copied directly into the blog post. ## Release Notes Link Include a link to the full release notes (typically on pkgdown site): ```markdown You can see a full list of changes in the [release notes](https://packagename.tidyverse.org/news/). ``` ## Example Complete Frontmatter ```yaml --- output: hugodown::hugo_document slug: purrr-1-2-0 title: purrr 1.2.0 date: 2025-11-04 author: Hadley Wickham description: > purrr 1.2.0 includes deprecations and minor enhancements to functional programming tools in R. photo: url: https://unsplash.com/photos/xyz789 author: Jane Photographer categories: [purrr] tags: [purrr, tidyverse] --- ``` ## Examples of Well-Formatted Posts Reference these posts for formatting examples: - [pkgdown 2.2.0](https://www.tidyverse.org/blog/2025/11/pkgdown-2-2-0/) - [testthat 3.3.0](https://www.tidyverse.org/blog/2025/11/testthat-3-3-0/) - [purrr 1.2.0](https://www.tidyverse.org/blog/2025/11/purrr-1-2-0/) - [ellmer 0.4.0](https://www.tidyverse.org/blog/2025/11/ellmer-0-4-0/)
-
-
scripts
-
get_contributors.R 1.4 KB · in bundle
-
-
SKILL.md 9.7 KB
--- name: release-post description: > Create professional package release blog posts following Tidyverse or Shiny blog conventions. Use when the user needs to: (1) Write a release announcement blog post for an R or Python package for tidyverse.org or shiny.posit.co, (2) Transform NEWS/changelog content into blog format, (3) Generate acknowledgments sections with contributor lists, (4) Format posts following specific blog platform requirements. Supports both Tidyverse (hugodown) and Shiny (Quarto) blog formats with automated contributor fetching and comprehensive style guidance. metadata: author: Garrick Aden-Buie (@gadenbuie) version: "1.0" license: MIT --- # Package Release Post Create professional R/Python package release blog posts following Tidyverse or Shiny blog conventions. ## Quick Start 1. **Identify the blog platform**: Tidyverse (tidyverse.org) or Shiny (shiny.posit.co) 2. Verify NEWS.md or changelog exists for the package 3. Gather package info: name, version, repository (e.g., "tidyverse/dplyr") 4. Follow the workflow below 5. Use `scripts/get_contributors.R` to generate acknowledgments 6. Reference the appropriate formatting guide for final polish ## Platform Selection This skill supports two blog platforms with different formatting requirements: - **Tidyverse blog** (tidyverse.org) - Uses hugodown - R packages primarily - More rigid structure and conventions - See `references/tidyverse-formatting.md` - **Shiny blog** (shiny.posit.co) - Uses Quarto - R and Python packages - More flexible, feature-focused structure - See `references/shiny-formatting.md` **First, determine which platform the post is for**, then follow the general workflow and apply platform-specific formatting. ## General Workflow These steps apply to both platforms. Content guidelines are based on Tidyverse best practices but adapt them as needed for Shiny posts. ### Step 1: Gather Information Collect required information: - **Platform**: Tidyverse or Shiny blog? - **Package name and version**: e.g., "dplyr 1.2.0" or "shiny 1.9.0" - **Repository**: GitHub repo in "owner/repo" format - **Package language**: R or Python - **NEWS content**: Read the package's NEWS.md, CHANGELOG, or NEWS - **Package description**: One-sentence core purpose - **Previous release tag**: For contributor fetching (optional) - **Featured image**: For frontmatter (optional but recommended) ### Step 2: Structure the Post Create the post outline following this order: 1. **Frontmatter**: Platform-specific YAML (see formatting references) 2. **Title and Opening**: - Title: Package name and version - Opening: Announcement with one-sentence package description - Installation: Code block with installation command - Overview: Brief summary with link to full release notes 3. **Main Content** (choose appropriate sections): - **Migration guide** (if breaking changes) - Always first when present - **Lifecycle changes** (deprecations, soft-deprecations, defunct) - **Feature sections** (one per major feature, descriptive headings) - **Minor improvements** (bulleted list) 4. **Acknowledgements** (when appropriate): - Use `scripts/get_contributors.R` - Format: "A big thank you to all the folks who helped make this release happen:" - Comma-separated GitHub links ### Step 3: Apply Content Guidelines Follow the best practices in `references/content-guidelines.md`: - **Opening style**: "We're [random adjective expressing excitement] to announce the release of..." - **Section organization**: Migration → Lifecycle → Features → Improvements → Acknowledgements - **Tone**: Conversational, professional, enthusiastic but authentic - **Technical precision**: Use exact function names in backticks - **Focus on benefits**: Explain "why" not just "what" - **Code examples**: Realistic, well-commented, properly formatted ### Step 4: Transform NEWS Content Convert NEWS.md bullets to blog-friendly content: - **Research features thoroughly**: Don't just copy NEWS bullets—read function docs, check PRs, understand the context - **Expand context**: Why changes matter, not just what changed - **Add complete code examples**: Show realistic usage with full workflows, not just function signatures - **Explain concepts first**: For unfamiliar features, explain what they are and how they work before showing code - **Group thematically**: Combine related NEWS items into coherent sections - **Use conversational tone**: Transform terse bullets into prose - **Link documentation**: Add relevant links to docs and resources - **Highlight breaking changes**: Make migration paths clear - **Multi-language parity** (Shiny only): For R+Python packages on the Shiny blog, ensure all examples show both languages in tabsets ### Step 5: Apply Platform-Specific Formatting **For Tidyverse posts**, read `references/tidyverse-formatting.md` and apply: - hugodown frontmatter with `slug`, `photo.url`, `photo.author` - Specific slug format: `packagename-x-y-z` (hyphens replace dots) - R code blocks with `r` language identifier - Acknowledgements always included as final section **For Shiny posts**, read `references/shiny-formatting.md` and apply: - Quarto frontmatter with YAML anchors for social media - Flexible title formatting - Use tabsets for Python/R or Express/Core variations - Platform-specific code block attributes - Acknowledgements optional, varies by post type - May use lead paragraphs, callouts, embedded media ### Step 6: Generate Acknowledgements Run the contributor script: ```bash Rscript scripts/get_contributors.R "owner/repo" ``` Or with a specific starting tag for the previous version (or tag used for last release post): ```bash Rscript scripts/get_contributors.R "owner/repo" "v1.0.0" ``` Copy the markdown output into the Acknowledgements section. ### Step 7: Review and Polish Platform-agnostic checklist: - [ ] Frontmatter complete with all required fields - [ ] Opening clearly states package purpose - [ ] Installation code block present (both languages if applicable) - [ ] Sections organized logically - [ ] Code examples use proper syntax highlighting - [ ] Function names in backticks with parentheses: `` `function()` `` - [ ] Package names are not backticked or otherwise styled - [ ] Tone is conversational but not marketing-speak - [ ] No superlatives ("powerful", "rich", "seamless", etc.) - [ ] Features explained with context, not just listed - [ ] Concepts explained before showing code - [ ] All examples show R and Python variants (if applicable) - [ ] Links to full release notes included Platform-specific checklist: **Tidyverse:** - [ ] Slug format: `package-x-y-z` (hyphens, not dots) - [ ] Photo URL and author included - [ ] Acknowledgements section is final section - [ ] All contributors listed alphabetically **Shiny:** - [ ] YAML anchors used for description (`&desc`, `*desc`) - [ ] Social media cards configured (`open-graph`, `twitter-card`) - [ ] Appropriate filters specified if using tabsets/shinylive - [ ] Tabsets used for showing paired variants (Python/R, Express/Core) - [ ] Multi-language tabsets used consistently (for R+Python packages only) ## Reference Documentation Load these as needed for detailed guidance: ### Content Guidelines **`references/content-guidelines.md`** - General best practices for all release posts: - Post structure and organization - Opening style and tone - Section hierarchy and organization - Code examples and formatting - Before/after patterns - Acknowledgments conventions ### Platform-Specific Formatting **`references/tidyverse-formatting.md`** - Tidyverse blog requirements: - hugodown frontmatter structure - Slug and title conventions - Photo attribution - Code block formatting - Lifecycle section structure - Acknowledgements format **`references/shiny-formatting.md`** - Shiny blog requirements: - Quarto frontmatter with YAML anchors - Social media card configuration - Lead paragraphs and callouts - Tabsets for variants - Line highlighting and annotations - Video embedding - Flexible acknowledgements ## Resources - **`scripts/get_contributors.R`**: Fetch formatted contributor list using `usethis::use_tidy_thanks()` - **`references/content-guidelines.md`**: General content best practices (platform-agnostic) - **`references/tidyverse-formatting.md`**: Tidyverse-specific formatting requirements - **`references/shiny-formatting.md`**: Shiny-specific formatting requirements ## Platform-Specific Quick Reference ### Tidyverse Post Template ````markdown --- output: hugodown::hugo_document slug: package-x-y-z title: package x.y.z date: YYYY-MM-DD author: Your Name description: > Brief description photo: url: https://unsplash.com/photos/id author: Photographer Name categories: [package] tags: [package] --- # package x.y.z We're pleased to announce the release of package x.y.z... ```r install.packages("package") ``` ... ## Acknowledgements A big thank you to all the folks who helped make this release happen: [Contributors from get_contributors.R] ```` ### Shiny Post Template ````markdown --- title: Package Name x.y.z description: &desc | Brief description of the release. author: "Your Name" date: "YYYY-MM-DD" image: feature.png open-graph: image: feature.png description: *desc twitter-card: image: feature.png description: *desc --- # package x.y.z We're excited to announce package x.y.z... [Installation for Python or R] ... ```` ## Tips - **Breaking changes first**: Put migration guides before features - **Highlight the wins**: Lead with the most exciting features - **Show don't tell**: Use code examples liberally - **Link generously**: Help readers find more information - **Keep it conversational**: Write like you're explaining to a colleague - **Be authentic**: Enthusiasm should feel genuine, not marketing-speak
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.