How this skill is triggered — by the user, by Claude, or both
Slash command
/r-package-development:cran-submissionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
---
This skill covers the complete CRAN submission process, from pre-submission preparation through to acceptance and post-release tasks. CRAN (Comprehensive R Archive Network) is the primary repository for R packages and has strict quality requirements.
@returns and @examples documentation\donttest{} sparingly)Every exported function must have:
#' Function Title
#'
#' @description
#' Detailed description of what the function does.
#'
#' @param x Description of parameter x
#' @param y Description of parameter y
#'
#' @returns A data.frame with columns:
#' \item{col1}{Description of column 1}
#' \item{col2}{Description of column 2}
#'
#' @examples
#' # Basic usage
#' result <- my_function(x = 1, y = 2)
#' print(result)
#'
#' # Advanced usage
#' result2 <- my_function(x = 1:10, y = 20)
#'
#' @export
my_function <- function(x, y) {
# implementation
}
Critical: Use @returns (not @return) for consistency with roxygen2 7.0+.
Package: packagename
Title: A Package That Does Amazing Things # Title case, < 65 chars, no period
Version: 0.1.0 # Must be > current CRAN version
Authors@R: c(
person("First", "Last", email = "[email protected]",
role = c("aut", "cre"),
comment = c(ORCID = "0000-0000-0000-0000")),
person("Another", "Author", role = "aut"),
person("Company Name", role = "cph") # Copyright holder
)
Description: Provides tools for amazing analysis. This package implements
novel algorithms and provides intuitive interfaces. Functions include
data processing, visualization, and reporting capabilities.
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.0
URL: https://username.github.io/packagename/, https://github.com/username/packagename
BugReports: https://github.com/username/packagename/issues
Suggests:
testthat (>= 3.0.0),
knitr,
rmarkdown
VignetteBuilder: knitr
Config/testthat/edition: 3
Title field rules:
Description field rules:
For new submissions:
Version: 0.1.0
For updates (must be > CRAN version):
# If CRAN has 0.1.0, use:
Version: 0.1.1 # Bug fixes
Version: 0.2.0 # New features
Version: 1.0.0 # Major release
Development versions (not for CRAN):
Version: 0.1.0.9000 # Development version after 0.1.0
# Standard check
devtools::check()
# Check with remote checking (stricter)
devtools::check(remote = TRUE, manual = TRUE)
# Check with --as-cran flag
devtools::check(args = c('--as-cran'))
# Check on Windows builder (CRAN's Windows server)
devtools::check_win_devel() # R-devel
devtools::check_win_release() # R-release
devtools::check_win_oldrelease() # R-oldrelease
You'll receive an email with results in ~30 minutes.
# Install rhub
install.packages("rhub")
# Validate email first time
rhub::validate_email()
# Check on multiple platforms
rhub::check_for_cran()
# Specific platforms
rhub::check(platform = "windows-x86_64-devel")
rhub::check(platform = "ubuntu-gcc-release")
rhub::check(platform = "macos-highsierra-release-cran")
rhub::check(platform = "solaris-x86-patched")
# List available platforms
rhub::platforms()
Note: R-hub can be unreliable. GitHub Actions with r-lib/actions is often more reliable.
Most reliable multi-platform testing:
# Set up GitHub Actions
usethis::use_github_action("check-standard")
Tests on:
# Check all URLs in documentation and vignettes
urlchecker::url_check()
# Fix or explain any broken URLs
Common issues:
https://doi.org/ not http://dx.doi.org/Create cran-comments.md in package root:
## Test environments
* local R installation, R 4.4.0
* ubuntu 22.04 (on GitHub Actions), R-devel, R-release, R-oldrel-1
* windows-latest (on GitHub Actions), R-release
* macos-latest (on GitHub Actions), R-release
* win-builder (devel and release)
## R CMD check results
0 errors | 0 warnings | 1 note
* This is a new release.
## Downstream dependencies
There are currently no downstream dependencies for this package.
## Test environments
* local R installation, R 4.4.0
* ubuntu 22.04 (on GitHub Actions), R-devel, R-release, R-oldrel-1
* windows-latest (on GitHub Actions), R-release
* macos-latest (on GitHub Actions), R-release
## R CMD check results
0 errors | 0 warnings | 0 notes
## What's changed
This is a minor release that fixes bugs and adds new features:
* Fixed issue with X (#123)
* Added new function Y
* Improved documentation for Z
## Downstream dependencies
I have run R CMD check on downstream dependencies of my package.
All packages passed.
## R CMD check results
0 errors | 0 warnings | 1 note
* Checking CRAN incoming feasibility ... NOTE
Maintainer: 'First Last <[email protected]>'
New submission
Possibly misspelled words in DESCRIPTION:
MCMC (3:49)
PyMC (9:31)
These are not misspelled:
* MCMC is a standard acronym for Markov Chain Monte Carlo
* PyMC is the name of a Python library
# 1. Final checks
devtools::check()
devtools::check_win_devel()
rhub::check_for_cran()
urlchecker::url_check()
# 2. Build the package
devtools::build()
# 3. Submit to CRAN
devtools::submit_cran()
# This will:
# - Build the package
# - Run R CMD check
# - Ask for confirmation
# - Submit to CRAN via web form
If submit_cran() doesn't work:
devtools::build()You'll receive an email asking to confirm submission:
Typical timeline: 1-2 weeks, but can be longer during busy periods.
Problem:
checking R code for possible problems ... NOTE
my_function: no visible binding for global variable 'x'
my_function: no visible binding for global variable 'y'
Cause: Using NSE (non-standard evaluation) with dplyr, data.table, etc.
Solution:
# In R/globals.R
utils::globalVariables(c("x", "y", "z"))
# Or use .data pronoun
library(dplyr)
my_function <- function(df) {
df %>%
mutate(z = .data$x + .data$y)
}
Problem:
checking dependencies in R code ... NOTE
Namespace in Imports field not imported from: 'package'
Solution: Remove from DESCRIPTION or use somewhere:
#' @importFrom package function
Problem:
checking R files for non-ASCII characters ... NOTE
Solution: Use Unicode escapes:
# Bad
"Müller"
# Good
"M\u00fcller"
Problem:
checking examples ... ERROR
Solution: Wrap problematic examples:
#' @examples
#' # Basic example (always runs)
#' result <- my_function(x = 1)
#'
#' \donttest{
#' # Slow example (skipped on CRAN)
#' slow_result <- slow_function(x = 1:1000000)
#' }
#'
#' \dontrun{
#' # Requires authentication (never runs)
#' api_result <- call_api(key = "your-key")
#' }
Rules:
\donttest{}: Runs locally and on CI, skipped on CRAN (for slow examples)\dontrun{}: Never runs automatically (for examples needing setup)Problem:
checking dependencies in R code ... WARNING
'::' or ':::' imports not declared from:
'package'
Solution: Add to DESCRIPTION Imports and use:
#' @importFrom package function
Or declare in NAMESPACE:
importFrom(package, function)
Problem:
checking PDF version of manual ... WARNING
Solution: Fix .Rd formatting issues or use:
# In GitHub Actions
build_args: 'c("--no-manual")'
Problem:
checking re-building of vignette outputs ... WARNING
Solution: Ensure vignettes build:
devtools::build_vignettes()
# Check for missing packages in Suggests
Problem:
checking file modes ... NOTE
Solution: Fix permissions:
chmod 644 R/*.R
chmod 644 man/*.Rd
chmod 755 configure
Problem:
checking installed package size ... NOTE
installed size is X Mb
sub-directories of 1Mb or more:
data Y Mb
Solution:
tools::resaveRdaFiles("data")LazyData: true in DESCRIPTIONProblem: Package writes to home directory or modifies environment
Solution: Use temporary directories:
# Bad
write.csv(data, "~/mypackage/output.csv")
# Good
tmpdir <- tempdir()
write.csv(data, file.path(tmpdir, "output.csv"))
# For configuration
config_dir <- tools::R_user_dir("mypackage", which = "config")
if (!dir.exists(config_dir)) {
dir.create(config_dir, recursive = TRUE)
}
11. Suggested packages not declared:
# Conditional usage
if (requireNamespace("ggplot2", quietly = TRUE)) {
# Use ggplot2
} else {
message("Install ggplot2 for better plots")
}
12. Internet resources without checks:
# Check connectivity
check_connection <- function(url) {
tryCatch({
httr::GET(url, httr::timeout(5))
TRUE
}, error = function(e) {
message("Cannot connect to ", url)
FALSE
})
}
13. Testing failures:
# Skip tests on CRAN if they require internet/auth
testthat::skip_on_cran()
testthat::skip_if_offline()
14. Long-running tests:
# In tests/testthat.R
Sys.setenv("NOT_CRAN" = "true")
# In test files
testthat::skip_on_cran() # Skip slow tests
15. Missing LICENSE file:
# For MIT license
usethis::use_mit_license()
# Creates LICENSE and LICENSE.md
16. Undeclared S3 methods:
#' @export
print.myclass <- function(x, ...) {
# implementation
}
# In NAMESPACE (auto-generated by roxygen2)
S3method(print, myclass)
17. Examples too long:
\donttest{}18. Rd cross-references broken:
#' @seealso \code{\link{other_function}}
#' @seealso \code{\link[otherpackage]{their_function}}
19. Non-standard installation:
configure script for system dependencies20. Archived dependencies:
21. Data documentation missing:
#' Dataset Title
#'
#' @description Description of dataset
#'
#' @format A data frame with 100 rows and 5 variables:
#' \describe{
#' \item{var1}{Description of var1}
#' \item{var2}{Description of var2}
#' }
#' @source \url{https://example.com/data}
"dataset_name"
22. NAMESPACE conflicts:
# Don't export everything
#' @keywords internal
internal_function <- function() {}
23. Windows path issues:
# Use file.path() not paste
file.path("dir", "file.txt") # Good
# Not: paste("dir", "file.txt", sep = "/") # Bad
24. Encoding issues: Add to DESCRIPTION:
Encoding: UTF-8
25. Undeclared attachments:
# Don't use library() in package code
# Use :: or importFrom instead
dplyr::filter() # Good
# Not: library(dplyr); filter() # Bad
26. Examples with \dontrun only:
\donttest{} instead of \dontrun{} when possible27. Biased package names:
28. Missing return values:
#' @returns A numeric vector of length n
#' @returns NULL (invisibly) if no output
29. Improper TRUE/FALSE:
# Use TRUE/FALSE, not T/F
if (condition == TRUE) # Good
# Not: if (condition == T) # Bad
30. Unconventional directory structure:
31-40: Platform-specific code, parallel processing issues, memory leaks, C/C++ code problems, Fortran code issues, Java dependencies, system command calls, graphic device problems, locale-specific code, timezone issues
41-50: Partial argument matching, 1:length() issues, sapply() problems, dependency version constraints, circular dependencies, namespace pollution, documentation warnings, alias issues, keyword problems, cross-reference errors
If rejected, you'll get an email with issues. Fix them and resubmit:
## Resubmission
This is a resubmission. In this version I have:
* Fixed the DESCRIPTION title to be in title case
* Added \value sections to all exported functions
* Ensured all examples run without errors
* Fixed the NOTE about global variables by using utils::globalVariables()
## Test environments
...
Important:
After rejection, bump patch version:
# First submission
Version: 0.1.0
# After rejection
Version: 0.1.0 # Keep same version if resubmitting same release
# Or bump if making significant changes
Version: 0.1.1
If your package has downstream dependencies (packages that depend on yours):
# Install revdepcheck
install.packages("revdepcheck")
# Check reverse dependencies
revdepcheck::revdep_check(num_workers = 4)
# View results
revdepcheck::revdep_report()
# If issues found, contact maintainers
# 1. Create GitHub release
usethis::use_github_release()
# 2. Bump to development version
usethis::use_dev_version()
# This changes:
# Version: 0.1.0 -> Version: 0.1.0.9000
Check CRAN check results daily:
https://cran.r-project.org/web/checks/check_results_PACKAGENAME.html
Fix any issues that arise on CRAN's servers.
Problem: Package has warnings but submitter thinks they're acceptable
Fix: CRAN will auto-reject. Fix ALL warnings before submission.
Problem: Package works on Mac/Linux but fails on Windows
Fix: Use check_win_devel() and GitHub Actions before submission.
Problem: Examples assume files/data/authentication exist
Fix: Examples must be self-contained or use \dontrun{}.
Problem: Wait too long to respond to CRAN
Fix: Respond within 2 weeks or submission is archived.
Problem: Trying to argue that a NOTE is acceptable
Fix: Either fix it or provide a clear, technical explanation in cran-comments.md.
Problem: Missing @returns or @examples
Fix: Every exported function needs both.
Problem: Trying to submit 0.1.0 when CRAN has 0.1.0
Fix: Bump version to 0.1.1 or higher.
Problem: Package is 10+ MB
Fix: Compress data, use external data, or justify in cran-comments.md.
Problem: Importing 20+ packages
Fix: Consider if all are necessary. Each import is a dependency burden.
Problem: Violating policies unknowingly
Fix: Read https://cran.r-project.org/web/packages/policies.html
devtools::check() shows 0 errors, 0 warnings, 0 notes (or explained)check_win_devel() passesrhub::check_for_cran() or GitHub Actions passes@returns and @examplesurlchecker::url_check() passesGood luck with your CRAN submission!
npx claudepluginhub choxos/rpkgagent --plugin r-package-developmentComplete procedure for submitting an R package to CRAN, including pre-submission checks (local, win-builder, R-hub), cran-comments.md preparation, URL and spell checking, and the submission itself. Covers first submissions and updates. Use when a package is ready for initial CRAN release, when submitting an updated version of an existing CRAN package, or when re-submitting after receiving CRAN reviewer feedback.
R package development guide covering dependencies, API design, testing, and documentation. Use when developing R packages.
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.