Skip to main content
ClaudeWave
Skill396 repo starsupdated yesterday

r-cli-app

Rapp is an R package that transforms R scripts into command-line applications by automatically parsing top-level variable assignments into CLI arguments, options, and subcommands. Use this skill when building standalone CLI tools in R, adding argument parsing to existing scripts, shipping command-line utilities within R packages, or creating shebang scripts and subcommand-based tools without writing boilerplate argument-parsing code.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/posit-dev/skills /tmp/r-cli-app && cp -r /tmp/r-cli-app/r-lib/r-cli-app ~/.claude/skills/r-cli-app
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Building CLI Apps with Rapp

Rapp (v0.3.0) is an R package that provides a drop-in replacement for `Rscript`
that automatically parses command-line arguments into R values. It turns simple
R scripts into polished CLI apps with argument parsing, help text, and subcommand
support — with zero boilerplate.

**R ≥ 4.1.0** | **CRAN:** `install.packages("Rapp")` | **GitHub:** `r-lib/Rapp`

After installing, put the `Rapp` launcher on PATH:

```r
Rapp::install_pkg_cli_apps("Rapp")
```

This places the `Rapp` executable in `~/.local/bin` (macOS/Linux) or
`%LOCALAPPDATA%\Programs\R\Rapp\bin` (Windows).

---

## Core Concept: Scripts Are the Spec

Rapp scans **top-level expressions** of an R script and converts specific
patterns into CLI constructs. This means:

1. The same script works identically via `source()` and as a CLI tool.
2. You write normal R code — Rapp infers the CLI from what you write.
3. Default values in your R code become the CLI defaults.

Only top-level assignments are recognized. Assignments inside functions,
loops, or conditionals are not parsed as CLI arguments.

---

## Pattern Recognition: R → CLI Mapping

This table is the heart of Rapp — each R pattern automatically maps to a
CLI surface:

| R Top-Level Expression | CLI Surface | Notes |
|---|---|---|
| `foo <- "text"` | `--foo <value>` | String option |
| `foo <- 1L` | `--foo <int>` | Integer option |
| `foo <- 3.14` | `--foo <float>` | Float option |
| `foo <- TRUE` / `FALSE` | `--foo` / `--no-foo` | Boolean toggle |
| `foo <- NA_integer_` | `--foo <int>` | Optional integer (NA = not set) |
| `foo <- NA_character_` | `--foo <str>` | Optional string (NA = not set) |
| `foo <- NULL` | positional arg | Required by default |
| `foo... <- NULL` | variadic positional | Zero or more values |
| `foo <- c()` | repeatable `--foo` | Multiple values as strings |
| `foo <- list()` | repeatable `--foo` | Multiple values parsed as YAML/JSON |
| `switch("", cmd1={}, cmd2={})` | subcommands | `app cmd1`, `app cmd2` |
| `switch(cmd <- "", ...)` | subcommands | Same; captures command name in `cmd` |

### Type behavior

- **Non-string scalars** are parsed as YAML/JSON at the CLI and coerced to the
  R type of the default. `n <- 5L` means `--n 10` gives integer `10L`.
- **NA defaults** signal optional arguments. Test with `!is.na(myvar)`.
- **Snake case** variable names map to kebab-case: `n_flips` → `--n-flips`.
- **Positional args** always arrive as character strings — convert manually.

---

## Script Structure

### Shebang line

```r
#!/usr/bin/env Rapp
```

Makes the script directly executable on macOS/Linux after `chmod +x`.
On Windows, call `Rapp myscript.R` explicitly.

### Front matter metadata

Hash-pipe comments (`#|`) before any code set script-level metadata:

```r
#!/usr/bin/env Rapp
#| name: my-app
#| title: My App
#| description: |
#|   A short description of what this app does.
#|   Can span multiple lines using YAML block scalar `|`.
```

The `name:` field sets the app name in help output (defaults to filename).

### Per-argument annotations

Place `#|` comments immediately before the assignment they annotate:

```r
#| description: Number of coin flips
#| short: 'n'
flips <- 1L
```

Available annotation fields:

| Field | Purpose |
|---|---|
| `description:` | Help text shown in `--help` |
| `title:` | Display title (for subcommands and front matter) |
| `short:` | Single-letter alias, e.g. `'n'` → `-n` |
| `required:` | `true`/`false` — for positional args only |
| `val_type:` | Override type: `string`, `integer`, `float`, `bool`, `any` |
| `arg_type:` | Override CLI type: `option`, `switch`, `positional` |
| `action:` | For repeatable options: `replace` or `append` |

Add `#| short:` for frequently-used options — users expect single-letter
shortcuts for common flags like verbose (`-v`), output (`-o`), or count (`-n`).

---

## Named Options

Scalar literal assignments become named options:

```r
name <- "world"          # --name <value>    (string, default "world")
count <- 1L              # --count <int>     (integer, default 1)
threshold <- 0.5         # --threshold <flt> (float, default 0.5)
seed <- NA_integer_      # --seed <int>      (optional, NA if omitted)
output <- NA_character_  # --output <str>    (optional, NA if omitted)
```

For optional arguments, test whether the user supplied them:

```r
seed <- NA_integer_
if (!is.na(seed)) set.seed(seed)
```

## Boolean Switches

`TRUE`/`FALSE` assignments become toggles:

```r
verbose <- FALSE   # --verbose or --no-verbose
wrap <- TRUE       # --wrap (default) or --no-wrap
```

Values `yes`/`true`/`1` set TRUE; `no`/`false`/`0` set FALSE.

## Repeatable Options

```r
pattern <- c()     # --pattern '*.csv' --pattern 'sales-*'  → character vector
threshold <- list() # --threshold 5 --threshold '[10,20]'   → list of parsed values
```

## Positional Arguments

Assign `NULL` for positional args (required by default):

```r
#| description: The input file to process.
input_file <- NULL
```

Make optional with `#| required: false`. Test with `is.null(myvar)`.

### Variadic positional args

Use `...` suffix to collect multiple positional values:

```r
pkgs... <- c()
# install-pkgs dplyr ggplot2 tidyr → pkgs... = c("dplyr", "ggplot2", "tidyr")
```

---

## Subcommands

Use `switch()` with a string first argument to declare subcommands.
Options before the `switch()` are global; options inside branches are
local to that subcommand.

```r
switch(
  command <- "",

  #| title: Display the todos
  list = {
    #| description: Max entries to display (-1 for all).
    limit <- 30L
    # ... list implementation
  },

  #| title: Add a new todo
  add = {
    #| description: Task description to add.
    task <- NULL
    # ... add implementation
  },

  #| title: Mark a task as completed
  done = {
    #| description: Index of the task to complete.
    index <- 1L
    # ... done implementation
  }
)
```

Help is scoped: `myapp --help` lists commands; `myapp list --help` shows
list-spec
alt-textSkill

>

brand-ymlSkill

Create and use brand.yml files for consistent branding across Shiny apps and Quarto documents. Covers: (1) Creating new _brand.yml files, (2) Applying to Shiny (R and Python), (3) Using in Quarto, (4) Modifying existing files, and (5) Troubleshooting. Includes complete specifications and integration guides.

ggsqlSkill

Write ggsql queries — a grammar of graphics for SQL. Use when the user wants to create, modify, or understand a ggsql visualization query.

pr-createSkill

Creates a pull request from current changes, monitors GitHub CI, and debugs any failures until CI passes. Activate when the user says "create pr", "make a pr", "open pull request", "submit pr", "pr for these changes", or wants to get their current work into a reviewable PR. Assumes the project uses git, is hosted on GitHub, and has GitHub Actions CI with automated checks (lint, build, tests, etc.). Does NOT merge - stops when CI passes and provides the PR link.

pr-threads-addressSkill

Address PR review feedback by systematically working through every unresolved PR review thread on the current branch's PR - analyze each comment, make the requested code changes (with tests where useful), commit, and optionally reply and resolve.

pr-threads-resolveSkill

Bulk resolve unresolved PR review threads on the current branch’s PR — typically after threads have been addressed manually or via /pr-threads-address

create-release-checklistSkill

>

maintainer-declineSkill

Guide for drafting issue closure and decline responses as an open-source package maintainer. Use when helping compose a reply that says \"no\" to a feature request, closes an issue as won't-fix, redirects a user to a different package, explains why a design choice is intentional, or otherwise declines or closes a community contribution. Also use when the maintainer needs to explain a deprecation, point out a user misunderstanding, or communicate an effort/scope tradeoff to a contributor.