DataStep Studio for R Install
Documentation · version 0.10.3

The dsr commands

The command line of the extension, for you and for AI agents: 44 tools, each with its own help, made from the tool itself so that this page cannot drift from it.

On this page
44 tools
  1. The session
    1. dsr start
    2. dsr stop
    3. dsr status
    4. dsr wait
    5. dsr sessions
    6. dsr doctor
    7. dsr history
  2. Running programs
    1. dsr run
    2. dsr eval
    3. dsr log
    4. dsr output
    5. dsr more
    6. dsr reload
    7. dsr outline
    8. dsr batch
  3. Debugging: when a value is wrong and the log does not say why
    1. dsr pry
    2. dsr trace
    3. dsr pipe
    4. dsr coverage
  4. Data (a data frame of the session, a file .xpt/.rds/.sas7bdat/.csv, @pry:<obj>, @pipe[k])
    1. dsr datasets
    2. dsr describe
    3. dsr profile
    4. dsr query
    5. dsr freq
    6. dsr means
    7. dsr dups
    8. dsr compare
    9. dsr data
    10. dsr ls
  5. The R language
    1. dsr syntax
    2. dsr complete
    3. dsr index
  6. Writing code, tests and packages
    1. dsr lint
    2. dsr format
    3. dsr load
    4. dsr check
    5. dsr test
  7. Clinical data: subjects, specifications, conformance
    1. dsr subject
    2. dsr spec
    3. dsr cdisc
    4. dsr numbers
  8. Checks of the dashboard and the study (the clinical add-on)
    1. dsr app
    2. dsr gate
    3. dsr adam
  9. The guide for agents

Every dsr tool, with the help text the tool itself prints (dsr tools, dsr help <tool>), version 0.10.3. The editor puts dsr on the PATH of its terminals; elsewhere it is node <extension folder>/bin/dsr.js. The MCP server (bin/dsr-mcp.js) gives the same tools with the same arguments.

Every tool also takes --json (one JSON object), --max-lines N (the rest: dsr more) and --root DIR (that folder's session).

The session

dsr start

Start the shared R session of the project (its .Rprofile, renv and startup file triallens.R). When it cannot start, it says why (a missing R package, no Rscript) and the fix.

Usage: dsr start [--root DIR]

dsr stop

Stop what the session is running now (like Ctrl+C); the objects stay. --session ends the R session itself.

Usage: dsr stop [--session]

dsr status

State of the session: running or busy (with what, and its last message), the last run, an open pry, the data frames.

Usage: dsr status

dsr wait

Wait until the session is free again (a run that outlived its call, or --timeout): SESSION: FREE, or exit 3 when it still runs after --timeout seconds.

Usage: dsr wait [--timeout 600]

dsr sessions

The R sessions dsr can reach from here (this folder, the folders above and below it): running, busy or stopped, with their project folder. Choose one with --root DIR (or cd).

Usage: dsr sessions [--dir DIR]

dsr doctor

Can a session start here, and which tools will work: Node, Rscript, R, the R library the project uses, the packages each tool needs, Chrome, the session; each problem with its fix.

Usage: dsr doctor [--root DIR]

dsr history

The last runs of the session and their verdicts.

Usage: dsr history [--n 20]

Running programs

dsr run

Run a program (or code from stdin) in the session, expression by expression: a log with the line of every message and a NOTE for each data frame a step makes.

Usage: dsr run <file.R | -> [--from-line N] [--to-line M] [--stop-at LINE | FILE:LINE ['if <condition>'] (repeat it)] [--stop-when '<R condition>'] [--stop-on-warning] [--coverage] [--echo] [--timeout S]

The log names the line of every message. A data frame a step creates or changes gets a NOTE:
  NOTE: adae has 1191 rows and 57 columns (was 1191 x 55). New: ASTDT (11 missing), ASTDTF (1180 missing).
  NOTE: Empty columns in adae (missing on every row): AEACN.      <- a bug until you know why
  WARNING: adae: rows went from 1191 to 1205 in a join ...        <- duplicate keys on the other side
--from-line/--to-line run a part (whole expressions); the objects of the session stay between runs, so after one
full run, run only what you changed. --stop-at stops before that line (also a line inside a function, in this or
another file the session sourced); repeat it for several stops; 'R/f.R:8 if x > 3' or --stop-when (for all) only
when the condition is TRUE there. The run WAITS at the stop (live): dsr pry ls | eval look there, then
dsr pry next | step | finish | continue | quit go on (each answers at the next stop or at the end of the run).
--stop-on-warning stops where a warning happens. --coverage: how often each line ran (dsr coverage).
An ERROR keeps the frames where it happened open: dsr pry stack, dsr pry ls, dsr pry eval.
pry() in the code stops there (pry(when = <condition>)); pry(stop = FALSE) keeps a snapshot and goes on (dsr pry points).
The last line before the verdict says what the run changed in the workspace (new, changed, removed objects).
A program runs in its own folder (as Rscript started there): its relative paths start at the program's folder;
dsr eval and dsr run - run in the project folder. A program elsewhere in the project can find the project folder
with rprojroot (rprojroot::find_root(rprojroot::has_file("<a file of the project root>"))).
--timeout S: come back after S seconds while the run goes on (exit 3); dsr wait, then dsr log.

dsr eval

Run R code in the session (at a pry stop: dsr pry eval); says what it changed in the workspace.

Usage: dsr eval '<code>' | dsr eval - <<'R' ... R  [--timeout S]

dsr log

Page through the log of the last run, with line numbers; --filter errors | warnings | notes | output | suspicious (the suspicious log: each message with its rule, why it matters and the fix) | rules (the rules).

Usage: dsr log [--filter errors|warnings|notes|output|suspicious|rules] [--from 1] [--n 200]

dsr output

The printed output of the last run.

Usage: dsr output [--from 1] [--n 200]

dsr more

The rest of a long output that --max-lines cut (the MCP tools cut at 400 lines): page through it.

Usage: dsr more [--from 1] [--n 200]

dsr reload

Source again the library files that changed since the session sourced them (dsr run names them in a NOTE).

Usage: dsr reload

dsr outline

The steps of a program with their lines: what each assigns, the functions it defines, its sections (then run --from-line/--to-line).

Usage: dsr outline <file.R>

dsr batch

Run programs in a NEW R session (a production run): proves each runs on its own; writes program.log next to it. --vanilla: without the project's .Rprofile and startup (only R and the project's packages), to prove a program needs nothing of the project.

Usage: dsr batch <file.R> [more.R ...] [--vanilla] [--timeout S]

Each program runs in its own new R session, in the project folder, with the log of dsr run (program.log next to it).
--vanilla (anywhere on the line): R --vanilla, so no .Rprofile (neither the project's nor yours), no .Renviron and no site
profile, and no startup file (triallens.R); the library paths are the session's (.libPaths(), passed as R_LIBS), so the
packages are there but nothing of the project is loaded: the proof that a program needs only R and its packages.

Debugging: when a value is wrong and the log does not say why

dsr pry

Look inside the frame where a run stopped (pry(), --stop-at, an error) and go on from a live stop: whereami, stack, ls, eval, up, down, frame; next, step, finish, continue, quit; break, watch, source, run, pipe, points.

Usage: dsr pry [whereami | stack | ls | eval '<code>' | up | down | frame <k> | next [n] | step | finish | continue | quit | break 'FILE:LINE [if <cond>]' | watch '<expr>' | unwatch | source <function> | run <file.R> | pipe | vars | points | point <k> | help]

whereami     the frame, its code around the line, its objects
stack (bt)   the frames from the top level down to where it stopped (=> the current one)
ls           the objects of the current frame
eval <code>  run code IN the frame (its local variables), e.g. dsr pry eval 'table(grp, useNA = "always")'
up / down / frame <k>   move between frames
At a LIVE stop (dsr run --stop-at, a breakpoint of the editor, pry() in the code) the run waits; each of these answers
at the next stop or at the end of the run, with the log since the last answer:
next [n] (n) the next line of this frame (or of the frame it returns to); n lines
step (s)     the next line anywhere: into a function of the project that this line calls
finish (f)   the first line after this frame returns
continue (c) to the next stop, or to the end of the run (its verdict)
quit (q)     end the run here: RESULT: STOPPED, the lines after the stop do not run (a new dsr run quits too)
break 'R/f.R:12 if x > 3'   one more stop;  watch 'x'   stop at the line after x changes;  unwatch
source <fn>  the function's code with its file and line;  run <file.R>  a program file run in the frame
pipe         the pipeline at this line, step by step, on the frame's data (as dsr pipe)
points       the snapshots that pry(stop = FALSE) kept (e.g. one per loop pass), point <k> opens one
The data tools take @pry:<object> (and @point[k]:<object>): dsr query @pry:adsl --where 'is.na(BMIBL)'

dsr trace

Run a function call and see every line that ran, the variables each line changed, and each if/while [TRUE]/[FALSE] with its values.

Usage: dsr trace [file.R] --call '<f(args)>' [--into g,h] [--steps 300]

The R counterpart of the DATA step trace: use it when a value is wrong and the log does not say why.
file.R (optional) defines the functions without running the rest of it; --into also traces the functions it calls.
  dsr trace R/derive.R --call 'bmi_group(c(22, 30, NA))'
  R/derive.R:8   grp[bmi > 30] <- ">=30"          grp = [3] "<25", "", ""     <- 30 is in no group
An error in the call keeps its frames open for dsr pry.

dsr pipe

Run the pipeline at a line step by step: rows before/after, columns added, values changed and the records each step dropped (by USUBJID + SEQ).

Usage: dsr pipe <file.R>:<line> [--no-prepare]

dsr coverage

Which lines the last run with --coverage ran, and how often: per file the lines that ran and those that never ran; a file: each line with its count.

Usage: dsr coverage [file.R]

Data (a data frame of the session, a file .xpt/.rds/.sas7bdat/.csv, @pry:<obj>, @pipe[k])

dsr datasets

The data frames of the session (also inside lists, e.g. study$adam$ADSL), of an open pry frame and of the last pipe debug.

Usage: dsr datasets

dsr describe

Columns of a data set (name, type, label, SAS format, width) and its size, as PROC CONTENTS; --find: the columns whose name or label contains a text.

Usage: dsr describe <data> [--find <text>]

dsr profile

What is in a data set in one call: missing, distinct and top values or min/max per column, hidden characters, duplicate rows, the key.

Usage: dsr profile <data> [--vars 'A B'] [--where '<R condition>']

dsr query

Rows of a data set with a WHERE (an R condition), columns and order; hidden characters show as \t, \xA0 and · (blanks at the ends).

Usage: dsr query <data> [--where '<R condition>'] [--search <text>] [--vars 'A B'] [--sort 'A -B'] [--n 20] [--offset 0] [--raw] [--code]

--code: the query as R code to paste into a program (dplyr and base R), checked to give the same rows: the
data viewer's "View as R code". --search: rows where any column contains the text (case not counted).
--raw: the stored values, not the formatted ones: a factor's code, a labelled value's number (haven), a date's days
since 1970-01-01. Formatted (the default): a factor's level, a labelled value's label, a SAS w.d format's decimals.

dsr freq

Counts and percents of values (PROC FREQ), one-way or A*B; --by for percents within groups; --subjects counts subjects (USUBJID), not rows.

Usage: dsr freq <data> <VAR | 'A*B'> (or --vars) [--by TRTA] [--where '<R condition>'] [--subjects] [--n 50]

dsr means

n, missing, mean, SD, min, median, max of numeric columns (PROC MEANS), --by groups.

Usage: dsr means <data> <'A B'> (or --vars) [--by TRTA] [--where '<R condition>']

dsr dups

Duplicate keys: how many, examples, and which columns differ between the duplicate rows.

Usage: dsr dups <data> --key 'USUBJID AESEQ' (or --by) [--where '<R condition>']

dsr compare

Compare two data sets value by value (PROC COMPARE), matched by --key: rows and columns only in one, values that differ with examples.

Usage: dsr compare <base> <compare> [--key 'USUBJID AESEQ'] [--vars 'A B'] [--tolerance 1e-8] [--n 5]

dsr data

A data frame in short: its columns with labels, missing and values, and the first rows (profile + query in one).

Usage: dsr data <data> [--where '<R condition>'] [--n 10] [--vars A,B]

dsr ls

The objects of the session (class, size, a short value) and its data frames.

Usage: dsr ls

The R language

dsr syntax

Look up an R function BEFORE you write the call: the signature and arguments of the installed version, from its help page.

Usage: dsr syntax <pkg::fn | fn> [--full]

dsr complete

What the editor offers at a place in a file: completions (the session's functions and their arguments, packages and their exports, data frames and their columns with labels, in a call or a pipe on a data frame), the signature of the call there; without a session (or while it runs): the project's functions, the packages' exports (dsr index) and the columns of the project's data specification.

Usage: dsr complete <file.R>:<line>:<col> [--n 40]

dsr index

Write the index for completion without a session (.triallens/index.json): each package the project uses, with its functions, their arguments and help titles, and the R library paths. A short R process in the project folder.

Usage: dsr index

Writing code, tests and packages

dsr lint

Problems in R code WITHOUT running it, with file:line: syntax, functions that do not exist in the installed package, argument names a function does not have, undefined variables (typos); lintr's correctness linters when installed.

Usage: dsr lint [file.R | folder ...]   (default: R/, programs/ and the .R files of the project)

dsr format

Put R files into the house style with styler, with the proof that only the layout changed: the code's tokens and its comments stay the same (a file whose proof fails is not written); --check writes nothing; the project's style: options(dsr.format = list(...)) or --scope.

Usage: dsr format <file.R | folder ...> [--check | --write] [--scope spaces|indention|line_breaks|tokens] [--indent-by 2] [--strict true|false]

The proof, per file: the code's tokens (every token but the comments: its kind and its text, in order) are the
same before and after, the comments are the same word for word, and the parsed program is the same. A file is
written only when its tokens and comments are the same; with --scope tokens (styler may change ' to ", = to <-,
braces) when its program and comments are the same. Else it stays as it is and the first difference is named.
--scope: how much styler may change: spaces < indention < line_breaks (the default: the layout only) < tokens.
--check: write nothing, say which files would change (exit 1 when one would); --write: write (the default).
The style: options(dsr.format = list(scope = "line_breaks", indent_by = 4, strict = FALSE)) in the project's .Rprofile,
else styler's defaults (indent 2); the verdict line names where it came from.
--indent-by N: spaces per level (styler's indent_by); --strict false: keep the spaces and line breaks styler would
only tidy (fewer changes). Both override options(dsr.format) of the project, as the editor's settings do.

dsr load

An R package in the project: load its code into the session like library() (pkgload::load_all, all functions), so they can be run, traced and pried.

Usage: dsr load

dsr check

R CMD check of the package in the project -> CHECK PASS | NOTES | FAIL, with each ERROR, WARNING and NOTE.

Usage: dsr check [--cran] [--timeout S]

dsr test

testthat in a clean R process (a package: its code loaded) -> TESTS PASS | FAIL, each failure with file:line; a test file, or --filter, runs only those tests; --verbose one line per file; --coverage: which lines of the project's functions the tests run.

Usage: dsr test [dir | test-file.R] [--filter <part of a file name>] [--verbose] [--coverage] [--timeout S]

--coverage: after the clean run, the same test files run once more in the session with the debugger's counters
(failures do not stop it), then COVERAGE per file of the project's functions: the lines the tests ran and those
they never ran; dsr coverage <file> lists each line with its count. A test file that sources a file of R/ is fine:
the functions it defines are counted from the next line on.

Clinical data: subjects, specifications, conformance

dsr subject

One subject across all data sets of the session: subject-level values, the records of each data set, and the events in time order.

Usage: dsr subject <USUBJID | subject number> [--vars 'A B'] [--n 30]

dsr spec

The specification of a data set (specs/adam/<ds>.yml), or of one variable with its derivation and codelist, checked against the data: missing values, values outside the codelist, type, label.

Usage: dsr spec <dataset> [VARIABLE] [--data <data>]

dsr cdisc

Conformance before a submission: names (8 characters), labels (40), flags (Y/N/blank), population flags, dates, ISO 8601, keys, text length, non-ASCII, and against the specification: variables, types, labels, codelists, order.

Usage: dsr cdisc <data> [--dataset ADSL] [--key 'USUBJID PARAMCD AVISIT'] [--spec specs/adam/advs.json]

dsr numbers

Are the numbers of an output table those of a reference (a CSR page, a double programmed output)? Row by row (block + label), number by number at the reference's decimals; --table cuts that table out of a long document.

Usage: dsr numbers <output.txt> <reference.txt | .pdf> [--table 14-3.01] [--only '<block regex>'] [--rows 'ref row = out row; ...'] [--label '<regex>'] [--round r|sas] [--page 49] [--n 30]

Each line of a table is a label and its numbers; a line of words only is a block heading (Baseline, Week 24).
Reference rows pair with output rows by block + label; numbers by position, each rounded to the reference's decimals.
  --only 'Week 24|Baseline'   compare only these blocks of the reference; the other rows are "not compared", not differences
  --rows 'Week 24 / Median (Range) = Week 24 / Median + Week 24 / Min, Max; n = Week 24 / n'
                              pair rows whose labels differ; + joins several output rows to one reference row
  --label '^Week \d+( \(Windowed\))?'   where a label ends, for pages with no gap of two blanks before the numbers
  --round sas                 round half away from zero (SAS ROUND: 42.65 -> 42.7), as a CSR made with SAS prints
  --page 49                   read a PDF page with its layout (pdftotext); a text file needs no option

Checks of the dashboard and the study (the clinical add-on)

dsr app

The dashboard (app.R, or --dir): start | stop | status | logs | check (headless browser, every page, screenshots -> APP: OK | CHECK | ERROR).

Usage: dsr app start|stop|status|logs|check [--dir apps/dashboard] [--port 3150 | --ports 3100-3199] [--timeout 120] [--width 1400] [--height 1000] [--set 'input=value' ...] [--wait '<CSS selector | js:condition>'] [--key data-rid]

start      the app in a background R process (the session stays free); --port, or a free port of --ports
check      a headless browser opens the app, visits every tab, and keeps for each page its errors, a screenshot and
           its text (.triallens/check/). --timeout: seconds for the app to load (also the browser's own commands);
           --width/--height: the browser window; --set 'f_SEX="F"' (repeat it) sets inputs before the visits, so the
           check runs on another view; --wait '.page-meta[data-view]' (a CSS selector) or 'js:<condition>' waits on
           each page; --key data-rid keeps the text and data-raw of every element with that attribute for dsr gate.
--dir      the app's folder when it is not the project folder (apps/dashboard).

dsr gate

The contract's numbers (triallens_gate(): dashboard.yml, specs/sap.yml) from the data and on the screen -> GATE PASS | FAIL; with a key column, each number from its own element (app check --key).

Usage: dsr gate

dsr adam

adam check <ds|all>: a programmed ADaM data set against specs/adam/<ds>.yml and, cell by cell, its reference -> ADAM PASS | FAIL.

Usage: dsr adam check <dataset|all>

The guide for agents

dsr guide prints the way of working on one page; an agent reads it once.

How to work in the programmer's R session through DataStep Studio for R (dsr)

The tools work in the user's live R session: the user sees every run, log and stop in the editor.
Find things out with the tools; never guess what R did. Run R only through dsr (no Rscript, no R -e).

THE LOOP
1. Goal: "Done when ..." is a fact in the data or the output (254 subjects; the gate passes), not a clean log.
   The specifications and contracts (specs/, dashboard.yml) belong to people: report what is wrong in them.
2. Look: dsr describe | profile | query <data> (also a file, @pry:x, @pipe[k]); dsr outline <program>.
   Before a call you are not sure of: dsr syntax pkg::fn (the installed version's arguments).
3. Write a small piece, dsr lint <file>, then dsr run <file> (or dsr run - for code on stdin).
   A program runs in its own folder (its relative paths start there); dsr eval and dsr run - in the project folder.
4. Read the verdict line, then every NOTE:
   RESULT: CLEAN  look at the result         CHECK  a warning or an error in disguise: fix it, or say why it is right
   RESULT: ERROR  fix the FIRST CAUSE only   NOTEs  empty columns, new columns with missing values, rows that grow in a join
   dsr log --filter suspicious: the messages that matter, each with its rule, why and fix (dsr log --filter rules)
5. A wrong value: find the cause with the tools before you change code, and say what you saw.
   an ERROR leaves its frames open: dsr pry stack | ls | eval '<code>'
   stop anywhere: dsr run <file> --stop-at 'R/f.R:42 if USUBJID == "01-701-1015"' (repeat it; --stop-on-warning);
   the run WAITS there: dsr pry ls | eval look, dsr pry next | step | finish | continue | quit go on (each answers at
   the next stop or the end); dsr pry watch x, break, pipe (the pipeline at the stop, on its data); a new run quits it
   dsr trace --call 'f(x)' (each line, what it changed, each if)    dsr pipe <file>:<line> (each pipeline step)
   dsr freq | means | dups --key | compare on the data
6. The smallest fix; run again (--from-line/--to-line runs a part; the objects stay). Three failed tries: report.
   Which lines ran at all: dsr run <file> --coverage, or dsr test --coverage (the lines the tests run), then
   dsr coverage <file> (a line run 0 times never ran).
   A refactor that must not change results: keep the old function (git show HEAD:R/f.R > old.R, sys.source into
   its own environment) and compare identical(old(x), new(x)) on many inputs: factor, Date and NA groups, empty
   data, one row. for() walks a factor as text and a Date as numbers; rbind() and c() decide the result's type.
7. Finish: dsr lint, dsr format (it writes only when it proves that only the layout changed), dsr batch <program>
   (alone, in a new session; it writes <program>.log next to it), dsr test, and the checks that fit the project:
   an output table with a reference (a CSR page, a double-programmed table): dsr numbers <output> <reference>
   ADaM with specs/adam/<ds>.yml: dsr adam check <ds>      a dashboard: dsr app check, then dsr gate
   data for a submission: dsr cdisc <data>
   A test that fails outside your task: report it, and run yours with dsr test <file> or --filter.
   A specification and a reference that disagree: follow the specification, say where they differ; never match
   the reference silently.

FOR A PROGRAM THAT CALLS dsr (an agent, a harness)
- --json on every tool: one object {schema "dsr/1", tool, exit, ok, verdict, summary, fix, text, truncated,
  more, data}. MCP: the same as structuredContent (node <extension>/bin/dsr-mcp.js; docs/agents.md).
- Exit codes: 0 good; 1 the tool says not good (ERROR, FAIL, PROBLEMS); 2 a wrong call or no session (fix: names
  what to do); 3 still running after --timeout S (dsr wait, then dsr log; dsr stop cancels, the objects stay).
- Long output: --max-lines N keeps the head and the verdict; dsr more --from N gives the rest.
- Writing code: dsr complete <file>:<line>:<col> (what fits there: columns with labels, arguments, exports, the
  signature), dsr query <data> ... --code (a view as R code to paste), dsr syntax pkg::fn.
- Sessions: dsr status, dsr sessions, --root DIR; it cannot start: dsr start says why; dsr doctor checks all.

dsr guide --full: which tool answers which question, in detail. dsr tools: every tool. dsr help <tool>: one.