Skip to contents

The ssel command calls the installed SSEL public API and shares its version. Every public function is available by its exact R name. The aliases model, chain and post remain available. The command reads the installed library’s API facts.

Work Operations
Complete workflows modelPipeline, chainPipeline, semiSupervisedPipeline
Splits, fits and predictions buildDataset, trainModel, trainRegressionModel, predictModel
OOF diagnostics oofEnsemble, auditQuantiles, auditOverfit
Delivery aggregateResponses, postProcess
Chain importance and gates extractChainImportance, activeByImportance, activeByShadow, computeActiveByImportance
Data utilities detectOutliers, removeOutliersIQR, toNumeric, which.nonnum

ssel --help lists operations. ssel OPERATION --help renders that function’s installed R documentation. ssel --version prints ssel <version>, the version of the package actually loaded; the command has no version of its own. API access does not imply that every learner, dataset or scientific configuration has been validated.

Library boundary

The adapter owns terminal arguments, JSON/RDS decoding, table schemas, result serialization and exit status. Its private R helpers implement those interface contracts. Modeling, iteration, gates, diagnostics and transformations stay in the installed library. The adapter resolves exported functions and invokes them with their existing arguments; it does not source implementation files or introduce a second scientific pipeline.

Project data builders and manifest interpretation remain in the consuming project. A project manifest is not automatically an SSEL argument specification. AR-S2J2J, for example, assembles its domains and datasets before calling SSEL.

Installation

Use a complete source bundle containing cli/ and install/. The R package alone does not install the terminal command. R must be installed.

The normal macOS entry installs the package when missing and the CLI under the default prefix /usr/local:

sudo bash install/install.sh

Under sudo, every R process runs as the validated invoking user; R does not request elevation. The default builds and installs the package from the bundle’s lib/ together with the CLI, even when the installed version is equal or newer; --tarball selects a recorded package artifact instead of building the checkout. On Windows the entry is native PowerShell without elevation, with default prefix %LOCALAPPDATA%\Programs\ssel:

powershell -ExecutionPolicy Bypass -File install\install.ps1

Equivalent options are -Yes, -Check, -Library, -Dependency, -Tarball and -Prefix; -NoPath prevents a user PATH change. The bundle’s install/USAGE.md is the installation manual and defines these separate operations.

The public operation installs the package and the CLI together; there is no component selection. The examples below therefore send both to temporary destinations, so they leave an existing installation untouched. Run them from the bundle root. They do not alter shell profiles.

macOS, in Bash:

work="$(mktemp -d)"
library="$work/library"
prefix="$work/ssel"
mkdir -p "$library"
bash install/install.sh --yes --library "$library" --prefix "$prefix"
export R_LIBS="$library${R_LIBS:+:$R_LIBS}"
export PATH="$prefix/bin:$PATH"
ssel --version

Windows, in native PowerShell:

$Work = Join-Path ([System.IO.Path]::GetTempPath()) ([guid]::NewGuid().ToString())
$Library = Join-Path $Work 'library'
$Prefix = Join-Path $Work 'ssel'
New-Item -ItemType Directory -Path $Library -Force | Out-Null
& .\install\install.ps1 -Yes -Library $Library -Prefix $Prefix -NoPath
$env:R_LIBS = (@($Library, $env:R_LIBS) | Where-Object { $_ }) -join ';'
$env:PATH = (Join-Path $Prefix 'bin') + ';' + $env:PATH
& (Join-Path $Prefix 'bin\ssel.ps1') --version

Runtime commands never install dependencies. Compatible dependencies visible to R remain available through normal library resolution.

The installed payload contains platform launchers under PREFIX/bin, the runtime under PREFIX/libexec/ssel, an uninstaller and an ownership receipt. The launchers resolve R when they run; the receipt records the R that installed them as history, not as the interpreter to reuse. It works after the source bundle is removed. Existing CLI paths and linked bin/libexec directories cause a conflict. On Windows use ssel.ps1 when the working directory is a UNC path; cmd.exe cannot preserve a UNC working directory.

To remove the temporary CLI, after using it:

bash "$prefix/libexec/ssel/install/uninstall.sh" --prefix "$prefix" --library "$library"
& (Join-Path $Prefix 'libexec\ssel\install\uninstall.ps1') -Prefix $Prefix -Library $Library

A default macOS installation is removed with sudo bash install/uninstall.sh; after deleting the checkout, use the installed copy sudo bash /usr/local/libexec/ssel/install/uninstall.sh. Removal checks owned file checksums first. Modified or missing files stop removal. R packages and unrelated files remain.

Inputs and returned objects

ssel OPERATION --spec FILE.json|FILE.rds [--output RESULT.rds|RESULT_DIR] [--seed N] [--root DIR]

A JSON specification is one object with exact R argument names. Omitted arguments retain R defaults. Scalars and declared vector arguments become R values/vectors; nested objects remain lists. A JSON null supplies NULL. Null elements within a vector become missing values. Empty character vectors and nested gate histories are supported. The exact texts "Inf", "-Inf" and "NaN" decode to their numeric values only where the argument default is numeric; anywhere else they remain ordinary strings.

--seed N seeds the R process before the operation, so independent invocations of stochastic learners are reproducible.

An RDS specification is a plain named list of arguments. It preserves native R types, tables, factors, empty vectors, nested lists, NULL, NA, NaN and infinities. In JSON, any argument can instead be {"$rds":"value.rds"} to read that native object. Values are passed as data, without evaluating stored expressions.

Table arguments DT, .data, importanceDT and IMP also accept {"$csv":"table.csv","colClasses":{"column":"character"},"na.strings":["NA"]}. Declare every CSV column and its class, and the exact missing-value convention. Use RDS when factor levels or other R attributes matter.

Data-returning functions require --output. This includes trainRegressionModel in both modes and the complete semi-supervised history and promotion return. With an .rds path the full result, including an invisible R return, is saved as RDS. With a path without extension, a new directory is created holding result.json — the result’s shape and types, with NA as null and NaN, Inf and -Inf as their exact texts — plus one CSV per table with column classes and factor levels recorded in the manifest. Classes without a portable form refuse the conversion; use .rds for them. The six file-oriented operations buildDataset, trainModel, modelPipeline, chainPipeline, aggregateResponses and postProcess allow output to be omitted. Outputs must be new paths in an existing directory; this restriction applies only to --output, not to files written by the library. The six-operation classification controls whether --output is optional; other operations also write files, as described below.

--output saves the function’s return after the operation runs. It does not select or redirect the operation’s working directories. For example, trainRegressionModel requires it even with TRAIN = TRUE, which writes models and returns NULL. Changing --output and invoking the command again executes the operation again; it does not convert a previously saved result.

--root DIR selects an existing project directory. Relative paths resolve from that directory: the specification itself, its CSV/RDS references, operation arguments and --output. Without --root, they resolve from the working directory. Moving the specification does not change that base; absolute paths remain absolute. For example, from outside a project:

ssel toNumeric --root /path/to/project --spec numeric.json --output numeric-result.rds

The selected root is also the working directory seen by the library’s existing validation of destinations that a pipeline may wipe.

Files written by each operation

The paths below are arguments inside the specification, resolved from --root or the working directory as described above. A name such as .path.export is a caller-selected directory, not a fixed data/export location. The model, chain and post aliases have the effects of modelPipeline, chainPipeline and postProcess respectively.

Splits, models, diagnostics and delivery

Here <response>, <dataset> and <method> stand for the selected names. These functions do not recursively clear their output directories. Files they write can replace existing files at the same paths; skipped cells can leave earlier files in place.

Operation Files read Files written and rerun behavior
buildDataset Dataset CSVs in .path.input. Writes <response>_<dataset>_TRAIN.csv, _TEST.csv and _TRAIN_ids.csv in the existing .path.train directory. Replaces the splits it emits; it does not create that directory or remove obsolete splits.
trainModel TRAIN splits in .path.train, and cached models/hashes in .path.model. Calls trainRegressionModel with TRAIN = TRUE: writes model/hash pairs in .path.model. Creates missing .path.model, .path.metrics and .path.response directories when their parents exist; this training step does not emit metrics or predictions. OVERRIDE follows the cache rule below.
trainRegressionModel With TRAIN = TRUE, TRAIN splits in .path.data and cached models/hashes. With TRAIN = FALSE, TRAIN/TEST splits, models and metrics. With TRAIN = TRUE, saves .path.model/<method>_<response>_<dataset>.Rds and its .Rds.hash companion. With TRAIN = FALSE, writes <response>_<dataset>.csv in .path.metrics and .path.response. The needed destination directories must already exist.
predictModel Splits in .path.train, models in .path.model, metrics/response CSVs, and .path.summary/prediction_quantiles.csv from auditQuantiles. Optionally .file.index. Runs trainRegressionModel with TRAIN = FALSE, then replaces .path.summary/metrics.csv, response_long.csv and nonempty .path.export/<dataset>.csv deliveries. Creates missing summary/export directories when their parents exist; metrics/response directories must already exist. When .file.index exists, it also joins location data into every CSV in summary/export containing the index key, rewriting those files.
auditQuantiles Models in .path.model, TRAIN splits/ID sidecars in .path.train, and .path.datasets for ID recovery when a sidecar is absent; existing summary residuals if present. Creates .path.summary as needed. Rewrites residuals_oof.csv, retaining previous rows for responses absent from the reconstructed batch, then recomputes prediction_quantiles.csv from the combined residuals. No reconstructed rows is an error before either CSV is written.
auditOverfit Models in .path.model and TRAIN splits in .path.train. Creates .path.summary as needed and writes overfit.csv for the reconstructed audit. This replaces the table rather than merging responses. If the audit returns a column-less empty table, fwrite does not replace an earlier file; read the warnings before treating that file as a current result.
aggregateResponses .path.summary/{response_long,metrics,prediction_quantiles,residuals_oof}.csv, declared dataset CSVs in .path.datasets, and earlier Yo.csv/Y.csv when present. Rewrites .path.export/Yo.csv, retaining responses absent from the new prediction rows. Writes .path.export/X.csv and Xo.csv from the last declared dataset whose file exists; with no dataset file, warns and leaves earlier X files in place. The export directory must exist. When .path.iter is supplied, creates it as needed and merges/replaces response columns in Y.csv.
postProcess .path.export/Yo.csv, .path.summary/{response_long,residuals_oof,metrics,prediction_quantiles}.csv, and locationSources. Their defaults are data/domains/index.csv, .path.export/X.csv and .path.export/Xo.csv. Writes or replaces .path.export/predictions.csv and audit.csv. It reads but does not rewrite Yo.csv or the summaries.

In training mode, OVERRIDE = FALSE skips a model only when both its RDS and hash file exist and the stored hash matches the sorted predictor names. This is a feature-name check, not a check of training values, tuning or all model settings. A missing or different hash triggers fitting and may replace the model. OVERRIDE = TRUE requests fitting regardless of that cache; a failed fit is reported and does not replace the existing model.

Workflow cleanup and iteration state

modelPipeline (model) reads .path.datasets, rebuilds splits in .path.train in every mode, and uses the corresponding destinations from the table above. Its cleanup policy is:

mode With wipe = NULL (default) or TRUE Work after cleanup
full (default) Recursively removes .path.train, .path.metrics, .path.response, .path.summary, .path.model and .path.export. Rebuilds splits, fits, audits, predicts and aggregates.
train Recursively removes .path.train, .path.metrics, .path.response and .path.summary; retains model/export directories. Rebuilds splits and fits under OVERRIDE = FALSE.
predict Recursively removes .path.train, .path.metrics, .path.response and .path.summary; retains model/export directories. Rebuilds splits, audits existing models, predicts and aggregates.

With wipe = FALSE, none of those directory trees is removed, but individual split/product files can still be replaced or merged. Training then uses OVERRIDE = FALSE. Missing destination directories are created recursively. An optional .path.iter receives Y.csv during aggregation; this operation does not clear that directory. modelPipeline does not call postProcess.

chainPipeline (chain) uses the same dataset and output arguments plus .path.iter. A fresh chain (resume = FALSE, the default) recursively removes .path.iter and runs a full model pass. Each Jacobi iteration runs another full pass; each Gauss-Seidel sweep clears the six model output directories once, then accumulates its response substeps without clearing them again. The chain writes augmented datasets_<n>/, Y.csv, Y<n>.csv, Yo<n>.csv, metrics_<n>.csv, summary_<n>/ snapshots and convergence.csv under .path.iter. Summary snapshots replace the same snapshot directory; convergence rows are appended for continued iterations.

resume = TRUE continues only when both .path.iter/convergence.csv and .path.iter/Y.csv exist. If either is absent, it takes the fresh-chain path, including deletion of .path.iter. If both exist but .path.summary/metrics.csv is missing, it stops instead. Later continuation and final assembly also consume the saved snapshots. Resume still replaces the model-stage outputs as iterations run; it is not an append-only operation. At completion, Yo.csv and the five summary CSVs are assembled from the selected iteration for each response. Models and .path.iter/Y.csv retain the last iteration, not that assembled per-response selection.

semiSupervisedPipeline reads .path.datasets and writes under .path.work/round/. Before every fit round, including its initial fit and a fit restoring accepted pseudo-labels after rejection, it recursively removes that round directory. It recreates datasets, train, model, metrics, response, summary and export there, then re-emits final predictions over the original prediction pool. It does not retain a separate product tree per round; --output saves its returned history and promotions. When .path.iter is supplied, the function reads its metrics_<n>.csv files and selects datasets_<n>/ there as its source instead of the supplied .path.datasets. That iteration directory is an input to this operation.

The workflows validate paths before their recursive cleanup: a wipe target cannot coincide with, contain or lie inside the source datasets directory, or coincide with or contain the working directory. Repeated canonical targets are also rejected where several destinations are checked together. This guard is not a general no-overwrite policy for the lower-level writers or for wipe = FALSE.

Operations without library-managed file output

oofEnsemble reads models, TRAIN splits and ID sidecars, with dataset files as its fallback for ID recovery, and returns the reconstructed OOF table. extractChainImportance and computeActiveByImportance read models from pathModel. activeByImportance, activeByShadow, detectOutliers, removeOutliersIQR, toNumeric and which.nonnum operate on supplied objects. These nine operations do not write library-managed product files; the CLI writes their return to the required --output. This does not mean they all avoid fitting: removeOutliersIQR fits a model in memory.

Executable example

After installation, the following R block creates a fresh directory and complete specifications from the public chain example. It only prepares inputs; the subsequent commands run the installed CLI. The fixture seed and learners are teaching choices, not scientific recommendations.

Root <- tempfile("ssel-cli-example-")
dir.create(file.path(Root, "datasets"), recursive = TRUE)
setwd(Root)
Data <- data.frame(
  SampleID = c(paste0("S", 1:18), "P1", "P2"),
  set = c(rep("train", 18), "predict", "predict"),
  x = 1:20, z = rep(c(0, 1), 10),
  targetA = c(1, 2.4, 1.8, 3.7, 2.9, 5.1, 4, 6.2, 5.4,
              7, 6.1, 8.3, 7.2, 9.1, 8, 10.5, 9.4, 11.2, NA, NA),
  targetB = c(2.2, 1.3, 3.6, 2.7, 4.1, 3.8, 5.7, 4.6, 6.5,
              5.9, 7.8, 6.4, 8.6, 7.5, 9.9, 8.7, 10.4, 9.6, NA, NA)
)
utils::write.csv(Data, "datasets/demo.csv", row.names = FALSE, na = "")
Spec <- list(
  .path.datasets = "datasets", .path.train = "train", .path.model = "model",
  .path.metrics = "metrics", .path.response = "response",
  .path.summary = "summary", .path.export = "export",
  key = "SampleID", responses = c("targetA", "targetB"), datasets = "demo",
  methods = "lm", seed = 2026, features = c("x", "z")
)
jsonlite::write_json(Spec, "model.json", auto_unbox = TRUE, pretty = TRUE)
Spec$.path.iter <- "iter"
Spec$maxIter <- 1
Spec$tol <- 0
Spec$patience <- 2
Spec$sweep <- "jacobi"
jsonlite::write_json(Spec, "chain.json", auto_unbox = TRUE, pretty = TRUE)
jsonlite::write_json(list(
  .path.summary = "summary", .path.export = "export", key = "SampleID",
  responses = c("targetA", "targetB"), location = c("x", "z"),
  locationSources = "datasets/demo.csv"
), "post.json", auto_unbox = TRUE, pretty = TRUE)
jsonlite::write_json(list(x = c("1,25", "1 234", "x")),
                     "numeric.json", auto_unbox = TRUE)
saveRDS(list(
  .path.datasets = "datasets", .path.work = "semi", key = "SampleID",
  responses = c("targetA", "targetB"), datasets = "demo",
  methods = c("lm", "glm"), seed = 2026, tau = 0.1, maxRounds = 1,
  epsRevert = Inf, promotionCap = 0.5
), "semi.rds")
Root

From that printed directory, run these commands in order. The chain replaces the model-stage products using its own documented fresh-run policy.

ssel toNumeric --spec numeric.json --output numeric-result.rds
ssel modelPipeline --spec model.json
ssel chainPipeline --spec chain.json
ssel postProcess --spec post.json
ssel semiSupervisedPipeline --spec semi.rds --output semi-result.rds
ssel semiSupervisedPipeline --spec semi.rds --output semi-portable

The last command executes the semi-supervised pipeline again, replacing semi/round/, and saves that run’s return in portable form: a new semi-portable/ directory with result.json and one CSV per table. Run it only if this second execution is intended.

Back in R in the same directory, inspect the complete returned objects:

readRDS("numeric-result.rds")
readRDS("semi-result.rds")$history
jsonlite::read_json("semi-portable/result.json")$result$kind  # "list"
utils::read.csv("semi-portable/history.csv")
utils::read.csv("export/predictions.csv")
utils::read.csv("semi/round/export/Yo.csv")

Effects and failures

Choose --output separately from the paths the operation creates or clears. The CLI checks this return destination before calling the function, then refuses to save the return if the function has created that path. An existing parent checked before execution can also be removed by workflow cleanup. The CLI has no dry-run mode, transaction or rollback: a library error can leave partial products, and a serialization error happens after the library has run. Portable serialization can also leave a partially written result directory. Reinvoking the operation to change output format repeats its library effects.

Malformed specifications, unknown or duplicate names, missing required arguments, invalid output destinations and library errors exit 1 with their cause. Warnings remain visible. A successful exit does not prove that every model cell had enough data to fit. Learner dependencies and scientific validation remain the public library’s contracts.