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