tinytrail is a lightweight R package that — once initialized — leaves a ‘tiny trail’ of human- and AI-readable information about what each script saves to disk, making it effortless to keep better track of small to medium-sized projects. It maintains a YAML trail file (_tinytrail.yaml) at the project root recording which scripts produced which output files and each script’s runtime. The tinytrail package also provides a convenience function that effortlessly registers column names along with sample values (optional) in the YAML.
Installation
install.packages("tinytrail")
# Development version from GitHub:
pak::pak("tinytrail-r/tinytrail")Usage
Call tinytrail() once near the top of each script. Common write functions are intercepted automatically:
library(tinytrail)
tinytrail(
description = "Clean and summarise survey data",
data_source = "Current Population Survey (BLS)"
)
dat <- read.csv("data/raw/survey.csv")
write.csv(dat, "output/clean.csv") # auto-tracked
png("output/age_dist.png") # auto-tracked
hist(dat$age, main = "Age distribution")
dev.off()tinytrail() detects the script name and creates or updates _tinytrail.yaml:
scripts:
01_clean.R:
description: Clean and summarise survey data
data_source: Current Population Survey (BLS)
first_run: '2026-06-27 09:00'
latest_run: '2026-06-27 09:01'
script_runtime: 0.2 min
n_outputs: 2
outputs:
- output/age_dist.png
- output/clean.csvFor write functions not in the built-in list, pass a list to extra_hooks with the function names and their file-path arguments:
tinytrail(
description = "Export results",
extra_hooks = list(
fn = c("readr::write_csv", "ggplot2::ggsave"),
arg = c("file", "filename")
)
)(These two functions are already captured automatically — they’re shown here for illustration only.)
Optionally, pipe data frames through tinytrail_dict() to capture column names and sample values:
# ... cleaning and preparing data ...
dat |>
tinytrail_dict()This adds a data dictionary entry to _tinytrail.yaml:
data_dictionary:
01_clean.R:
dat:
columns:
id: [1, 2, 3, 4, 5]
age: [34, 52, 28, 41, 37]
response: ['yes', 'no', 'yes', 'yes', 'no']Manual tracking with auto = FALSE
To track only specific outputs, set auto = FALSE and use tinytrail_write() explicitly. It returns its argument invisibly, so it drops inline into any save call:
tinytrail("Export selected results", auto = FALSE)
write.csv(dat, tinytrail_write("output/clean.csv"))
saveRDS(model, tinytrail_write(here::here("output/model.rds")))