ssel command-line interface
cli.RmdThe 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:
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:
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 --versionWindows, 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') --versionRuntime 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:
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:
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")
RootFrom 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-portableThe 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:
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.