К основному содержанию
скилл CX Codex

r-cli-app — скилл для Claude Code: CLI-приложения на R через Rapp

Помогает агенту собрать консольную утилиту на R: разбор аргументов, справка и подкоманды берутся из самого скрипта.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add posit-dev/skills --skill r-cli-app -a claude-code
Открыть на GitHub

Что делает r-cli-app

Скилл учит агента писать CLI-приложения на R с пакетом Rapp — это замена Rscript, которая сама превращает аргументы командной строки в значения R. Отдельный парсер подключать не нужно: Rapp читает выражения верхнего уровня в скрипте и по ним строит интерфейс. Присвоение строки даёт опцию --foo <value>, целого числа — --foo <int>, TRUE/FALSE — переключатель --foo и --no-foo, а NULL — позиционный аргумент. Имена в snake_case становятся kebab-case: n_flips превращается в --n-flips.

Справка тоже выводится из кода. Комментарии #| перед присвоением задают описание аргумента, короткий однобуквенный алиас и признак обязательности, а switch() с первым строковым аргументом объявляет подкоманды. Каждое приложение получает --help и --help-yaml, причём у подкоманд справка своя. Отлаживать удобно через Rapp::run(), не выходя из сессии R.

Понадобится R версии 4.1.0 или новее. Пакет ставится из CRAN командой install.packages("Rapp"), после чего лаунчер нужно положить в PATH вызовом Rapp::install_pkg_cli_apps("Rapp") — без этого шага #!/usr/bin/env Rapp в шебанге не сработает. Учтите: Rapp разбирает только присвоения верхнего уровня, поэтому аргумент, объявленный внутри функции или цикла, в CLI не попадёт.

Какие задачи решает

  • добавить разбор аргументов в готовый R-скрипт
  • превратить скрипт в исполняемую утилиту с шебангом
  • собрать CLI с подкомандами вида add, list, done
  • вывести справку по аргументам без ручного парсера
  • положить консольные приложения в exec/ внутри R-пакета

Примеры запросов агенту

  • Сделай из analyze.R CLI-приложение на Rapp: входной файл позиционным аргументом, опция --n-flips целым числом
  • Добавь в скрипт подкоманды list и add через switch() и опиши их в #|-комментариях
  • Проверь приложение через Rapp::run() с аргументами --help и --name Alice

Как установить r-cli-app

1Через Skills CLI (Vercel)

npx skills add posit-dev/skills --skill r-cli-app -a claude-code

2Вручную: положить файлы

~/.claude/skills/r-cli-app/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/r-cli-app/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора18

describe-design Скилл исследует кодовую базу и пишет markdown-документ о том, как устроена фича или система. Пригодится для онбординга и передачи знаний. CX Codex +1 785установок shiny-bslib-theming Скилл для оформления Shiny-приложений через bslib и Bootstrap 5: пресеты, цвета, шрифты, тёмный режим и живую подстройку темы. CX Codex +1 746установок create-release-checklist Скилл формирует чеклист подготовки релиза для R-пакета и заводит под него issue в GitHub. Пригодится мейнтейнерам перед публикацией новой версии. CX Codex +1 704установок release-post Пишет блог-пост о выпуске R или Python пакета по правилам блогов Tidyverse и Shiny. Пригодится, когда NEWS.md уже есть, а текста для сайта нет. CX Codex +1 684установок pr-threads-resolve Скилл закрывает все незакрытые треды ревью в PR текущей ветки одной командой. Пригодится, когда правки уже внесены и осталось только снять статус «unresolved». CX Codex +1 668установок pr-threads-address Скилл находит все неразрешённые треды ревью в пулреквесте текущей ветки, вносит правки в код с тестами и помогает ответить рецензенту. CX Codex +1 666установок alt-text Пишет и правит alt-текст для графиков и картинок в R-пакетах и документах Quarto. Пригодится, когда фигуры на сайте pkgdown или в .qmd остаются без описания. CX Codex +1 587установок ggsql Помогает агенту писать и править запросы ggsql, где SQL и описание графика живут в одном синтаксисе. Пригодится, когда нужно построить визуализацию прямо из таблицы или CSV. CX Codex +1 522установок

Похожие

cli-developer https://github.com/Jeffallan Скилл для разработки командной строки: помогает строить CLI-инструменты с парсингом флагов, интерактивными подсказками, прогресс-барами и автодополнением в bash/zsh/fish. Работает с commander, click, typer и cobra. CX Codex +1 4 800установок dart-build-cli-app dart-lang Скилл для разработки command-line приложений на Dart. Даёт паттерны архитектуры, структуру точки входа, коды выхода, маршрутизацию потоков и запуск подпроцессов. CX Codex +1 18 000установок angular-new-app Angular Team @ Google Скилл для быстрого создания нового Angular-приложения с помощью Angular CLI. Проверяет окружение, генерирует проект с нужными флагами и направляет разработку по лучшим практикам Angular. CX Codex +1 19 200установок create-slack-app slackapi Проведёт от проверки Slack CLI до запуска нового Bolt-приложения локально. Пригодится, когда нужно поднять бота или агента с нуля. CX Codex +1 446установок platform-lightning-app-coordinate forcedotcom Создаёт развёртываемые приложения Salesforce Lightning Experience из текстового описания. Нужен, когда требуется связать несколько типов метаданных в одном приложении. CX Codex +1 5 600установок build-zoom-team-chat-app официальный anthropics Справочный скилл для разработки интеграций с Zoom Team Chat: ботов, интерактивных карточек, слэш-команд и отправки сообщений от имени пользователя. CX Codex +1 2 100установок

Рядом в теме «Языки программирования»

Все скиллы по теме «Языки программирования» →

Вопросы о r-cli-app

Как установить r-cli-app в Claude?

Выполните npx skills add posit-dev/skills --skill r-cli-app -a claude-code. Скилл окажется в ~/.claude/skills/r-cli-app/SKILL.md.

Что делает скилл r-cli-app?

Помогает агенту писать консольные приложения на R с пакетом Rapp: разбор аргументов, справка и подкоманды выводятся из кода скрипта.

Что нужно для работы Rapp?

R 4.1.0 или новее и сам пакет: install.packages("Rapp"). Затем лаунчер ставится в PATH через Rapp::install_pkg_cli_apps("Rapp").

Исходный текст

SKILL.md · MIT
---
name: r-cli-app
description: Build command-line apps in R using the Rapp package. Use when creating a CLI tool in R, adding argument parsing to an R script, turning an R script into a command-line app, shipping CLIs in an R package, or using Rapp (the alternative Rscript front-end). Also use for shebang scripts, exec/ directory in R packages, or subcommand-based R tools.
metadata:
  author: Garrick Aden-Buie (@gadenbuie)
  version: "1.1"
license: MIT
---

# 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-specific options plus globals. Subcommands can nest by placing another
`switch()` inside a branch.

---

## Built-in Help

Every Rapp automatically gets `--help` (human-readable) and `--help-yaml`
(machine-readable). These work with subcommands too.

---

## Development and Testing

### Interactive Development

Use `Rapp::run()` to test scripts from an R session:

```r
Rapp::run("path/to/myapp.R", c("--help"))
Rapp::run("path/to/myapp.R", c("--name", "Alice", "--count", "5"))
```

It returns the evaluation environment (invisibly) for inspection, and
supports `browser()` for interactive debugging.

### Testing CLI Apps in Packages

Use `Rapp::run()` with `testthat` snapshot testing. Test computed values by
accessing the returned environment, and test output with `expect_snapshot()`.

**See [references/advanced.md](references/advanced.md#testing-cli-apps)** for
detailed testing patterns, including:

- Accessing computed values via the evaluation environment
- Snapshot testing for help output and formatted text
- Testing file side effects and state changes

---

## Complete Example: Coin Flipper

```r
#!/usr/bin/env Rapp
#| name: flip-coin
#| description: |
#|   Flip a coin.

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

sep <- " "
wrap <- TRUE

seed <- NA_integer_
if (!is.na(seed)) {
  set.seed(seed)
}

cat(sample(c("heads", "tails"), flips, TRUE), sep = sep, fill = wrap)
```

```sh
flip-coin            # heads
flip-coin -n 3       # heads tails heads
flip-coin --seed 42 -n 5
flip-coin --help
```

Generated help:
```
Usage: flip-coin [OPTIONS]

Flip a coin.

Options:
  -n, --flips <FLIPS>  Number of coin flips [default: 1] [type: integer]
      --sep <SEP>      [default: " "] [type: string]
      --wrap / --no-wrap  [default: true]
      --seed <SEED>    [default: NA] [type: integer]
```

## Complete Example: Todo Manager (Subcommands)

```r
#!/usr/bin/env Rapp
#| name: todo
#| description: Manage a simple todo list.

#| description: Path to the todo list file.
#| short: s
store <- ".todo.yml"

switch(
  command <- "",

  list = {
    #| description: Max entries to display (-1 for all).
    limit <- 30L

    tasks <- if (file.exists(store)) yaml::read_yaml(store) else list()
    if (!length(tasks)) {
      cat("No tasks yet.\n")
    } else {
      if (limit >= 0L) tasks <- head(tasks, limit)
      writeLines(sprintf("%2d. %s\n", seq_along(tasks), tasks))
    }
  },

  add = {
    #| description: Task description to add.
    task <- NULL

    tasks <- if (file.exists(store)) yaml::read_yaml(store) else list()
    tasks[[length(tasks) + 1L]] <- task
    yaml::write_yaml(tasks, store)
    cat("Added:", task, "\n")
  },

  done = {
    #| description: Index of the task to complete.
    #| short: i
    index <- 1L

    tasks <- if (file.exists(store)) yaml::read_yaml(store) else list()
    task <- tasks[[as.integer(index)]]
    tasks[[as.integer(index)]] <- NULL
    yaml::write_yaml(tasks, store)
    cat("Completed:", task, "\n")
  }
)
```

```sh
todo add "Write quarterly report"
todo list
todo list --limit 5
todo done 1
todo --store /tmp/work.yml list
```

---

## Shipping CLIs in an R Package

Place CLI scripts in `exec/` and add `Rapp` to `Imports` in DESCRIPTION:

```
mypkg/
├── DESCRIPTION
├── R/
├── exec/
│   ├── myapp       # script with #!/usr/bin/env Rapp shebang
│   └── myapp2
└── man/
```

Users install the CLI launchers after installing the package:

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

Expose a convenience installer so users don't need to know about Rapp:

```r
#' Install mypkg CLI apps
#' @export
install_mypkg_cli <- function(destdir = NULL) {
  Rapp::install_pkg_cli_apps(package = "mypkg", destdir = destdir)
}
```

By default, launchers set `--default-packages=base,<pkg>`, so only `base`
and the package are auto-loaded. Use `library()` for other dependencies.

---

## Quick Reference: Common Patterns

### NA vs NULL for optional arguments

- **NA** (`NA_integer_`, `NA_character_`) → optional **named option**.
  Test: `!is.na(x)`.
- **NULL** + `#| required: false` → optional **positional arg**.
  Test: `!is.null(x)`.

### stdin/stdout

```r
input_file <- NA_character_
con <- if (is.na(input_file)) file("stdin") else file(input_file, "r")
lines <- readLines(con)
writeLines(lines, stdout())
```

### Exit codes and stderr

```r
message("Error: something went wrong")   # writes to stderr
cat("Error:", msg, "\n", file = stderr()) # also stderr
quit(status = 1)                          # non-zero exit
```

### Error handling

```r
tryCatch({
  result <- do_work()
}, error = function(e) {
  cat("Error:", conditionMessage(e), "\n", file = stderr())
  quit(status = 1)
})
```

---

## Additional Reference

For less common topics — launcher customization (`#| launcher:` front matter),
detailed `Rapp::install_pkg_cli_apps()` API options, and more complete examples
(deduplication filter, variadic install-pkg, interactive fallback) — read
`references/advanced.md`.

© Garrick Aden-Buie (@gadenbuie) · MIT · posit-dev/skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой