Author: tidyILD authors
Date: 2026-04-17

# Bayesian dynamics recipes (ild_brms)

#### tidyILD authors

#### 2026-04-17

This article gives copy-paste templates for modest dynamics extensions with [`ild_brms()`]. It is not a substitute for identification work, prior sensitivity, or specialized DSEM software when that is your estimand. See `vignette("temporal-dynamics-model-choice", package = "tidyILD")` for how these pieces fit the bigger picture.

## Prerequisites

- Packages: brms, Stan backend (rstan or cmdstanr).
- Data prepared with [`ild_prepare()`]; lag columns from [`ild_lag()`] or [`ild_panel_lag_prepare()`].

## Recipe 1: Random slope for a lagged predictor

    library(tidyILD)
    set.seed(1)
    d <- ild_simulate(n_id = 15, n_obs_per = 12, seed = 1)
    d$x <- rnorm(nrow(d))
    x <- ild_prepare(d, id = "id", time = "time")
    x <- ild_lag(x, x, n = 1L, mode = "gap_aware")
    tpl <- ild_brms_dynamics_formula("y", "x_lag1", id_var = "id")
    tpl$formula
    tpl$notes
    # Short chains for illustration only:
    # fit <- ild_brms(tpl$formula, data = x, iter = 500, chains = 2, refresh = 0)
    # ild_tidy(fit)

`ild_brms_dynamics_formula()` returns a suggested formula `(lag | id) + (1|id)`; adjust priors via [`ild_prior_ild()`] and check [`ild_diagnose()`] (R-hat, ESS).

## Recipe 2: Bivariate lag sketch (two variables)

Build two lag columns, then include both fixed effects (and optionally random slopes). A full panel VAR requires more structure than this template; this is a minimal associational extension.

    x2 <- ild_panel_lag_prepare(x, c("x", "y"), n = c(1L, 1L), mode = "gap_aware")
    names(x2$data)
    # Example fixed structure only (not run):
    # f2 <- y ~ x_lag1 + y_lag1 + (1 | id)
    # fit2 <- ild_brms(f2, data = x2$data, iter = 500, chains = 2, refresh = 0)

## Recipe 3: Multivariate outcomes with `mvbind` (sketch)

For two or more outcomes measured on the same occasions, brms can model them jointly with `mvbind()` so residuals can correlate across outcomes. This is still not a full panel VAR / DSEM: you must choose lags, priors, and residual structure deliberately. When the estimand is a fully specified dynamic system with feedback, dynamite or lavaan DSEM (or similar) is often more appropriate than stacking outcomes in a single `brms` formula.

    # Not run — requires brms; illustration only:
    # library(brms)
    # f_mv <- bf(mvbind(mood, stress) ~ mood_lag1 + stress_lag1 + (1 | id)) + set_rescor(TRUE)
    # fit_mv <- brm(f_mv, data = x2$data, chains = 2, iter = 500, refresh = 0)
    # Build mood_lag1 / stress_lag1 with ild_lag() or ild_panel_lag_prepare() first.

For routing when joint multivariate dynamics or high-dimensional predictors matter, see `vignette("ild-specialist-backends", package = "tidyILD")`.

## See also

- `?ild_brms`, `?ild_prior_ild`, `?ild_diagnose`
- `vignette("temporal-dynamics-model-choice", package = "tidyILD")`
- `vignette("ild-specialist-backends", package = "tidyILD")`