skills/55-ab604-claude-code-r-skills/skills/r-style-guide/SKILL.md
R style guide covering naming conventions, spacing, layout, and function design best practices. Use when writing R code.
npx skillsauth add brycewang-stanford/Awesome-Agent-Skills-for-Empirical-Research r-style-guideInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Consistent naming, spacing, structure, and function design for R code
# Good function structure
rescale01 <- function(x) {
rng <- range(x, na.rm = TRUE, finite = TRUE)
(x - rng[1]) / (rng[2] - rng[1])
}
# Use type-stable outputs
map_dbl() # returns numeric vector
map_chr() # returns character vector
map_lgl() # returns logical vector
# Good naming: snake_case for variables/functions
calculate_mean_score <- function(data, score_col) {
# Function body
}
# Prefix non-standard arguments with .
my_function <- function(.data, ...) {
# Reduces argument conflicts
}
# Good
day_one
calculate_mean
user_data
# Avoid
DayOne
calculate.mean
userData
# Good spacing
x[, 1]
mean(x, na.rm = TRUE)
if (condition) {
action()
}
# Pipe formatting
data |>
filter(year >= 2020) |>
group_by(category) |>
summarise(
mean_value = mean(value),
count = n()
)
# Good - Use <- for assignment
x <- 5
# Avoid - = for assignment (use only for function arguments)
x = 5 # Less clear intent
# Good - Long function call
do_something_complicated(
data = my_data,
arg_one = value_one,
arg_two = value_two,
arg_three = value_three
)
# Good - Long pipe chain
result <- data |>
filter(year >= 2020) |>
mutate(
new_var = old_var * 2,
another_var = str_to_lower(text_var)
) |>
summarise(
mean_value = mean(value),
.by = category
)
# Good - Comments explain WHY, not WHAT
# Calculate running average to smooth noise in sensor data
running_avg <- zoo::rollmean(values, k = 5)
# Avoid - Comments that just repeat the code
# Add 1 to x
x <- x + 1
# 1. Load packages at the top
library(dplyr)
library(ggplot2)
# 2. Source any helper files
source("R/helpers.R")
# 3. Define constants
MAX_ITERATIONS <- 1000
DEFAULT_THRESHOLD <- 0.05
# 4. Define functions
process_data <- function(data) {
# ...
}
# 5. Main script logic (if not a package)
main <- function() {
data <- read_csv("data/input.csv")
result <- process_data(data)
write_csv(result, "data/output.csv")
}
# Good - Each function does one thing
read_and_validate <- function(path) {
data <- read_csv(path)
validate_columns(data)
data
}
validate_columns <- function(data) {
required <- c("id", "value", "date")
missing <- setdiff(required, names(data))
if (length(missing) > 0) {
stop("Missing columns: ", paste(missing, collapse = ", "))
}
}
# Avoid - Function does too many things
do_everything <- function(path, output_path, ...) {
# Reads, validates, transforms, models, plots, writes...
}
# Good - Explicit return for complex functions
calculate_metrics <- function(data) {
metrics <- list(
mean = mean(data$value),
sd = sd(data$value),
n = nrow(data)
)
return(metrics)
}
# Good - Implicit return for simple functions
square <- function(x) {
x^2
}
# Avoid - Return in the middle without good reason
process <- function(x) {
if (is.null(x)) return(NULL) # OK - early exit
# ... more code
result # Implicit return at end
}
Prefer cli::cli_abort() over stop() for user-facing errors. Structure messages as a problem statement followed by context bullets.
# Good - cli::cli_abort() with structured bullets
# Bullet types: x = error detail, i = info/hint, ! = warning
validate_input <- function(x, threshold = 0) {
if (!is.numeric(x)) {
cli::cli_abort(c(
"{.arg x} must be numeric.",
x = "You supplied {.cls {class(x)}}.",
i = "Convert with {.fn as.numeric} first."
))
}
if (any(x < threshold)) {
cli::cli_abort(c(
"{.arg x} must be >= {threshold}.",
x = "{sum(x < threshold)} value{?s} below threshold.",
i = "Set {.arg threshold} to adjust the lower bound."
))
}
}
# Good - reference argument names, functions, and classes with inline markup
cli::cli_abort(c(
"{.fn my_func} requires a data frame.",
x = "{.arg data} is {.cls {class(data)}}, not {.cls data.frame}.",
i = "Did you mean to call {.fn as.data.frame}?"
))
# Avoid - stop() with string concatenation
stop("`x` must be numeric, not ", typeof(x), call. = FALSE)
Inline markup tokens:
{.arg x} — argument name (backtick-formatted){.fn foo} — function name{.cls {class(x)}} — class name{.val {value}} — literal value{?s} — pluralisation (value{?s} → "value" or "values")# Good - Sensible defaults
summarise_data <- function(data, na.rm = TRUE, digits = 2) {
# ...
}
# Good - NULL default for optional arguments
filter_data <- function(data, min_value = NULL, max_value = NULL) {
if (!is.null(min_value)) {
data <- filter(data, value >= min_value)
}
if (!is.null(max_value)) {
data <- filter(data, value <= max_value)
}
data
}
# Good - Data as first argument for piping
my_transform <- function(data, var, threshold = 0.5) {
data |>
filter({{ var }} > threshold)
}
# Usage
data |> my_transform(value, threshold = 0.8)
# Good - Prefix with . to avoid conflicts
group_summary <- function(.data, ..., .by = NULL) {
.data |>
summarise(..., .by = {{ .by }})
}
# Good - Always return tibble
my_function <- function(data) {
result <- data |>
# processing...
filter(!is.na(value))
tibble::as_tibble(result)
}
# Avoid - Inconsistent spacing
x<-1+2 # No spaces
x <- 1 + 2 # Correct
# Avoid - Unnecessary parentheses
if ((x > 0)) {} # Extra parens
if (x > 0) {} # Correct
# Avoid - Using T/F instead of TRUE/FALSE
if (x == T) {} # T can be overwritten
if (x == TRUE) {} # Correct
# Avoid - Semicolons to separate statements
x <- 1; y <- 2 # Hard to read
x <- 1 # Correct
y <- 2
# Avoid - attach() - creates ambiguity
attach(mtcars)
mean(mpg) # Which mpg?
detach(mtcars)
# Correct - Be explicit
mean(mtcars$mpg)
# or
with(mtcars, mean(mpg))
# or
mtcars |> pull(mpg) |> mean()
tools
Recommend AND run open-source AI tools, agents, Claude Code / Codex skills, and MCP servers for any stage of a literature review — searching, reading, extracting, synthesizing, screening, citation-checking, and paper writing. Use when the user asks "what tool should I use to..." OR "install/run/use <tool> to ..." for research/lit-review work: automating a survey or related-work section, PDF→Markdown extraction for LLMs (MinerU/marker/docling), PRISMA / systematic review (ASReview), citation-backed Q&A over PDFs (PaperQA2), wiring papers into Claude/Cursor via MCP (arxiv/paper-search/zotero servers), or chatting with a Zotero library. Ships a launcher (scripts/litrun.py) that installs each tool in an isolated venv and runs it. Curated catalog of 70+ vetted projects. 支持中英文(用于「文献综述工具选型」与「一键安装/运行」)。
development
Route empirical-research requests through the Auto-Empirical Research Skills catalog when this whole repository is installed as one skill in Codex, CodeBuddy, Claude Code, or another IDE. Use to choose and load the right vendored AERS skill for causal inference, econometrics, replication, data acquisition, manuscript writing, peer review and referee responses, citation checking, de-AIGC editing, or full empirical-paper workflows without reading the entire repository at once.
documentation
Use when the project collects primary data or runs a field, lab, or survey experiment, before the intervention begins — write the pre-analysis plan, size the sample from a power calculation, and register with the AEA RCT Registry. Apply after the design is chosen in aer-identification and before any outcome data are seen.
tools
Guide economists to authoritative data sources with explicit, confirmed data specifications before retrieval; interfaces with Playwright MCP to navigate portals and extract real data, not articles about data.