Skip to contents

Register your own node kinds and executors. bayesgrove handles the graph, cache, decision log, and workflow protocol.

Term Meaning in bayesgrove
Node set A group of node kinds plus executors you register on a handle
Ruleset A chosen set of workflow_packs plus the summary vocabulary they consume
Domain module An R helper or package that bundles node registration, pack selection, and project conventions
Plugin A built-in executor set (e.g. bg_use_cmdstanr())
Extension Any combination of the four items above

The stable public hooks are node-kind registration, built-in executor activation (bg_use_cmdstanr() / bg_use_brms()), and summary emission from executors. Workflow-pack selection is also public. Custom workflow-pack providers use internal APIs. External packages should emit the built-in summary kinds rather than call unexported provider functions.

Select workflow packs

Projects start empty by default. If your workflow needs the built-in review vocabulary, activate and persist the packs you want after creating the project:

library(bayesgrove)

project_root <- file.path(tempdir(), "bg-extensions")
unlink(project_root, recursive = TRUE, force = TRUE)

handle <- bg_init(
  path = project_root,
  project_name = "Extensions"
)

bg_use_workflow_packs(
  handle,
  c(
    "bayesgrove.default_bayesian",
    "bayesgrove.process_guidance",
    "bayesgrove.model_taxonomy",
    "bayesgrove.prior_workflow",
    "bayesgrove.model_checks",
    "bayesgrove.model_selection",
    "bayesgrove.stan_workflow",
    "bayesgrove.causal_dagitty"
  )
)
#> [[1]]
#> [[1]]$pack_id
#> [1] "bayesgrove.default_bayesian"
#> 
#> [[1]]$version
#> [1] "0.2.0"
#> 
#> [[1]]$config
#> list()
#> 
#> 
#> [[2]]
#> [[2]]$pack_id
#> [1] "bayesgrove.process_guidance"
#> 
#> [[2]]$version
#> [1] "0.1.0"
#> 
#> [[2]]$config
#> list()
#> 
#> 
#> [[3]]
#> [[3]]$pack_id
#> [1] "bayesgrove.model_taxonomy"
#> 
#> [[3]]$version
#> [1] "0.1.0"
#> 
#> [[3]]$config
#> list()
#> 
#> 
#> [[4]]
#> [[4]]$pack_id
#> [1] "bayesgrove.prior_workflow"
#> 
#> [[4]]$version
#> [1] "0.1.0"
#> 
#> [[4]]$config
#> list()
#> 
#> 
#> [[5]]
#> [[5]]$pack_id
#> [1] "bayesgrove.model_checks"
#> 
#> [[5]]$version
#> [1] "0.1.0"
#> 
#> [[5]]$config
#> list()
#> 
#> 
#> [[6]]
#> [[6]]$pack_id
#> [1] "bayesgrove.model_selection"
#> 
#> [[6]]$version
#> [1] "0.1.0"
#> 
#> [[6]]$config
#> list()
#> 
#> 
#> [[7]]
#> [[7]]$pack_id
#> [1] "bayesgrove.stan_workflow"
#> 
#> [[7]]$version
#> [1] "0.1.0"
#> 
#> [[7]]$config
#> list()
#> 
#> 
#> [[8]]
#> [[8]]$pack_id
#> [1] "bayesgrove.causal_dagitty"
#> 
#> [[8]]$version
#> [1] "0.1.0"
#> 
#> [[8]]$config
#> list()

vapply(bg_workflow_packs(handle), function(pack) pack$pack_id, character(1))
#> [1] "bayesgrove.default_bayesian" "bayesgrove.process_guidance"
#> [3] "bayesgrove.model_taxonomy"   "bayesgrove.prior_workflow"  
#> [5] "bayesgrove.model_checks"     "bayesgrove.model_selection" 
#> [7] "bayesgrove.stan_workflow"    "bayesgrove.causal_dagitty"

Those packs add review vocabulary without changing the graph engine:

  • bayesgrove.default_bayesian: computation review, fit criticism, candidate comparison, and branch disposition.
  • bayesgrove.process_guidance: workflow preflight, iterative repair notes, and out-of-sample stability review.
  • bayesgrove.model_taxonomy: PAD classification and utility-tradeoff review.
  • bayesgrove.prior_workflow: prior rationale and prior predictive review.
  • bayesgrove.model_checks: posterior predictive checks and, for latent_inference branches, SBC and LOO-PIT calibration review.
  • bayesgrove.model_selection: model-comparison evidence from fresh comparison summaries, with optional stacking weights.
  • bayesgrove.stan_workflow: a bundled Stan-oriented ruleset covering the default loop, process guidance, taxonomy, predictive checks, model selection, Stan diagnostics, and projection review.
  • bayesgrove.causal_dagitty: DAG-backed adjustment review, implication review, and causal selection contracts for latent_inference branches.

bayesgrove.model_selection only acts at project scope when there are at least two clean fit candidates. The taxonomy and causal packs apply to branches with the relevant goal. After review of a causal_selection_contract, bayesgrove.causal_dagitty can constrain formulas and projection-based selection to retain required identification terms and exclude forbidden controls.

Build a node set

A node set is usually a helper that registers several node kinds for one modeling domain. Each executor receives (node, inputs) and returns plain R data.

register_normal_model_nodes <- function(handle) {
  bg_register_node_kind(handle, "study_data", executor = function(node, inputs) {
    data.frame(y = rnorm(50), x = rnorm(50))
  })

  bg_register_node_kind(handle, "prior_note", executor = function(node, inputs) {
    list(
      result = node$params,
      summaries = list(list(
        summary_kind = "prior_spec",
        passed = TRUE,
        severity = "ok",
        metrics = list(scale = node$params$scale)
      ))
    )
  })

  bg_register_node_kind(handle, "fit_normal", executor = function(node, inputs) {
    data <- inputs[[1]]

    list(
      result = list(mean_y = mean(data$y)),
      summaries = list(
        list(
          summary_kind = "prior_predictive_check",
          passed = TRUE,
          severity = "ok",
          metrics = list(simulated_mean = 0.0)
        ),
        list(
          summary_kind = "posterior_predictive_check",
          passed = TRUE,
          severity = "ok",
          metrics = list(ppc_p_value = 0.46)
        ),
        list(
          summary_kind = "pad_annotation",
          passed = TRUE,
          severity = "ok",
          metrics = list(
            model_class = "PAD",
            primary_utility = "predictive_performance"
          )
        )
      )
    )
  })
}

For node sets that can be used together:

  1. Keep executors domain-specific and return plain data.
  2. Emit summaries as plain-data records so workflow packs can react to them.

Opening a project never runs project-supplied code

Executors are R functions, and a project’s runtime manifest stores their source text so the project can be reopened later. For safety, bg_open() restores the kind name, input contracts, and executor source as metadata. It does not evaluate the saved source, including when opening a project directory from an untrusted source.

To restore executable executors after opening, call bg_restore_executors() explicitly:

handle <- bg_open("path/to/project")

# Default: print the stored source for each kind and abort, so you can
# review what would run before consenting.
bg_restore_executors(handle)

# Once you have reviewed the source, opt in:
bg_restore_executors(handle, trust = TRUE)

With trust = FALSE (the default) the stored source for each kind is printed and the call aborts. With trust = TRUE each source is evaluated in a child of the global environment (not inside the bayesgrove namespace), and a warning reminds you that closures capturing the original environment are not restored. Alternatively, re-register executors with bg_register_node_kind().

Built-in executors (shipped with the package) are persisted as stable references and restore safely without this opt-in step.

Attach data to nodes

Node params contain data, not executable R source. bayesgrove does not evaluate R code from params, including data_fn_source or check_fn_source. To preserve R types that JSON serialization can change, such as Stan’s typed integers, attach the object with bg_set_node_data(). It saves the object in the content-addressed store and sets a data_ref param:

n_data <- bg_add_node(handle, kind = "stan_data", label = "Data")
bg_set_node_data(handle, n_data, list(N = 10L, y = as.integer(y)))

Register executable R functions with bg_register_node_kind(), or restore saved executors with bg_restore_executors(trust = TRUE) after reviewing them.

Emit diagnostic summaries

The optional packs are summary-driven. They do not require special node kinds; they use summary records attached to fresh results.

Summary kind Consumed by Typical use
prior_spec bayesgrove.prior_workflow Record the current prior specification
prior_predictive_check bayesgrove.prior_workflow Review whether priors generate plausible observables
posterior_predictive_check bayesgrove.model_checks Review fit-to-data mismatch after conditioning
loo_pit_calibration bayesgrove.model_checks Review leave-one-out predictive calibration
sbc_result bayesgrove.model_checks Review parameter recoverability and calibration for latent_inference branches
comparison_results / model_comparison / stacking_weights bayesgrove.model_selection Compare clean candidates and review weighting evidence
projpred_selection / projection_predictive_selection bayesgrove.stan_workflow Review submodel compression and refit plans
dagitty_adjustment bayesgrove.causal_dagitty Review DAG-derived adjustment sets
dagitty_implications bayesgrove.causal_dagitty Review implied independencies and falsification targets
causal_selection_contract bayesgrove.causal_dagitty Lock required terms, exclude forbidden controls, and rank admissible precision candidates
pad_annotation bayesgrove.model_taxonomy Label a branch with PAD class and utility dimensions

Causal selection contracts and constrained projpred workflows

A causal branch can emit a causal_selection_contract summary to constrain model construction. Its fields include:

  • required_terms for identification-critical covariates,
  • forbidden_terms for colliders, post-treatment variables, or other blocked controls,
  • ranked_candidate_terms for the admissible precision path from simpler to larger models, and
  • optionally allowed_formulas to enumerate exact permitted RHS patterns.

Once that summary is reviewed, bayesgrove.causal_dagitty can enforce formula consistency and keep downstream work on hold until the branch’s formulas obey the contract. bayesgrove.stan_workflow also forwards the same causal payload into projection-predictive review so a projpred-style node can search only inside the admissible ranked candidate set.

bg_register_node_kind(handle, "causal_selection_contract", executor = function(node, inputs) {
  list(
    summaries = list(list(
      summary_kind = "causal_selection_contract",
      passed = TRUE,
      severity = "ok",
      metrics = list(
        required_terms = c("treatment", "z"),
        forbidden_terms = "post_treatment",
        ranked_candidate_terms = c("w", "x")
      )
    ))
  )
})

Start with the smallest causally valid formula. Add permitted terms in the specified order when evaluating precision. Restrict projection-based selection to the permitted candidates.

Use serializable data in each summary:

  • summary_kind for dispatch,
  • passed and severity for review urgency,
  • metrics for compact numeric or categorical evidence,
  • extra fields only when they remain stable plain data.

Package a domain module

A domain module combines bg_init() with node-registration helpers in a reusable setup function. You can distribute it as an extension package.

init_normal_workflow <- function(path) {
  handle <- bg_init(
    path = path,
    project_name = "normal_workflow"
  )

  bg_use_workflow_packs(
    handle,
    c(
      "bayesgrove.default_bayesian",
      "bayesgrove.process_guidance",
      "bayesgrove.model_taxonomy",
      "bayesgrove.prior_workflow",
      "bayesgrove.model_checks",
      "bayesgrove.model_selection",
      "bayesgrove.stan_workflow"
    )
  )

  register_normal_model_nodes(handle)
  handle
}

Put the helper in an analysis package, a lab utility package, or a project script. Update the node set and its selected workflow packs together.

Built-in cmdstanr and brms executors

bayesgrove includes executors that call cmdstanr and brms and compute diagnostics themselves (divergences, R-hat, ESS, Pareto-k, posterior-predictive p-values). Activate them with:

These register node kinds (stan_data, cmdstanr_fit, brms_fit, loo, compare, ppc, …) whose executors emit the validated summary kinds the workflow packs consume. A cmdstanr_fit node emits an hmc_diagnostics summary. With the default review pack active, warning or error diagnostics raise a blocking review_computation_validity obligation.

Use the built-in executors for cmdstanr and brms, or register a custom executor with bg_register_node_kind().

Rulesets

A ruleset combines:

  1. the workflow_packs you activate in bg_init(), and
  2. the summary kinds your executors emit for those packs to interpret.

Registering new workflow-pack providers from an external package is not a public API. For custom review logic, use one of these approaches:

  • emit the existing summary vocabulary and reuse the built-in packs,
  • wrap a project-specific decision policy around bg_next_actions(), or
  • pin to internal helpers only if you are comfortable tracking internal API changes.