--- title: "Extending krt with plugins" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Extending krt with plugins} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` ```{r setup} library(krt) ``` `krt` is built on five registries, and each is a public extension point. An institution can add profiles, validators, resolvers, LLM providers, and autocomplete sources without forking the package. ```{r} krt_plugin_api() ``` Check an object against its contract before registering it: ```{r} validate_plugin_contract("validator", function(x, ctx) list()) ``` ## A custom validator A validator is `function(x, ctx)` returning a list of issues. Here is one that flags datasets lacking a license. ```{r} license_rule <- function(x, ctx) { out <- list() for (r in x$resources) { if (identical(r$resource_type, "Dataset") && is.null(r$license)) { out <- c(out, list(list(message = "Dataset has no license.", resource_id = r$resource_id, field = "license"))) } } out } register_validator("inst-dataset-license", license_rule, layer = "semantic", severity = "warning") k <- add_resource(new_krt("Demo"), "Dataset", "D", doi = "10.5281/zenodo.1", new_or_reuse = "new") "inst-dataset-license" %in% as.data.frame(validate_krt(k))$rule_id ``` ## A custom institutional profile A profile is a directory with `schema.yml` and `mappings.yml`. Register it by path: ```{r, eval = FALSE} register_profile(name = "my-institute", path = "path/to/profile/dir") export_krt(k, file.path(tempdir(), "out.csv"), profile = "my-institute") ``` ## A custom resolver or suggest source ```{r, eval = FALSE} register_resolver("myscheme", function(id, resolve = TRUE, ...) { list(input = id, normalized = id, resolved = FALSE, source = "mine") }) register_suggest_source("mysource", function(query, n) { data.frame(label = query, id = "X:1", authority = "mine", score = 1, uri = NA_character_, stringsAsFactors = FALSE) }) ``` Registered plugins run inside the same error isolation as the built-ins: a rule or resolver that throws is caught, so a faulty plugin cannot abort a validation or resolution run. Plugins are still trusted code. A plugin registered with `replace = TRUE` deliberately overrides a built-in, and a validator whose predicate or body errors is downgraded to a warning rather than failing the run, so a plugin can change validation and output behavior.