tinytrail is a lightweight R package that leaves a 'tiny trail' of human- and AI-readable records about each script's outputs, making it effortless to keep track of small to medium-sized projects.
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.csv
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']
tinytrail is flexible
For 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.)
If you encounter a package that is not supported, please open an issue and I will see what I can do as soon as possible. The next update will include more popular packages that employ custom save/write functions.
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")))
