본문으로 건너뛰기
cccskills
무료GitHub에 공개

r-cli-app

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.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(9)

  • SKILL.md11.2 KB
  • .evals/convert-script/eval.md2.4 KB
  • .evals/convert-script/input-script.R1.0 KB
  • .evals/convert-script/prompt.md628 B
  • .evals/simple-cli/eval.md2.1 KB
  • .evals/simple-cli/prompt.md574 B
  • .evals/subcommand-tool/eval.md2.3 KB
  • .evals/subcommand-tool/prompt.md608 B
  • references/advanced.md5.6 KB

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:

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 ExpressionCLI SurfaceNotes
foo <- "text"--foo <value>String option
foo <- 1L--foo <int>Integer option
foo <- 3.14--foo <float>Float option
foo <- TRUE / FALSE--foo / --no-fooBoolean toggle
foo <- NA_integer_--foo <int>Optional integer (NA = not set)
foo <- NA_character_--foo <str>Optional string (NA = not set)
foo <- NULLpositional argRequired by default
foo... <- NULLvariadic positionalZero or more values
foo <- c()repeatable --fooMultiple values as strings
foo <- list()repeatable --fooMultiple values parsed as YAML/JSON
switch("", cmd1={}, cmd2={})subcommandsapp cmd1, app cmd2
switch(cmd <- "", ...)subcommandsSame; 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

#!/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:

#!/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:

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

Available annotation fields:

FieldPurpose
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:

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:

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

Boolean Switches

TRUE/FALSE assignments become toggles:

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

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):

#| 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:

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.

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:

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 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

#!/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)
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)

#!/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")
  }
)
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:

Rapp::install_pkg_cli_apps("mypkg")

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

#' 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

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

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

Error handling

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.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

alt-text

무료

Generate and improve accessible alt text for data visualizations and images in R packages and Quarto documents. Use when the user wants to add, improve, or audit alt text for figures in a pkgdown site or .qmd files. Activate for requests that mention fig-alt, fig.alt, figure descriptions, or alt text in the context of an R package or Quarto document.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

posit-dev/skills5432026년 10월 16일 업데이트

brand-yml

무료

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.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

posit-dev/skills5432026년 10월 16일 업데이트

Create a release checklist and GitHub issue for an R package. Use when the user asks to "create a release checklist" or "start a release" for an R package.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

posit-dev/skills5432026년 10월 16일 업데이트

Rigorously review code or pull requests for correctness, security, accessibility, maintainability, tests, and edge cases. Use when users request a critical code review, want a guided walkthrough of findings, need implementer-facing feedback, or want to prepare, create, or submit a GitHub pull request review.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

posit-dev/skills5432026년 10월 16일 업데이트

Deploy or publish Python and R content to a Posit Connect server using rsconnect-python or the R rsconnect package. Handles interactive apps and dashboards, web APIs, rendered documents, and prepared bundles/manifests. Use whenever the user asks to deploy, publish, or redeploy content to Posit Connect, or mentions rsconnect. Consult this skill instead of guessing flags or commands.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

posit-dev/skills5432026년 10월 16일 업데이트

Research a codebase and create architectural documentation describing how features or systems work. Use when the user asks to: (1) Document how a feature works, (2) Create an architecture overview, (3) Explain code structure for onboarding or knowledge transfer, (4) Research and describe a system's design. Produces markdown documents with Mermaid diagrams and stable code references suitable for humans and AI agents.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

posit-dev/skills5432026년 10월 16일 업데이트

posit-dev의 스킬 모두 보기

이 스킬의 문제 신고