Agent skill
lifecycle
Guidance for managing R package lifecycle according to tidyverse principles using the lifecycle package. Use when: (1) Setting up lifecycle infrastructure in a package, (2) Deprecating functions or arguments, (3) Renaming functions or arguments, (4) Superseding functions, (5) Marking functions as experimental, (6) Understanding lifecycle stages (stable, experimental, deprecated, superseded), or (7) Writing deprecation helpers for complex scenarios.
Install this agent skill to your Project
npx add-skill https://github.com/posit-dev/skills/tree/main/r-lib/lifecycle
Metadata
Additional technical details for this skill
- author
- Garrick Aden-Buie (@gadenbuie)
- version
- 1.0
SKILL.md
R Package Lifecycle Management
Manage function and argument lifecycle using tidyverse conventions and the lifecycle package.
Setup
Check if lifecycle is configured by looking for lifecycle-*.svg files in man/figures/.
If not configured, run:
usethis::use_lifecycle()
This:
- Adds lifecycle to
Importsin DESCRIPTION - Adds
@importFrom lifecycle deprecatedto the package documentation file - Copies badge SVGs to
man/figures/
Lifecycle Badges
Insert badges in roxygen2 documentation:
#' @description
#' `r lifecycle::badge("experimental")`
#' `r lifecycle::badge("deprecated")`
#' `r lifecycle::badge("superseded")`
For arguments:
#' @param old_arg `r lifecycle::badge("deprecated")` Use `new_arg` instead.
Only badge functions/arguments whose stage differs from the package's overall stage.
Deprecating a Function
- Add badge and explanation to
@description:
#' Do something
#'
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `old_fun()` was deprecated in mypkg 1.0.0. Use [new_fun()] instead.
#' @keywords internal
- Add
deprecate_warn()as first line of function body:
old_fun <- function(x) {
lifecycle::deprecate_warn("1.0.0", "old_fun()", "new_fun()")
new_fun(x)
}
- Show migration in examples:
#' @examples
#' old_fun(x)
#' # ->
#' new_fun(x)
Deprecation Functions
| Function | When to Use |
|---|---|
deprecate_soft() |
First stage; warns only direct users and during tests |
deprecate_warn() |
Standard deprecation; warns once per 8 hours |
deprecate_stop() |
Final stage before removal; errors with helpful message |
Deprecation workflow for major releases:
- Search
deprecate_stop()- consider removing function entirely - Replace
deprecate_warn()withdeprecate_stop() - Replace
deprecate_soft()withdeprecate_warn()
Renaming a Function
Move implementation to new name, call from old name with deprecation:
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `add_two()` was renamed to `number_add()` for API consistency.
#' @keywords internal
#' @export
add_two <- function(x, y) {
lifecycle::deprecate_warn("1.0.0", "add_two()", "number_add()")
number_add(x, y)
}
#' Add two numbers
#' @export
number_add <- function(x, y) {
x + y
}
Deprecating an Argument
Use deprecated() as default value with is_present() check:
#' @param path `r lifecycle::badge("deprecated")` Use `file` instead.
write_file <- function(x, file, path = deprecated()) {
if (lifecycle::is_present(path)) {
lifecycle::deprecate_warn("1.4.0", "write_file(path)", "write_file(file)")
file <- path
}
# ... rest of function
}
Renaming an Argument
add_two <- function(x, y, na_rm = TRUE, na.rm = deprecated()) {
if (lifecycle::is_present(na.rm)) {
lifecycle::deprecate_warn("1.0.0", "add_two(na.rm)", "add_two(na_rm)")
na_rm <- na.rm
}
sum(x, y, na.rm = na_rm)
}
Superseding a Function
For functions with better alternatives that shouldn't be removed:
#' Gather columns into key-value pairs
#'
#' @description
#' `r lifecycle::badge("superseded")`
#'
#' Development on `gather()` is complete. For new code, use [pivot_longer()].
#'
#' `df %>% gather("key", "value", x, y, z)` is equivalent to
#' `df %>% pivot_longer(c(x, y, z), names_to = "key", values_to = "value")`.
No warning needed - just document the preferred alternative.
Marking as Experimental
#' @description
#' `r lifecycle::badge("experimental")`
cool_function <- function() {
lifecycle::signal_stage("experimental", "cool_function()")
# ...
}
Testing Deprecations
Test that deprecated functions work and warn appropriately:
test_that("old_fun is deprecated", {
expect_snapshot({
x <- old_fun(1)
expect_equal(x, expected_value)
})
})
Suppress warnings in existing tests:
test_that("old_fun returns correct value", {
withr::local_options(lifecycle_verbosity = "quiet")
expect_equal(old_fun(1), expected_value)
})
Deprecation Helpers
For deprecations affecting many functions (e.g., removing a common argument), create an internal helper:
warn_for_verbose <- function(
verbose = TRUE,
env = rlang::caller_env(),
user_env = rlang::caller_env(2)
) {
if (!lifecycle::is_present(verbose) || isTRUE(verbose)) {
return(invisible())
}
lifecycle::deprecate_warn(
when = "2.0.0",
what = I("The `verbose` argument"),
details = c(
"Set `options(mypkg_quiet = TRUE)` to suppress messages.",
"The `verbose` argument will be removed in a future release."
),
user_env = user_env
)
invisible()
}
Then use in affected functions:
my_function <- function(..., verbose = deprecated()) {
warn_for_verbose(verbose)
# ...
}
Custom Deprecation Messages
For non-standard deprecations, use I() to wrap custom text:
lifecycle::deprecate_warn(
when = "1.0.0",
what = I('Setting option "pkg.opt" to "foo"'),
with = I('"pkg.new_opt"')
)
The what fragment must work with "was deprecated in..." appended.
Reference
See references/lifecycle-stages.md for detailed stage definitions and transitions.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
create-release-checklist
Create a release checklist and GitHub issue for an R package. Use when the user asks to "create a release checklist" or "start a release" for an R package.
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 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.
shiny-bslib-theming
Advanced theming for Shiny apps using bslib and Bootstrap 5. Use when customizing app appearance with bs_theme(), Bootswatch themes, custom colors, typography, brand.yml integration, Bootstrap Sass variables, custom Sass/CSS rules, dark mode and color modes, dynamic theme switching, real-time theming, theme inspection, or making R plots match the app theme with thematic.
shiny-bslib
Build modern Shiny dashboards and applications using bslib (Bootstrap 5). Use when creating new Shiny apps, modernizing legacy apps (fluidPage, fluidRow/column, tabsetPanel, wellPanel, shinythemes), or working with bslib page layouts, grid systems, cards, value boxes, navigation, sidebars, filling layouts, theming, accordions, tooltips, popovers, toasts, or bslib inputs. Assumes familiarity with basic Shiny.
quarto-alt-text
Generate accessible alt text for data visualizations in Quarto documents. Use when the user wants to add, improve, or review alt text for figures in .qmd files. Triggers for requests about accessibility, figure descriptions, fig-alt, screen reader support, or making Quarto documents more accessible.
quarto-authoring
Writing and authoring Quarto documents (.qmd), including code cell options, figure and table captions, cross-references, callout blocks (notes, warnings, tips), citations and bibliography, page layout and columns, Mermaid diagrams, YAML metadata configuration, and Quarto extensions. Also covers converting and migrating R Markdown (.Rmd), bookdown, blogdown, xaringan, and distill projects to Quarto, and creating Quarto websites, books, presentations, and reports.
Didn't find tool you were looking for?