Files
gh-posit-dev-skills-open-so…/skills/release-post/references/content-guidelines.md
2025-11-30 08:48:07 +08:00

410 lines
12 KiB
Markdown

# 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.