Step Types

Every step is assumed to be R unless stated otherwise. Exactly one step type field must be set per step.

Core

script: – R script

Runs Rscript --no-save --no-restore <path> [args].

- id: extract
  script: etl/extract.R
  args: ["--dept", "sales"]

r_expr: – Inline R

Writes the expression to a temp .R file in the run directory, runs via Rscript.

- id: summarize
  r_expr: |
    data <- readRDS("data/clean.rds")
    cat(sprintf("Rows: %d\n", nrow(data)))
    cat("::daggle-output name=row_count::", nrow(data), "\n")

command: – Shell

Runs via sh -c. The escape hatch for non-R tasks.

- id: notify
  command: echo "Pipeline complete" | mail -s "Done" team@example.com

Documents

quarto: – Quarto render

Runs quarto render <path> [args]. Requires Quarto installed.

- id: report
  quarto: reports/dashboard.qmd
  args: ["--to", "html"]

rmd: – R Markdown

Renders via rmarkdown::render(). Requires the rmarkdown package.

- id: report
  rmd: reports/monthly.Rmd

R package development

test: – Run tests

Runs devtools::test() with structured output. Emits pass/fail/skip counts and coverage as ::daggle-output:: markers. Requires devtools.

- id: test
  test: "."

check: – R CMD check

Runs rcmdcheck::rcmdcheck(). Emits error/warning/note counts. Requires rcmdcheck.

- id: check
  check: "."
  error_on: warning    # treat check warnings as failures

document: – Generate docs

Runs roxygen2::roxygenize(). Requires roxygen2.

- id: docs
  document: "."

lint: – Lint code

Runs lintr::lint_package(). Emits issue count. Requires lintr.

- id: lint
  lint: "."

style: – Format code

Runs styler::style_pkg(). Requires styler.

- id: style
  style: "."

coverage: – Code coverage

Runs covr::package_coverage(). Emits coverage percentage. Requires covr.

- id: coverage
  coverage: "."

pkgdown: – Package website

Runs pkgdown::build_site(). Requires pkgdown.

- id: site
  pkgdown: "."

benchmark: – Benchmarks

Runs bench scripts from a directory.

- id: bench
  benchmark: benchmarks/

revdepcheck: – Reverse dependency checks

Runs revdepcheck::revdep_check(). Requires revdepcheck.

- id: revdep
  revdepcheck: "."

Environment

renv_restore: – Restore renv

Runs renv::restore() to install packages from renv.lock. Requires renv.

- id: restore
  renv_restore: "."

install: – Install packages

Installs packages via pak (preferred) or install.packages().

- id: deps
  install: "dplyr, ggplot2, tidyr"

Deployment

connect: – Posit Connect

Deploys to Posit Connect. Requires rsconnect. See Posit Connect deployment.

- id: deploy
  connect:
    type: quarto        # shiny, quarto, or plumber
    path: reports/dashboard.qmd
    name: sales-dashboard

pin: – Publish via pins

Publishes data or models via pins::pin_write(). Requires pins.

- id: publish
  pin:
    board: connect      # connect, s3, local, azure
    name: sales-data
    object: output/data.rds
    type: rds

vetiver: – MLOps

Model versioning and deployment via vetiver. Requires vetiver.

- id: version-model
  vetiver:
    action: pin          # pin or deploy
    model: models/fit.rds
    board: connect
    name: sales-model

Workflow

approve: – Approval gate

Pauses execution until a human approves or rejects. See Approval Gates.

- id: review
  approve:
    message: "Review model metrics before deploying"
    timeout: 24h

call: – Sub-DAG

Executes another DAG as a sub-step. See Sub-DAG Composition.

- id: run-etl
  call:
    dag: daily-etl
    params:
      dept: "{{ .Params.department }}"

targets: – Targets pipeline

Runs targets::tar_make(). Requires targets.

- id: pipeline
  targets: "."

shinytest: – Shiny app tests

Runs shinytest2::test_app(). Requires shinytest2.

- id: app-test
  shinytest: app/

validate: – Data validation

Runs a validation R script via Rscript.

- id: validate
  validate: scripts/validate_data.R

Data sources

database: – SQL query

Runs a SQL query via R DBI and writes the result set to disk. Replaces the common DBI + dbGetQuery + write.csv boilerplate.

- id: pull_orders
  database:
    driver: postgres        # postgres | mysql | mariadb | sqlite | duckdb | odbc
    params:
      dbname: analytics
      host: ${env:PGHOST}
      user: ${env:PGUSER}
      password: ${env:PGPASSWORD}
    query: |
      SELECT * FROM orders
      WHERE created_at >= now() - interval '7 days'
    output: data/orders.csv
Field Required Description
driver yes Database driver. Maps to RPostgres, RMariaDB, RSQLite, duckdb, or odbc
params no Named args passed to DBI::dbConnect() (e.g. dbname, host, user, password)
query either Inline SQL query. Mutually exclusive with query_file
query_file either Path to a .sql file, relative to workdir
output yes Output path. Format inferred from the extension: .csv, .tsv, .rds, .parquet, .feather

The row count is emitted as ::daggle-output name=row_count::<n>:: for downstream steps.

Notifications

email: – Send email

Sends an email via a named SMTP channel defined in config.yaml. Uses Go’s net/smtp directly — no R required.

- id: send_report
  email:
    channel: team_smtp       # SMTP channel name in config.yaml
    subject: "Weekly dashboard — {{.Today}}"
    body: |
      Hi team,
      The weekly dashboard and summary are attached.
    attach:
      - reports/dashboard.html
      - data/summary.csv
Field Required Description
channel yes Name of a smtp-type channel in config.yaml
subject yes Email subject
body either Inline plain-text body (mutually exclusive with body_file)
body_file either Path to body file
from no Sender address (overrides channel’s smtp_from)
to no List of recipients (overrides channel’s smtp_to)
cc no CC recipients
bcc no BCC recipients (not shown in headers)
attach no Files to attach (paths relative to workdir)

Attachments are base64-encoded with their MIME type inferred from the file extension. Output recipients holds the total envelope size (to + cc + bcc).

Isolation

docker: – Containerized step

Runs a command inside a Docker container. Useful for isolating different R versions, Bioconductor dependencies, or system libraries (GDAL, PROJ, CUDA).

- id: bio_pipeline
  docker:
    image: bioconductor/bioconductor_docker:3.18
    command: Rscript /work/scripts/analyze.R
    volumes:
      - ./scripts:/work/scripts:ro
      - ./data:/work/data
    env:
      PROJECT_ID: "{{.Params.project_id}}"
    workdir: /work
    pull: missing     # always | missing | never
Field Required Description
image yes Container image to run
command either Shell command inside the container (run via sh -c). One of command or entrypoint must be set
entrypoint either Override the image entrypoint
volumes no Bind mounts in host:container[:ro] form
env no Environment variables passed via -e
workdir no Working directory inside the container
network no Docker network (host, bridge, none, or a named network)
user no uid[:gid] to run as
pull no Pull policy: always, missing (default), never

The docker run --rm ... subprocess is supervised like any other step — timeouts, retries, and signal handling apply uniformly. Logs are captured to the run directory exactly like command: steps.

Missing packages

All R step types check for their required package at runtime. If a package is missing, the step fails with a clear message:

step "test" requires the devtools package. Install with: install.packages("devtools")