{"slug":"lifecycle","title":"lifecycle","summary":"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) Mar","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-28T19:34:15.976615Z","repo":{"url":"https://github.com/posit-dev/skills","stars":518,"forks":53,"license":"MIT","updatedAt":"2026-09-18T19:30:01Z"},"bodyHtml":"<hr>\n<h2>name: lifecycle\ndescription: \"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.\"\nmetadata:\nauthor: Garrick Aden-Buie (@gadenbuie)\nversion: \"1.1\"\nlicense: MIT</h2>\n<h1>R Package Lifecycle Management</h1>\n<p>Manage function and argument lifecycle using tidyverse conventions and the lifecycle package.</p>\n<h2>Setup</h2>\n<p>Check if lifecycle is configured by looking for <code>lifecycle-*.svg</code> files in <code>man/figures/</code>.</p>\n<p>If not configured, run:</p>\n<pre><code>usethis::use_lifecycle()\n</code></pre>\n<p>This:</p>\n<ul>\n<li>Adds lifecycle to <code>Imports</code> in DESCRIPTION</li>\n<li>Adds <code>@importFrom lifecycle deprecated</code> to the package documentation file</li>\n<li>Copies badge SVGs to <code>man/figures/</code></li>\n</ul>\n<h2>Lifecycle Badges</h2>\n<p>Insert badges in roxygen2 documentation:</p>\n<pre><code>#' @description\n#' `r lifecycle::badge(\"experimental\")`\n#' `r lifecycle::badge(\"deprecated\")`\n#' `r lifecycle::badge(\"superseded\")`\n</code></pre>\n<p>For arguments:</p>\n<pre><code>#' @param old_arg `r lifecycle::badge(\"deprecated\")` Use `new_arg` instead.\n</code></pre>\n<p>Only badge functions/arguments whose stage differs from the package's overall stage.</p>\n<h2>Deprecating a Function</h2>\n<ol>\n<li>Add badge and explanation to <code>@description</code>:</li>\n</ol>\n<pre><code>#' Do something\n#'\n#' @description\n#' `r lifecycle::badge(\"deprecated\")`\n#'\n#' `old_fun()` was deprecated in mypkg 1.0.0. Use [new_fun()] instead.\n#' @keywords internal\n</code></pre>\n<ol start=\"2\">\n<li>Add <code>deprecate_warn()</code> as first line of function body:</li>\n</ol>\n<pre><code>old_fun &lt;- function(x) {\n\nlifecycle::deprecate_warn(\"1.0.0\", \"old_fun()\", \"new_fun()\")\nnew_fun(x)\n}\n</code></pre>\n<ol start=\"3\">\n<li>Show migration in examples:</li>\n</ol>\n<pre><code>#' @examples\n#' old_fun(x)\n#' # -&gt;\n#' new_fun(x)\n</code></pre>\n<h2>Deprecation Functions</h2>\n<table>\n<thead>\n<tr>\n<th>Function</th>\n<th>When to Use</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>deprecate_soft()</code></td>\n<td>First stage; warns only direct users and during tests</td>\n</tr>\n<tr>\n<td><code>deprecate_warn()</code></td>\n<td>Standard deprecation; warns once per 8 hours</td>\n</tr>\n<tr>\n<td><code>deprecate_stop()</code></td>\n<td>Final stage before removal; errors with helpful message</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Deprecation workflow for major releases:</strong></p>\n<ol>\n<li>Search <code>deprecate_stop()</code> - consider removing function entirely</li>\n<li>Replace <code>deprecate_warn()</code> with <code>deprecate_stop()</code></li>\n<li>Replace <code>deprecate_soft()</code> with <code>deprecate_warn()</code></li>\n</ol>\n<h2>Renaming a Function</h2>\n<p>Move implementation to new name, call from old name with deprecation:</p>\n<pre><code>#' @description\n#' `r lifecycle::badge(\"deprecated\")`\n#'\n#' `add_two()` was renamed to `number_add()` for API consistency.\n#' @keywords internal\n#' @export\nadd_two &lt;- function(x, y) {\nlifecycle::deprecate_warn(\"1.0.0\", \"add_two()\", \"number_add()\")\nnumber_add(x, y)\n}\n\n#' Add two numbers\n#' @export\nnumber_add &lt;- function(x, y) {\nx + y\n}\n</code></pre>\n<h2>Deprecating an Argument</h2>\n<p>Use <code>deprecated()</code> as default value with <code>is_present()</code> check:</p>\n<pre><code>#' @param path `r lifecycle::badge(\"deprecated\")` Use `file` instead.\nwrite_file &lt;- function(x, file, path = deprecated()) {\n  if (lifecycle::is_present(path)) {\n    lifecycle::deprecate_warn(\"1.4.0\", \"write_file(path)\", \"write_file(file)\")\n    file &lt;- path\n  }\n  # ... rest of function\n}\n</code></pre>\n<h2>Renaming an Argument</h2>\n<pre><code>add_two &lt;- function(x, y, na_rm = TRUE, na.rm = deprecated()) {\n  if (lifecycle::is_present(na.rm)) {\n    lifecycle::deprecate_warn(\"1.0.0\", \"add_two(na.rm)\", \"add_two(na_rm)\")\n    na_rm &lt;- na.rm\n  }\n  sum(x, y, na.rm = na_rm)\n}\n</code></pre>\n<h2>Superseding a Function</h2>\n<p>For functions with better alternatives that shouldn't be removed:</p>\n<pre><code>#' Gather columns into key-value pairs\n#'\n#' @description\n#' `r lifecycle::badge(\"superseded\")`\n#'\n#' Development on `gather()` is complete. For new code, use [pivot_longer()].\n#'\n#' `df %&gt;% gather(\"key\", \"value\", x, y, z)` is equivalent to\n#' `df %&gt;% pivot_longer(c(x, y, z), names_to = \"key\", values_to = \"value\")`.\n</code></pre>\n<p>No warning needed - just document the preferred alternative.</p>\n<h2>Marking as Experimental</h2>\n<pre><code>#' @description\n#' `r lifecycle::badge(\"experimental\")`\ncool_function &lt;- function() {\n  lifecycle::signal_stage(\"experimental\", \"cool_function()\")\n  # ...\n}\n</code></pre>\n<h2>Testing Deprecations</h2>\n<p>Test that deprecated functions work and warn appropriately:</p>\n<pre><code>test_that(\"old_fun is deprecated\", {\n  expect_snapshot({\n    x &lt;- old_fun(1)\n    expect_equal(x, expected_value)\n  })\n})\n</code></pre>\n<p>Suppress warnings in existing tests:</p>\n<pre><code>test_that(\"old_fun returns correct value\", {\n  withr::local_options(lifecycle_verbosity = \"quiet\")\n  expect_equal(old_fun(1), expected_value)\n})\n</code></pre>\n<h2>Deprecation Helpers</h2>\n<p>For deprecations affecting many functions (e.g., removing a common argument), create an internal helper:</p>\n<pre><code>warn_for_verbose &lt;- function(\n  verbose = TRUE,\n  env = rlang::caller_env(),\n  user_env = rlang::caller_env(2)\n) {\n  if (!lifecycle::is_present(verbose) || isTRUE(verbose)) {\n    return(invisible())\n  }\n\n  lifecycle::deprecate_warn(\n    when = \"2.0.0\",\n    what = I(\"The `verbose` argument\"),\n    details = c(\n      \"Set `options(mypkg_quiet = TRUE)` to suppress messages.\",\n      \"The `verbose` argument will be removed in a future release.\"\n    ),\n    user_env = user_env\n  )\n\n  invisible()\n}\n</code></pre>\n<p>Then use in affected functions:</p>\n<pre><code>my_function &lt;- function(..., verbose = deprecated()) {\n  warn_for_verbose(verbose)\n  # ...\n}\n</code></pre>\n<h2>Custom Deprecation Messages</h2>\n<p>For non-standard deprecations, use <code>I()</code> to wrap custom text:</p>\n<pre><code>lifecycle::deprecate_warn(\n  when = \"1.0.0\",\n  what = I('Setting option \"pkg.opt\" to \"foo\"'),\n  with = I('\"pkg.new_opt\"')\n)\n</code></pre>\n<p>The <code>what</code> fragment must work with \"was deprecated in...\" appended.</p>\n<h2>Reference</h2>\n<p>See <code>references/lifecycle-stages.md</code> for detailed stage definitions and transitions.</p>\n","files":[{"path":"references/lifecycle-stages.md","sizeBytes":2238,"isText":true},{"path":"SKILL.md","sizeBytes":5948,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-08-28T19:34:39.184075Z","sha256":"9651FCDB232B1C765F34D44F22ECE1CC540CB8C99EF6FD6D2A8B90BA5D0C354B","sizeBytes":3555},"review":null,"source":{"repositoryUrl":"https://github.com/posit-dev/skills","path":"r-lib/lifecycle","license":"MIT","commit":"1bb49b8eecba38f04d39c2e6ddb8f8871382fe72","subtreeSha":"63E17C653150B3EB5A22E0F99A3D03A685A6EFBC84FE58826C02A89B6996EDA2","lastSyncedAt":"2026-09-21T13:51:07.177786Z"},"reviewedAt":"2026-08-28T19:35:41.625824Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/posit-dev/skills/tree/main/r-lib/lifecycle"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install posit-dev-skills@llmmart"},{"target":"git","command":"git clone https://github.com/posit-dev/skills.git"}]}