How to use
- Copy the installation command and review the source package before installing it in your own agent environment.
- Check the source document for required tools, credentials and supported hosts.
- Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/posit-dev/skills --skill r-cliBefore you start
- Installation does not include a model subscription, API allowance or permission to access your files.
- Repository stars and installation counts describe activity, not an independent quality or security test.
Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.
CLI for R Packages
When to Use What
task: Display error with context and formatting use: cli_abort() with inline markup and bullet lists
task: Show warning with formatting use: cli_warn() with inline markup
task: Display informative message use: cli_inform() with inline markup
task: Show progress for counted operations use: cli_progress_bar() with total count
task: Show simple progress steps use: cli_progress_step() with status messages
task: Format code or function names use: {.code ...} or {.fn package::function}
task: Format file paths use: {.file path/to/file}
task: Format package names use: {.pkg packagename}
task: Format variable names use: {.var variable_name}
task: Format values use: {.val value}
task: Handle singular/plural text use: {?s} or {?y/ies} with pluralization
task: Create headers use: cli_h1(), cli_h2(), cli_h3()
task: Create alerts use: cli_alert_success(), cli_alert_danger(), cli_alert_warning(), cli_alert_info()
task: Create lists use: cli_ul(), cli_ol(), cli_dl() with cli_li()
Inline Markup Essentials
Use inline markup with {.class content} syntax to format text:
# Basic formatting
cli_text("Function {.fn mean} calculates averages")
cli_text("Install package {.pkg dplyr}")
cli_text("See file {.file ~/.Rprofile}")
cli_text("{.var x} must be numeric, not {.obj_type_of {x}}")
cli_text("Got value {.val {x}}")
# Code formatting
cli_text("Use {.code sum(x, na.rm = TRUE)}")
# Paths and arguments
cli_text("Reading from {.path /data/file.csv}")
cli_text("Set {.arg na.rm} to TRUE")
# Types and classes
cli_text("Object is {.cls data.frame}")
# Emphasis
cli_text("This is {.emph important}")
cli_text("This is {.strong critical}")
# Fields
cli_text("The {.field name} field is required")Vector Collapsing
Vectors are automatically collapsed with commas and "and":
pkgs <- c("dplyr", "tidyr", "ggplot2")
cli_text("Installing packages: {.pkg {pkgs}}")
#> Installing packages: dplyr, tidyr, and ggplot2
files <- c("data.csv", "script.R")
cli_text("Found {length(files)} file{?s}: {.file {files}}")
#> Found 2 files: data.csv and script.REscaping Braces
Use double braces {{ and }} to escape literal braces:
cli_text("Use {{variable}} syntax in glue")
#> Use {variable} syntax in glueFor complete markup reference: See references/inline-markup.md for all 50+ inline classes, edge cases, nesting rules, and advanced patterns.
Pluralization Basics
Use {?} for pluralization with three patterns:
Single Alternative
nfile <- 1
cli_text("Found {nfile} file{?s}")
#> Found 1 file
nfile <- 3
cli_text("Found {nfile} file{?s}")
#> Found 3 filesTwo Alternatives
ndir <- 1
cli_text("Found {ndir} director{?y/ies}")
#> Found 1 directory
ndir <- 5
cli_text("Found {ndir} director{?y/ies}")
#> Found 5 directoriesThree Alternatives (zero/one/many)
nfile <- 0
cli_text("Found {nfile} file{?s}: {?no/the/the} file{?s}")
#> Found 0 files: no files
nfile <- 1
cli_text("Found {nfile} file{?s}: {?no/the/the} file{?s}")
#> Found 1 file: the file
nfile <- 3
cli_text("Found {nfile} file{?s}: {?no/the/the} file{?s}")
#> Found 3 files: the filesHelpers: qty() and no()
Use no() to display "no" instead of zero:
nfile <- 0
cli_text("Found {no(nfile)} file{?s}")
#> Found no filesUse qty() to set quantity explicitly:
nupd <- 3
ntotal <- 10
cli_text("{nupd}/{ntotal} {qty(nupd)} file{?s} {?needs/need} updates")
#> 3/10 files need updatesFor advanced pluralization: See references/inline-markup.md for edge cases and complex patterns.
CLI Conditions: Core Patterns
Use cli conditions instead of base R for better formatting:
cli_abort() - Formatted Errors
# Before (base R)
stop("File not found: ", path)
# After (cli)
cli_abort("File {.file {path}} not found")
# With bullets for context
check_file <- function(path) {
if (!file.exists(path)) {
cli_abort(c(
"File not found",
"x" = "Cannot read {.file {path}}",
"i" = "Check that the file exists"
))
}
}cli_warn() - Formatted Warnings
# Before (base R)
warning("Column ", col, " has missing values")
# After (cli)
cli_warn("Column {.field {col}} has missing values")
# With context
cli_warn(c(
"Data quality issues detected",
"!" = "Column {.field {col}} has {n_missing} missing value{?s}",
"i" = "Consider using {.fn tidyr::drop_na}"
))cli_inform() - Formatted Messages
# Before (base R)
message("Processing ", n, " files")
# After (cli)
cli_inform("Processing {n} file{?s}")
# With structure
cli_inform(c(
"v" = "Successfully loaded {.pkg dplyr}",
"i" = "Version {packageVersion('dplyr')}"
))Bullet Types
"x"- Error/problem (red X)"!"- Warning (yellow !)"i"- Information (blue i)"v"- Success (green checkmark)"*"- Bullet point">"- Arrow/pointer
For advanced error design: See references/conditions.md for error design principles, rlang integration, testing strategies, and real-world patterns.
Basic Progress Indicators
Simple Progress Steps
process_data <- function() {
cli_progress_step("Loading data")
data <- load_data()
cli_progress_step("Cleaning data")
clean <- clean_data(data)
cli_progress_step("Analyzing data")
analyze(clean)
}Basic Progress Bar
process_files <- function(files) {
cli_progress_bar("Processing files", total = length(files))
for (file in files) {
process_file(file)
cli_progress_update()
}
}Auto-Cleanup
Progress bars auto-close when the function exits:
process <- function() {
cli_progress_bar("Working", total = 100)
for (i in 1:100) {
Sys.sleep(0.01)
cli_progress_update()
}
# No need to call cli_progress_done() - auto-closes
}For advanced progress: See references/progress.md for nested progress, custom formats, parallel processing, all progress variables, and Shiny integration.
Semantic CLI Elements
Headers
cli_h1("Main Section")
cli_h2("Subsection")
cli_h3("Detail")Alerts
cli_alert_success("Operation completed successfully")
cli_alert_danger("Critical error occurred")
cli_alert_warning("Potential issue detected")
cli_alert_info("Additional information available")Text and Code
# Regular text with markup
cli_text("This is formatted text with {.emph emphasis}")
# Code blocks
cli_code(c(
"library(dplyr)",
"mtcars %>% filter(mpg > 20)"
))
# Verbatim text (no formatting)
cli_verbatim("This is displayed exactly as-is: {not interpolated}")Lists
# Unordered list
cli_ul()
cli_li("First item")
cli_li("Second item")
cli_end()
# Ordered list
cli_ol()
cli_li("First step")
cli_li("Second step")
cli_end()
# Definition list
cli_dl()
cli_li(c(name = "The name field"))
cli_li(c(email = "The email address"))
cli_end()Common Workflows
Base R to CLI Migration
# Before: Base R error handling
validate_input <- function(x, y) {
if (!is.numeric(x)) {
stop("x must be numeric")
}
if (length(y) == 0) {
stop("y cannot be empty")
}
if (length(x) != length(y)) {
stop("x and y must have the same length")
}
}
# After: CLI error handling
validate_input <- function(x, y) {
if (!is.numeric(x)) {
cli_abort(c(
"{.arg x} must be numeric",
"x" = "You supplied a {.cls {class(x)}} vector",
"i" = "Use {.fn as.numeric} to convert"
))
}
if (length(y) == 0) {
cli_abort(c(
"{.arg y} cannot be empty",
"i" = "Provide at least one element"
))
}
if (length(x) != length(y)) {
cli_abort(c(
"{.arg x} and {.arg y} must have the same length",
"x" = "{.arg x} has length {length(x)}",
"x" = "{.arg y} has length {length(y)}"
))
}
}Error Message with Rich Context
check_required_columns <- function(data, required_cols) {
actual_cols <- names(data)
missing_cols <- setdiff(required_cols, actual_cols)
if (length(missing_cols) > 0) {
cli_abort(c(
"Required column{?s} missing from data",
"x" = "Missing {length(missing_cols)} column{?s}: {.field {missing_cols}}",
"i" = "Data has {length(actual_cols)} column{?s}: {.field {actual_cols}}",
"i" = "Add the missing column{?s} or check for typos"
))
}
invisible(data)
}Function with Progress Bar
process_files <- function(files, verbose = TRUE) {
n <- length(files)
if (verbose) {
cli_progress_bar(
format = "Processing {cli::pb_bar} {cli::pb_current}/{cli::pb_total} [{cli::pb_eta}]",
total = n
)
}
results <- vector("list", n)
for (i in seq_along(files)) {
results[[i]] <- process_file(files[[i]])
if (verbose) {
cli_progress_update()
}
}
results
}Resources & Advanced Topics
Reference Files
- [references/inline-markup.md](references/inline-markup.md) - Complete catalog of inline classes organized by category, advanced patterns, nesting rules, and real-world examples
- [references/conditions.md](references/conditions.md) - Advanced error design patterns, rlang integration, testing with testthat snapshots, migration guide, and anti-patterns
- [references/progress.md](references/progress.md) - Nested progress bars, custom formats, all progress variables, parallel processing, Shiny integration, and debugging
- [references/themes.md](references/themes.md) - Complete theming system with CSS-like selectors, container functions, color palettes, custom themes, and accessibility
- [references/ansi-operations.md](references/ansi-operations.md) - ANSI string operations (align, columns, nchar, etc.), hyperlinks, color detection, testing CLI output, and troubleshooting
External Resources
Related Packages
- rlang - Condition handling and error objects integrate with cli
- glue - String interpolation powers cli's
{}syntax - testthat - Snapshot testing for cli output




