410 lines
12 KiB
Markdown
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.
|