^arrow →
^ipc: The Arrow IPC (Feather v2) format is now the
^ipc serializer. read_arrow() /
write_arrow() are renamed to read_ipc() /
write_ipc(), and the strategy symbol ^arrow is
now ^ipc. No alias is kept. Existing pipelines must update
their node serializers/deserializers (serializer = ^ipc,
deserializer = ^ipc) and call sites. The R runtime package
stays arrow, and ^parquet is a separate,
supported strategy (R arrow::write_parquet, Python
pyarrow.parquet, Julia Parquet2.jl).^parquet now uses
Parquet2.jl: The Julia emitter for the
^parquet serializer switched from the legacy
Parquet.jl package to the actively maintained pure-Julia
Parquet2.jl (Parquet2.writefile /
Parquet2.readfile). Projects that rely on
^parquet with Julia nodes must update any manually declared
[jl-dependencies].packages entry from Parquet
to Parquet2 (and re-run t update);
DataFrames remains required.%name% infix operators: Any function
can now be called infix with %name% syntax, R-style. For
example d %within% interval(start, end) is equivalent to
%within%(d, interval(start, end)). The lexer only treats
%name% as an infix operator when a % is
immediately followed by an identifier, so plain modulo
(a % b) is unaffected.Datetime values now render with a plain Z
suffix (Datetime(2024-01-15T09:30:00Z)) instead of
Z[UTC]. Named timezones render as
Datetime(2024-01-15T09:30:00[Europe/Lisbon]).str_nchar,
str_substring, slice, and char_at
now operate on Unicode code points instead of raw bytes. Multi-byte
characters are never split, and
str_substring(s, 0, str_nchar(s)) round-trips any
string.days_in_month validation:
days_in_month(year, month) now raises an explicit
ValueError when month is outside
[1, 12] instead of silently misbehaving.index_of / last_index_of are
character-indexed: index_of(s, needle) and
last_index_of(s, needle) now return character (Unicode code
point) indices instead of raw byte offsets, so multi-byte characters
count as one position. last_index_of(s, "") returns the
character count.str_split with empty separator splits on code
points: str_split(s, "") splits into individual
Unicode code points rather than raw bytes, so multi-byte characters are
never torn apart.str_pad / str_trunc count
characters: widths are measured in characters rather than
bytes, and truncation never splits a multi-byte character in half.drop_na handles every column type:
date, datetime, dictionary, list, and NA columns now correctly
contribute to missingness detection, so drop_na no longer
silently keeps or drops rows on non-scalar data.left_join, inner_join,
right_join, full_join, anti_join,
and semi_join treat integer 1 and float
1.0 as the same key, matching R’s coercion-to-character
semantics.distinct is NaN-aware: repeated
NaN rows collapse to a single row, consistent with
n_distinct.mode uses typed keys and deterministic
tie-breaking: values of different types no longer collide
(mode([1, 1, "1"]) is 1), and ties break by
first occurrence in input order.to_lower / to_upper are
Unicode-aware: case mapping uses the Unicode character database
(uucp) instead of ASCII-only byte folding, so
to_upper("éàüç") yields "ÉÀÜÇ" and
to_upper("ß") yields "SS". Mapping is
deterministic and reproducible (no locale dependence).str_detect, str_extract,
str_extract_all, str_count,
str_replace, str_replace_first,
str_split, str_lines, and
str_words now use PCRE2 in UTF-8 mode instead of
byte-oriented Str regex. .,
[...], and anchors match code points rather than bytes
(str_count("héllo", ".") is 5), and
\p{...} Unicode property classes are supported.mutate(select(df, $x), $z = $x * 2),
arrange(arrange(df, $x), $x), and
mutate(df, $y = select(other, $col)) now evaluate the
nested call to a DataFrame instead of being wrapped into a row-lambda
and rejected with a spurious TypeError. Previously these
valid expressions failed with “Function mutate expects a
DataFrame as first argument.”matches and contains selection helpers,
separate, and separate_rows now use PCRE2 in
UTF-8 mode instead of byte-oriented Str regex.
matches supports \p{...} Unicode property
classes (e.g. select(df, matches("^\\p{L}+$"))), and
multibyte values flow through separate /
separate_rows without being torn. contains now
uses a literal substring test. Existing Str.split semantics
(trailing empty tokens dropped, empty subject yields no rows) are
preserved.str_extract_all / str_count handle
trailing zero-width matches: patterns that can match the empty
string at end-of-input (a*, a?, lookaheads,
$-anchored assertions) no longer hang with unbounded memory
growth. The trailing empty match is reported once and the scan
terminates, matching R’s stringr behavior.get() raises KeyError for missing dict
keys: get(dict, "key") now performs a real lookup
— returning the value for an existing key, the default (if
given) for a missing one, and raising
KeyError: "Key \missing` not found in
Dict.”when no default is supplied. Previously it silently returned the whole dict unchanged, masking typos. Unsupportedget(a,
b)pairs now raise an explicitTypeError` instead of echoing
back the first argument.get() raises KeyError for missing pipeline
nodes: get(pipeline, "node") now raises
KeyError: "Node \missing` not found in
Pipeline.”when the node does not exist instead of silently returningNA, matchingpipeline_node. The 2-argument form decides existence by the declared node names, so a node whose value happens to beNAis not mistaken for a missing node. The 3-argument form (get(pipeline,
“missing”, default)`) keeps its documented safe-retrieval semantics and
returns the default on a missing node.get(pipeline, $node) strips the leading
$: dollar-symbol node lookup now retrieves the
node, matching the dict form of get. Previously
get(p, $a) failed with the misleading
Node \$a` not found in
Pipeline.and the 3-argument formget(p, $a,
default)silently returned the default even when nodea`
existed.pipeline_node(p, $node) accepts bare-word
selectors: a leading $ in the node name is now
stripped, so pipeline_node(p, $a) and
pipeline_node(p, "$a") both retrieve node a,
matching get(p, $a). Previously the $-prefixed
forms failed with Node \$a` not found in Pipeline.`.count, group_by + summarize, and
related verbs on factor (dictionary) columns now group by level string
with R-compatible ordering — unused levels are dropped and
NA factor values form an NA group. Previously
grouping fell back to raw dictionary indices, which produced wrong
groups for non-default level orders.count, summary, source,
n) or a runtime symbol (e.g. R,
sh, default) now fails immediately —
structurally in t check, at pipeline construction, and in
rename_node — with a clear Node \count` is
reserved: …message. Previously a node namedn` silently
shadowed the builtin and broke dependency inference for cross-pipeline
references.t fix suggests renaming colliding node
names: the reserved-name error now carries a
Rename_node suggested fix that appends _node
to the colliding name (count → count_node).
t fix / t_fix() applies it mechanically to the
node’s definition line. Downstream references to the node
(deps entries, sibling expressions, or other nodes’ raw
code) cannot be rewritten safely at the text level, so the fix is
refused — reported as skipped, file left untouched — whenever the old
name appears elsewhere in the file; references must then be renamed
manually. t fix --dry-run probes the file and reports a
refused rename as skipped too (not would-apply), and a skipped rename
prints a note naming the blocking line(s)
(e.g. Node \count` is still referenced on line 3 of
…). Confidence is“medium”` for this reason.t fix dry-run is accurate for
add_node_arg too: t fix --dry-run /
t_fix(dry_run = true) now probes the file for
Add_node_arg fixes the same way it already did for
Rename_node: an argument-insertion fix whose node is no
longer defined in the file is reported as skipped (with a note naming
the missing node) instead of would-apply, matching what the real apply
would do. Internally, apply_fixes no longer prints per-fix
preview lines to stdout — previews are returned in
fix_result.dry_run_entries and rendered by the caller — so
t_fix()’s returned summary string is clean (no stray
Would apply: lines leaking from a side effect).rewire no longer silently ignores a bad
replace:
rewire(p, "node", replace = ...) now raises an explicit
error when replace is missing, is not a Dict or named List
of node-name strings, or evaluates to an error. Previously a
list(...) value (which is not a function in T) was
swallowed into an empty replace map, making the call a silent no-op. Use
the dict literal form:
rewire(p, "node", replace = [old: "new"]).col_lens List values spread elementwise over
DataFrame rows: set(df, col_lens("c"), [10, 20])
now spreads the list elementwise across the new column, matching the
existing VVector behavior. A list whose length equals
nrow(df) assigns position-for-position; a shorter list
recycles modulo; a single-element list broadcasts to all rows; and an
empty list yields an NA column. Previously the raw List was
written as a scalar string per row
(e.g. Vector["[10,20]", "[10,20]"]).{ src = src + 1; [out: src] } where src
is also a preceding node) now correctly records the sibling node as a
dependency. Previously the locally-bound name was pre-registered before
scanning the right-hand side’s free variables, silently dropping the
reference.base package
and deepens propcraft self-tests:
serialize/deserialize round-trips are
property-tested over generated Int/Float/Bool/String scalars (30 draws
each), all five NA variants survive the round-trip,
t_write_json/t_read_json round-trips cover the
same scalar types, is_na identity holds for every generated
non-NA scalar, and error-code/message/context/chain round-trips verify
all 13 error codes. Additional propcraft self-tests exercise
prop_map_gen chains, prop_resize nesting,
prop_gen_df zero-row and single-cell edges,
prop_gen_one_of with NA-inclusive value sets, triple-nested
prop_gen_choice, all-NA column type correctness across
Int/Float/Bool/String, prop_for_all n=1, block-evaluated
error propagation, prop_gen_df_from factor-only and
single-row schemas, and multi-seed prop_gen_dict
invariants.testcraft
package: expect_equal identity is verified over
generated Int/Float/Bool/String scalars, DataFrames with injected NAs,
Lists, and Vectors; tolerance-based Float comparisons
correctly pass and fail;
expect_nrow/expect_ncol/expect_length
dimension identity holds over generated DataFrames and Vectors;
expect_true/expect_false are correct with
NA-hold semantics; expect_between catches out-of-range
values; expect_set_equal is order-independent;
expect_unique passes on all-unique generated vectors;
expect_no_na detects NA-bearing DataFrames;
expect_str_contains holds identity;
expect_fields correctly matches generated Dict keys;
expect_in/expect_match/expect_summary
are exercised.propcraft package: Property-based
testing primitives for hardening T’s standard library and user packages.
Instead of hand-writing fixed cases, state an invariant and
prop_for_all checks it over many generated inputs,
reporting a deterministic shrunk counterexample on failure.prop_for_all(gen, property, n = 100, max_counterexamples = 1, shrink = true):
Draws n values from a generator spec and evaluates the
property on each. The property may return a Bool, an
Expect value, or an Error. Returns an
Expect value, so assert(prop_for_all(...))
works directly inside t test files.
max_counterexamples = k collects up to k
distinct failing inputs (each shrunk) and reports them as numbered
blocks.prop_gen_int,
prop_gen_int_range, prop_gen_float_range,
prop_gen_bool, prop_gen_string_from,
prop_gen_choice, prop_gen_frequency,
prop_gen_vector, prop_gen_list,
prop_gen_factor, prop_gen_one_of,
prop_gen_date_range, prop_gen_df,
prop_gen_between, prop_gen_dict, and
prop_gen_ymd.prop_gen_df_from(df, nrows = 30, na_prob = 0.1):
Derives a DataFrame generator from a real sample — Int/Float bounds from
observed min/max, Strings from observed distinct values, Factors keep
their levels, Dates/Datetimes keep their observed range and timezone.
Empty frames, NA-only columns, and unsupported column types raise
explicit errors.prop_gen_fn(fn): Wraps any callable as
a generator; each draw calls fn(size) with the current
generation size.prop_stats(gen, n = 100): Probes a
generator (size ramp 1..n) and returns n_runs,
n_errors, value_types,
nested_sizes, and elapsed_ms — handy for
sanity-checking derived and custom generators.prop_gen_df with typed NA injection:
prop_gen_df(columns, nrows = 30, na_prob = 0.1) generates
DataFrames and injects typed NA values
(NAInt/NAFloat/NABool/NAString)
into columns according to na_prob — the fastest way to
catch data verbs that silently corrupt or drop rows on missing input.
Leaf scalar columns draw through a batched fast path, so 1000-row frames
generate in milliseconds.prop_map_gen(source, fn),
prop_such_that(source, pred, max_tries = 100), and
prop_resize(source, n).set_seed(n) before a run reproduces the exact
same values and counterexample on any machine, every run.with_seed(seed, thunk): New
base-package function that seeds the RNG for a single expression and
restores the previous state afterwards — exception-safe and nestable.
Scope determinism to one prop_for_all or one
sample without perturbing surrounding random draws.prop_gen_df and prop_gen_dict
cells from ymd_range / date_range columns
canonicalize to the generator’s start_day /
start_micros floor instead of the Unix epoch, so
counterexamples stay inside the range you declared. This matches the
existing behavior for prop_gen_between integer
columns.prop_gen_between(min, max): Bounded
integer generator with in-domain shrinking. For properties that have a
natural lower bound, counterexamples shrink toward the lower bound
rather than toward 0. Inside prop_gen_df, between-column
cells canonicalize to VInt min so the shrinker minimizes
within range.prop_show_spec(spec): Render any
generator spec back to valid T source. The rendered output rebuilds a
behaviorally equivalent generator (identical draws under the same seed).
Closure-based generators produce an explicit error.prop_named(name, property) +
prop_test(named, gen, ...): Named properties as
plain immutable Dicts — no global registry. Define a property once
(m = prop_named("mutate_preserves_nrow", \(df) ...)) and
test it against multiple generators. Failure reports prefix the property
name (STOP(Property mutate_preserves_nrow failed...)).shrink_verify = true opt-in:
Exhaustive shrink re-verification. By default, per-level shrink
candidates are capped at 32 for performance. When
shrink_verify = true, every candidate at the fixpoint is
re-checked uncapped, guaranteeing the reported counterexample is truly
minimal.prop_gen_dict(columns, na_prob = 0.1):
Dict generator — produces a Dict with one value per column. Shares the
column-spec format and leaf batched fast path as
prop_gen_df. Between-column cells within dicts shrink
toward their column’s lower bound.between shrink
strategies now propagate through composite generators
(list, vector, choice,
frequency). Nested prop_gen_between values
inside composites shrink toward their lower bound rather than toward
0.math, strcraft, and core packages
with invariants for arithmetic identities, string round-trips,
idempotence, and functional primitives. New cookbook guide
(docs/property-testing-cookbook.md) documents reusable
property-test patterns.prop_gen_ymd(min_year, max_year):
Calendar-day date generator — draws a Date uniformly across
every day in the inclusive year range (February 29th at its real
frequency). Counterexamples shrink toward
Date(min_year-01-01), keeping shrinks inside the date
domain.Date/Datetime values now shrink within their
domain — ymd_range toward the year-span floor,
date_range toward the start bound (micros 0 + preserved
timezone for datetimes), and bare date cells inside
prop_gen_df toward the epoch (1970-01-01 / micros 0).chrono package — date-bound invariants (day,
month, quarter, semester,
yday, isoweek, wday, leap-year
consistency), round-trips
(format_date/parse_date, ymd,
period arithmetic), %within% intervals, datetime
components, and NA-hardening of mutate/arrange
over date columns.stats package (mode membership over
typed/mixed vectors, sd/var consistency,
constant-vector degeneracy, mean/quantile/min-max bounds,
range/fivenum endpoints,
cor/cov symmetry and range, iqr
non-negativity), multibyte UTF-8 invariants for strcraft
(split/pad/trunc/repeat
round-trips and case-mapping idempotence over accented generators),
colcraft/stats DataFrame verbs
(arrange idempotence,
mutate-then-select, drop_na
subsets on date/NaN columns, distinct bounds), plus
integer-domain math and list-domain core
invariants. These properties are tight enough to have surfaced the UTF-8
case-mapping, byte-based regex, and nested-NSE-call bugs fixed
above.prop_gen_int_range / prop_gen_between now work
for spans of 2^30 and wider (e.g. the full 32-bit integer range) instead
of raising an internal RNG error.RuntimeError diagnostic instead of terminating the
process.[v, \(x) x])
shrink cleanly instead of aborting the shrinker.prop_gen_one_of shrinks inside its declared
values: counterexamples stay within the generator’s domain,
shrinking toward earlier values with the first value treated as
minimal.Error
returned by a prop_map_gen / prop_gen_fn
mapping now fails the run instead of being silently treated as a drawn
value.Datetime counterexamples shrink correctly
instead of overflowing a 32-bit intermediate.text is now treated as format-agnostic raw
bytes in serializer checks: shell nodes (runtime
sh) and capture = "stdout" nodes may consume
any producer format through $T_INPUT_<dep> without a
“serializer coherence error”, and typed nodes may read a shell node’s
raw text output with an explicit deserializer
(e.g. deserializer = [node: ^csv]). Previously, valid
pipelines combining a shell node with a
^json/^csv producer (or a typed consumer
reading a shell node’s output) were wrongly rejected by
build_pipeline, populate_pipeline,
pipeline_validate, and t check. A shell node
with multiple dependencies also no longer trips the “single deserializer
strategy” check.set_pipeline_global_options(pipeline, ...)
replaces the old side-effecting pipeline_options(). Returns
a new pipeline with defaults merged into every node; the original
pipeline is never mutated and no global state is used. Composes
naturally with pipeline transforms and the pipe operator. Duplicate
runtime keys in the functions dict concatenate all values
(e.g. [rn: "a.R", rn: "b.R"] includes both files).functions/include: env_vars,
args, and shell_args prepend global values
before per-node values (per-node dict keys win);
serializer, deserializer, shell,
and flake override every node’s per-node value entirely
(serializer/deserializer accept
^-prefixed names such as ^json);
dependencies prepends explicit dependencies before per-node
deps; and noop = true forces every node to
no-op while noop = false leaves per-node noop settings
untouched.runtimes,
nodes): Restrict the merge to a subset of nodes.
runtimes = ["rn"] targets R nodes;
nodes = ["n1"] targets exact node names; when both are
given the target is their union. Omitted scoping arguments target all
nodes, while an explicitly empty list (nodes = []) targets
none. An unmatched runtime or an unknown node name raises an explicit
TypeError instead of silently changing nothing.pipeline_node_options(pipeline, node)
read-back: Returns a Dict of a node’s fully resolved
configuration (runtime, serializer/deserializer, noop, deps, depth,
functions, include, env_vars, args, shell, shell_args, flake) after any
global-options merges. What you merge in with
set_pipeline_global_options, you can read back out.dependencies are now visible to the
build DAG: In addition to p_explicit_deps,
set_pipeline_global_options now writes globally-injected
dependencies into p_deps so they participate in build
ordering, depth computation,
pipeline_validate/pipeline_cycles cycle
detection, and pipeline_to_frame read-back. Self-references
(a node depending on itself via global deps) are filtered out to prevent
false cycles.explain +
pipeline_node_options)pipeline_config_to_frame(p): New
tabular config read-back. Produces a DataFrame with one row per node
covering resolved config values (serializer, deserializer, noop, shell,
flake), per-field provenance (scalar source markers + global/node count
columns for lists), and identity columns (name, runtime, depth,
command_type). Complements pipeline_node_options (Dict
detail) with queryable DataFrame-wide overview — e.g., “filter on
prov_serializer == \"global\" to find every node whose
serializer came from global options.”
Expanded mutate_node field
coverage: Now supports functions,
include, env_vars, args,
shell, shell_args, and flake in
addition to the existing
noop/serializer/deserializer/runtime/deps.
All new fields participate in provenance tracking so
pipeline_node_options correctly shows them as
"node"-sourced after mutation. Pass NA to
clear an optional or list field.
explain(p.node) shows source
provenance: The config section of
explain() output for a computed node now distinguishes
which settings came from global pipeline options versus the node itself.
pipeline_node_options(p, node) includes a machine-readable
provenance key ({ global: [...], node: [...] }
groups for mergeable lists; "global"/"node"
markers for scalar overrides), so tooling can audit where every setting
originated.
pipeline_node_options provenance
key: Mergeable options (functions,
include, shell_args,
dependencies) report both global and
node contributions; scalar overrides
(serializer, deserializer, shell,
flake, noop) report which source won; unset
scalars are NA.
pipeline_validate(p) reports all structural
errors: New shared validator
(pipeline_validation.ml) backs
populate_pipeline/build_pipeline, the
eval-time cross-runtime guard,
pipeline_validate/pipeline_assert, and
t check tier 1. Checks now include missing
function/include/script files, unknown runtimes (known set:
T, R, Python, Julia,
Quarto, sh, fetchurl), missing
dependencies, cycles, cross-runtime deserializer gaps,
serializer/deserializer format coherence across dependency edges,
multiple dependencies with a single deserializer strategy, and
^bin serializers on non-fetchurl nodes.t check tier 1 surfaces structural
errors: t check <file.t> (no Nix needed) now
reports these as structured
file_error/type_error/structural_error
diagnostics with a non-zero exit code, matching the build path’s
guarantees.pipeline_assert(p) throws the first
error and returns the pipeline unchanged when valid, for
guard-style use in pipeline chains.testcraft — Testing
Packageexpect_* functions: First-class
assertion primitives for T tests. Returns VExpect values
(Expect_pass, Expect_stop,
Expect_hold) that integrate with assert().
Covers equality (expect_equal), comparison
(expect_lt, expect_gt,
expect_lte, expect_gte), type checks
(expect_type, expect_true,
expect_false, expect_truthy,
expect_falsy), error handling (expect_error),
collections (expect_length, expect_nrow,
expect_ncol, expect_colnames,
expect_has_colnames, expect_unique,
expect_fields, expect_in,
expect_no_na, expect_empty,
expect_summary), pipelines (expect_pipeline,
expect_nodes, expect_dependency,
expect_runtime, expect_serializer,
expect_deserializer, expect_noop,
expect_computed, expect_has_pattern),
diagnostics (expect_warning), datasets
(expect_column_types, expect_values,
expect_range, expect_table_equal), and
string/comparison (expect_between,
expect_match, expect_str_contains,
expect_set_equal).check() builtin: Inline assertion
wrapper that prints true on success and preserves
VError on failure, suitable for pipeline node
commands.expect_equal performs order-insensitive, deep structural
comparison of Dicts with nested crash safety.Expect_pass
(comparison succeeded), Expect_stop msg (failed with
diagnostic), Expect_hold msg (NA involved, cannot
determine). assert() passes on Expect_pass,
raises AssertionError with the diagnostic message on
Expect_stop/Expect_hold.t test — Test
Runner Enhancementst test --json):
Structured JSON output (schema version 1) with per-file
status, duration_ms, and error
fields, designed for agent tooling and CI automation.t_test() returns a DataFrame: The REPL
function now returns a DataFrame with columns file,
status, duration_ms, and error
instead of printing pass/fail text. Use
t_test() |> filter($status == "failed") for programmatic
inspection.--only,
--not): Run a subset of tests by substring
matching. --only "stats" runs only tests whose path
contains “stats”. Multiple --only flags use OR semantics.
--not "slow" excludes tests matching “slow”.--format junit):
Machine-readable test output for CI/CD pipelines. Use
--format junit or combine with --json for JSON
output..tignore support: Create
tests/.tignore to automatically exclude test files. One
pattern per line, # comments, blank lines ignored.--json:
--json continues to work as shorthand for
--format json.--failfast: Stop running tests after
the first failure.--list: List discovered test files
without running them. Respects --only and
--not filters.--timeout SECONDS: Mark any test
exceeding SECONDS as failed. Does not interrupt execution — the test
runs to completion but is reported as a timeout failure.--coverage: Clean old
.coverage files, run tests, then generate a Bisect_ppx
coverage summary. Requires a coverage-instrumented build
(nix build .#t-coverage).t_test() filtering:
t_test(only = ["arithmetic"]) and
t_test(not = ["slow"]) for programmatic filtering from the
REPL.t test
now auto-evaluates pipeline definitions in test files and reports node
failures inline.test_*.t pattern in addition to test-*.t and
*_test.t.t test --coverage target directory
fix: Coverage cleaning and discovery now check both the project
directory and the current working directory for .coverage
files.t check now
compares type annotations (x: Int = expr) against inferred
types and emits Warning diagnostics for mismatches. Works
via the CLI t check and the REPL t_check()
function.(Int, String) -> Bool. Parsed, typechecked, and used for
lambda signature validation.infer_type now covers BinOp,
UnOp, IfElse, Match,
ListLit, DotAccess, and Lambda
return types. Division always infers Float; comparison
operators infer Bool.mutate
infers new column types from expressions; select narrows
DataFrame columns to the selected set; filter,
arrange, group_by, ungroup pass
through the base DataFrame type.types_compatible: Asymmetric numeric
matching — Int is compatible with Float
(relaxed widening), but not vice versa. Any matches
everything. TArrow compares structurally.t check
CLI & Structured Diagnostics Protocolt check <file>):
Structural pipeline validation without triggering Nix builds. Catches
parse errors, DAG cycles, dangling node references, arity errors, and
built-in name resolution. Exit codes: 0=clean, 1=wire error, 2=schema
error, 3=env error.t check --schema): Static column-name and type
propagation through the pipeline DAG. Validates column references
against inferred upstream schemas and reports type mismatches with
suggested fixes.--json):
Machine-readable output for all tiers, with schema_version,
status, phase, tier, and
per-diagnostic error_class (stable enum),
severity, expected, actual,
caused_by, and suggested_fix fields.
Breaking change: file and
span (with start and end) are now
nested inside the node sub-object. Designed for agent
tooling.suggested_fix now carries a confidence field
("high", "medium", "low")
computed from diagnostic context. Rename_column and
Suggest_identifier scale with edit distance and uniqueness.
Add_node_arg is always "medium",
Run_command always "low".t_check(file, json, schema, env) REPL
function: Invoke t check from within a T
session.t explain — Node
Introspectiont explain --node <pipeline>.t:<node_id>:
Prints a human-readable summary of a pipeline node’s inputs, outputs,
language, and dependencies. Supports --json for
machine-readable output (YAML front matter style with
node_id, language, inputs,
outputs, dependencies, and
command).t add — Package
& Tool Management CLIt add <runtime> <package>:
Adds a dependency to tproject.toml from the command line.
Supports R, Python, T,
Julia, and Quarto runtimes. Example:
t add R dplyr, t add Python quarto.--json flag for expression mode:
t run --json --expr 'expr' now correctly enables NDJSON
streaming output, matching the behavior of file-mode execution.t diff —
Content-Addressed Output Diffingt diff <file>: Compares two
builds of a pipeline using per-node Nix content hashes without loading
artifacts. Reports each node as unchanged,
changed, added, removed, or
errored.t_diff(file, json, log_a, log_b) REPL
function: Invoke t diff from within a T
session.diff_summary(p): Returns a DataFrame
of per-node diff status for the two most recent builds.t fix —
Mechanical Suggested-Fix Applicationt fix <file>: Runs
t check --schema, extracts diagnostics with
suggested_fix, and applies them mechanically. Supports
Rename_column (replaces $old with
$new in column references), Add_node_arg
(inserts missing arguments into node definitions), and
Rename_node (renames a colliding node name; skipped when
the node is referenced elsewhere in the file).t_fix(file, dry_run) REPL function:
Invoke t fix from within a T session.$col and $`col` forms, avoiding
corruption of identifiers like valid when renaming
id.target_node on
suggested_fix: Rename_column and
Add_node_arg fixes now include a target_node
field indicating which pipeline node the fix applies to.deserializer, t check now suggests adding
deserializer = ^csv via an Add_node_arg
fix.fetchurl serializer parameter:
fetchurl() now accepts a serializer argument
for pipeline mode, allowing explicit control over the download format
(e.g., serializer = ^text).t check Environment
Validationt check --env
now also generates pipeline.nix and dag.json
and validates them via nix-instantiate --eval. This catches
Nix expression errors (bad references, type mismatches) before a full
build.check_lockfile_consistency now includes packages resolved
via GitHub/GitLab entries in renv.lock, preventing
false-positive missing_from_lockfile diagnostics.--watch):
t check --watch runs immediately, then polls the input file
for changes and re-runs the check on every modification. Can be combined
with --schema and --env.docs/nix-installation.md): Platform-specific instructions
for Linux, macOS, NixOS, and WSL2. Includes Determinate Systems
installer, manual configuration for existing Nix installs, and Docker
container setup.configuration.nix snippets for trusted users, binary cache,
and flakes.rstats-on-nix Cachix cache on NixOS and non-NixOS
systems.t run --json
— Streaming NDJSON Build Diagnosticst run --json
emits newline-delimited JSON events to stdout as the pipeline builds,
enabling agents to react to the first failing node without waiting for
the entire DAG. Events: run_started (DAG manifest),
node_failed (error + inline log tail),
node_skipped (propagation), run_finished
(terminal summary with root_causes)._pipeline/logs/<node>.log during
execution, eliminating dependence on nix log <drv>
after the fact. The node_failed event includes the last 200
lines of the log inline.run_started DAG manifest: The first
NDJSON line carries the full pipeline DAG (node IDs, languages,
dependencies) so consumers can reason about root causes while the stream
is still open.root_causes at
run_finished: Root cause computation is deferred
to the terminal event, where the full picture is known. No provisional
guesses on node_failed events.--json.node_failed events classify error details in real-time
using in-memory log buffers without blocking the execution stream.
Captured log tails for stderr-detected errors are now complete and
include the exact failure details.node_failed events for the same failing node are prevented
during streaming.node_completed events at the end of the build, ensuring
that all successful nodes are represented.succeeded
count: The succeeded field in
run_finished now correctly represents the number of
completed nodes built from scratch, and no longer double-counts
cached nodes.%history: Display REPL session history
with line numbers.%save [filename]: Save session
transcript to a file.%reset: Clear all variables from the
session.%who [pattern]: List defined variables
with optional fuzzy name matching.%objects [pattern]: List defined
variables with type information and optional fuzzy matching.%magic: List all available magic
commands.write_parquet(data, path): Write a
DataFrame to a Parquet file via Arrow.diagnostics.summary not counting soft-failed nodes that
carry captured errors. Previously the SoftFailed error
class was overwritten with the raw error code string during log parsing,
making those nodes invisible to diagnostics. The original
VError class is now preserved correctly.t init --project now copies agent skill files (SKILL.md
templates) into .claude/skills/ and .opencode/
directories, providing ready-to-use AI agent context for new
projects.1e-5, 3.14e+2,
2.7E-3).\xHH): String
literals now support \x followed by exactly two hexadecimal
digits (e.g. "\x48\x69" → "Hi"), enabling
embedding of arbitrary byte sequences.Float.abs v < 1e-15) and Float.compare in
statistical packages (e.g., mean, sd,
lm), eliminating silent precision corruption.git ls-remote) and
dependency upgrade error handling to report specific system warnings and
write failures rather than generic error messages.flake named argument for pipeline
nodes: node(), rn(),
pyn(), jln(), qn(),
shn() and their shorthand variants now accept an optional
flake parameter to specify a custom Nix flake for that
node’s build environment.jbedo/rshells) to coexist with T’s project-level
serialization infrastructure.github:owner/repo, gitlab:owner/repo,
sourcehut:owner/repo, path:/abs/path, and
path:../relative/path.flake argument are unchanged — project-level environment
bindings are aliased so existing pipelines require no
modifications.jsonlite,
arrow, deepdiff, etc.) are now automatically
injected into both project-level and per-node flake environments at
build time, so users no longer need to explicitly list them in
tproject.toml.python3 if not found) and
receive only the automatically-injected serializer packages, ignoring
the project’s own package list or UV workspace.debug_node() Environment Isolation:
Fixed parent environment variables (like PYTHONPATH or
Nix-develop variables) leaking into debug_node() subshells
when debugging nodes with custom flakes. Subshells now run with clean,
isolated environments containing only essential Nix, dynamic linker,
locale, proxy, and terminal settings. Surfaced warnings to
stderr if the flake environment fails to load.[py-dependencies].resolver = "uv" and point
workspace at a locked UV project directory (default
"python"). When enabled, Python dependencies are declared
in pyproject.toml and locked via uv.lock
instead of [py-dependencies].packages.t update generates uv2nix/pyproject.nix flake inputs
(pyproject-nix, uv2nix,
pyproject-build-systems) and builds the Python environment
as a Nix virtual environment via pySet.mkVirtualEnv,
avoiding mixed dependency resolution between nixpkgs and PyPI.pyResolver from tproject.toml at build
time and emits the corresponding uv2nix environment (or falls back to
the nixpkgs withPackages path). Python pipeline nodes work
unchanged regardless of resolver choice.resolver = "uv"
and packages simultaneously is rejected with a clear error.
Only "nixpkgs" and "uv" are valid resolver
values.uv2nix Commit: Pinned the
default uv2nix input URL to a specific, reproducible git
commit hash (102cb1ffb47c9f722633e947137f578874ea34cd) via
a compile-time constant rather than using a floating branch
reference.[r-dependencies].resolver = "renv" to auto-discover R
dependencies from renv.lock. CRAN packages from
Repository/Bioconductor entries are mapped to
pkgs.rPackages.*, and GitHub/GitLab packages are fetched
via builtins.fetchGit using RemoteHost,
RemoteUsername, RemoteRepo, and
RemoteSha fields.Remotes
field in renv.lock entries is parsed — user/repo strings
are matched against packages in the lock file and injected as
buildInputs of the declaring git package. Supported remote
hosts: api.github.com and gitlab.com. Other
sources produce a warning and are skipped. Base R packages
(R, methods, stats, etc.) are
automatically filtered out.[r-dependencies] (e.g.,
my_pkg = { git = "https://...", rev = "full-sha" }) and are
merged with renv-discovered git packages when using the renv
resolver.r_renv_cran_pkgs and r_git_pkgs at build
time, generating the appropriate Nix expressions for renv-discovered
CRAN packages alongside the traditional rPackagesList in
every R environment (mkNodeEnv and
projectREnv).resolver = "renv" is set, the dependency checker merges
renv.lock CRAN packages into the analysis so requirement checks pass
without an explicit packages list in
tproject.toml.fetchurl(url, sha256, output, dest):
Downloads a file from a URL with reproducibility guarantees. In REPL
mode, uses curl to download (optional
output/dest for the save path). In pipeline
mode, generates a builtins.fetchurl Nix derivation with the
required sha256 hash for content-addressable caching. The
downloaded artifact is accessible at p.node_name.path after
building.prefetch(url): Downloads a URL and
returns its SHA-256 hash, usable as the sha256 argument to
fetchurl. Enables a two-step workflow: compute the hash
upfront, then pin it in a pipeline for reproducible builds.rstats-on-nix/nixpkgs snapshot date in
RSTATS-NIX-DATE to 2026-06-22 along with the
corresponding hash updates in flake.nix. Added fixes to the
rstats-on-nix/nixpkgs fork to permanently disable checks
for django, twisted, sh,
fsspec, pyogrio, and httpcore
directly in their derivations (preventing build failures on
aarch64-darwin and during source compilation), and
integrated the upstream air-formatter package patch for
cargoBuildFlags compatibility. This allowed the local
python package overrides in flake.nix to be cleaned
up.rstats-on-nix/nixpkgs fork, allowing the local
postPatch overrides in flake.nix to be
simplified..github/workflows/test-build.yml for manual matrix builds
and adopted the wimpysworld/nothing-but-nix GitHub Action
to optimize disk space usage during CI runs.set_seed(seed): Initialize the global
RNG for reproducible random draws.sample(x, n = 1, replace = false):
Randomly sample elements from a Vector or List, with or without
replacement.slice_sample(data, n = 1, replace = false):
Randomly sample rows from a DataFrame, with or without replacement.set_seed() guarantees identical output across runs.qnorm(p, mean = 0, sd = 1): Normal
distribution quantile (inverse CDF), using Acklam’s algorithm.qt(p, df): Student t distribution
quantile, via binary search on pt.qf(p, df1, df2): F distribution
quantile, via binary search on pf.qchisq(p, df): Chi-squared
distribution quantile, via binary search on pchisq.jpmml-evaluator library (used for PMML model
scoring). The nixpkgs fetch source hash has been updated to restore
local build compatibility.Fix for https://github.com/b-rodrigues/tlang/issues/434
jpmm-statsmodels PR is not yet merged into NixOS/nixpkgs master branch, so it’s included in the rstats-on-nix fork. It seems like the Maven dependencies got cahnged after release so compilation was failing. This also means that previous releases of T are likely not installable anymore.
with_tz() and force_tz() now correctly apply
timezone offsets via POSIX localtime_r, supporting full
IANA timezone names (e.g. "Europe/Paris",
"America/New_York").to_factor on all-NA input now preserves factor metadata
(levels, ordered) through the Arrow round-trip, keeping the native Arrow
path active across data cleaning pipelines.VNA variants (NAInt, NAFloat,
NADate, NADatetime, …) now set the
corresponding type flag in values_to_column, so all-NA
columns route to the correct typed Arrow column
(e.g. IntColumn, FloatColumn) instead of
always falling back to NAColumn. Added
NADatetime variant to disambiguate datetime NAs from date
NAs.lag and
lead now inspect the input vector’s element type and use
the appropriate typed NA variant for fill positions
(e.g. NA(Int) for integer vectors, NA(Float)
for float vectors).group_by + summarize and typed NA for
Date/Datetime null cells in pivot_wider and
expand.get() data-mask awareness:
get("name") inside NSE data verbs (mutate,
filter, summarize, …) now checks the data mask
before the global environment, enabling dynamic column name
resolution.This release:
t init --project and t init --package now
accept --include-atelier (CLI flag) to configure the IDE in
the project environment. When running inside an active Atelier session,
the REPL automatically updates variables, writes diagrams/plots to the
_atelier/ directory, and runs a protected variables watcher
via the new tui_update builtin. Atelier can also be
declared as a project dependency via [additional-tools] in
tproject.toml.node_when(condition, node_value) and
node_fork(...) allow conditional node inclusion evaluated
at pipeline construction time, preserving Nix’s static DAG
requirement.map_pattern(dependency): Maps a node over each element
of a List, Vector, or DataFrame dependency.cross_pattern(sub_pattern1, sub_pattern2, ...):
Generates a Cartesian product of multiple map_pattern
sub-patterns.slice_pattern(dependency, indices): Creates branches
selecting specific element indices.head_pattern(dependency, n) /
tail_pattern(dependency, n): Restricts branches to the
first or last n elements.sample_pattern(dependency, n): Randomly samples
n elements from a dependency (with deterministic seed
behavior).expand_pipeline: Adds the built-in
function expand_pipeline(p) to manually expand dynamic
patterns into separate <node>_branch_<N>
nodes.build_pipeline() and populate_pipeline().
Attempting to build/populate a pipeline containing unexpanded patterns
raises a compile-time StructuralError._branch_N are strictly forbidden in
manual definitions to prevent namespace clashes. Duplicate node
detection and branch-aware read_node errors assist in
identifying naming conflicts.pipeline_to_ga: Adds
pipeline_to_ga(p, ...) to generate a complete GitHub
Actions CI workflow YAML. The generated workflow automates Nix-based
pipeline runs on push/PR events.rstats-on-nix cache) and automatically
manages the caching of built Nix artifacts using a repository’s
t-runs branch (archived as .nar files).file parameter to write the workflow YAML directly to
.github/workflows/<name>.yml (defaulting to
auto-detected project names).pipeline_report: Introduces
pipeline_report(p, ...) to generate structured Markdown
(target = "ssh") or HTML (target = "web")
execution reports.which_log
regex parameter to report on historical run records.float_seq: Adds the
float_seq(start, end, n) built-in function to generate a
List of n evenly-spaced floats.{ ... }) no longer silently swallow errors occurring
inside assignment/reassignment statements. The error is bound to the
variable and propagated correctly, enabling robust recovery patterns via
subsequent match blocks.This release:
pipeline_of), first-class artifact export/import
capabilities, meta-pipeline graph visualization, interactive Mermaid
browser rendering, and cache-aware dry runs with programmatic garbage
collection.{ ... }) now abort immediately on encountering a
VError from a bare expression, preventing silent error
accumulation. However, VError values from
Assignment and Reassignment statements no
longer abort the block — the error is bound to the variable and
subsequent statements (typically a match) can handle it.
This enables patterns like
{ x = 42 / 0; match(x) { Error { msg } => 0, default => x } }
where a risky computation is captured and recovered.VError now conditionally fall back to
binary serialize/deserialize rather than
triggering configured custom serializers (like Arrow), preventing
crashes.get_pipeline_member function no
longer eagerly evaluates T expressions when a pipeline is accessed.
Evaluation is deferred to rerun_pipeline at build time via
build_pipeline(). This eliminates redundant re-evaluation
cycles, improves performance for large pipelines, and avoids side-effect
leakage from unbuilt nodes.p.p_nodes instead of
p.p_exprs for identifying resolved nodes from other
pipelines, improving accuracy of dependency inference.build_pipeline(p), downstream nodes now automatically
inherit warnings from ancestor nodes.
warning_msg(downstream) shows warnings with source
provenance
("Ancestor node '<name>' reported following warning: <message>").
Multiple warnings (own + upstream, or from multiple ancestors) are
joined with ". Furthermore, ".inspect_node now shows warnings:
inspect_node(node) returns a warnings field
with a structured list of dicts (source +
message), showing both own and inherited upstream
warnings..warnings from read_node()
return: The .warnings field on
read_node() results has been removed. Use
warning_msg(node) for a formatted warning message or
inspect_node(node).warnings for structured warning
metadata.read_past_node(p.node_name, which_log):
New NSE-captured function to read a pipeline node from a specific
historical build log without the pipeline being in scope. The first
argument is captured before evaluation, so
read_past_node(base_p.raw, which_log = "qcfs") works even
when base_p is not defined. which_log is
mandatory — no default.read_node: The
which_log parameter has been removed from
read_node. Use
read_past_node(p.node_name, which_log = "...") for
historical reads, and read_node(p.node_name) for in-scope
pipeline reads.pipeline_name on
build_pipeline:
build_pipeline(p, pipeline_name = "my_name") now records
the pipeline name in the build log JSON ("pipeline" field).
list_logs() shows a new pipeline column for
disambiguation.pipeline_summary and
pipeline_dot: These convenience aliases have been
removed. Use pipeline_to_frame(p) instead of
pipeline_summary(p), and pipeline_to_dot(p)
instead of pipeline_dot(p). pipeline_to_dot
also handles MetaPipeline.pipeline_to_dot(p, title = na()):
Generates a Graphviz DOT representation of the given pipeline or
meta-pipeline. New optional title parameter auto-detects
the project name from tproject.toml (fallback: none).
Renders as label= in the digraph header.pipeline_to_mermaid(p, title = na(), flatten = false):
Generates a Mermaid flowchart diagram string from the pipeline topology.
New optional title parameter auto-detects from
tproject.toml; new flatten parameter (default
false) renders meta-pipelines as grouped subgraph blocks —
set to true for flat output.---\ntlang-title: ...\n---), visible in the HTML
<h1> via show_plot() but silently
ignored by Mermaid.js to avoid in-diagram title duplication.#ffced0 to #859900 (green) for a cleaner
visual appearance in generated graphs.show_plot:
show_plot(p) now accepts a pipeline or meta-pipeline
directly — it calls pipeline_to_mermaid internally, renders
the DAG as an interactive HTML page, and opens it in the browser.
show_plot(mermaid_string) also renders arbitrary Mermaid
diagram strings.read_node “Did you mean” hint: When
read_node receives a bare symbol
(e.g. read_node(ha) instead of
read_node(p.ha)), the error now suggests the correct form:
Did you mean read_node(p.ha)?read_node error messages: All
non-ComputedNode argument errors now follow a consistent
format guiding the user to build the pipeline first, use dot access, or
use read_past_node for historical builds.export_artifacts: Support
exporting cached Nix artifacts for individual nodes, sub-pipelines,
meta-pipelines, or lists/dictionaries of nodes/pipelines.import_artifacts: Support
both 1-argument import_artifacts(archive_path) (direct Nix
store import) and 2-argument
import_artifacts(target_val, archive_path) (import and
verify paths) calling signatures.inspect_artifacts(archive_path):
Import archive into a temporary, isolated Nix store and return a
DataFrame containing the included nodes, store paths, hashes, sizes in
bytes, and reference basenames without affecting the local store.import_artifacts,
export_artifacts, and inspect_artifacts.populate_pipeline(p, dry_run = true) and
build_pipeline(p, dry_run = true) now perform a dry run via
Nix (--dry-run), parsing the plan to report which nodes
will hit the local cache ("cached"), rebuild
("build"), or fetch from remote substituters
("fetch"), returning the results as a DataFrame.pipeline_gc(p, dry_run = true): Deletes the store paths
of the given pipeline p if safe. By default
(dry_run = true), it returns a DataFrame previewing the
nodes, store paths, and deletion eligibility status. Set
dry_run = false to execute the deletion.t_gc(): Triggers a global Nix garbage collection
(nix-store --gc) directly from the REPL to safely clean up
old, detached derivations.pipeline_of block: A new combinator
that composes multiple pipelines into a higher-order DAG. It allows you
to define relationships between sub-pipelines in a declarative way,
enabling complex, multi-stage workflows.etl.clean in the stats pipeline) to infer the
execution order between sub-pipelines. No manual depends
configuration is required for the flattening engine.meta_flatten
combinator automatically flattens meta-pipelines at execution time. When
a meta-pipeline is populated, queried, or inspected, T-Lang
automatically flattens it internally. This flattening is done on-demand,
so you don’t need to manually flatten meta-pipelines.etl.raw, etl.clean,
stats.summary) to prevent namespace collisions, and all
internal variable references are rewritten accordingly.p_etl.raw) are
automatically rewritten to their namespaced equivalents (e.g.,
etl.raw) during the flattening process.pipeline blocks (e.g.,
\(multiplier) pipeline { ... }) are now fully supported.
Outer variables referenced inside the pipeline nodes are automatically
substituted with their concrete values during compilation, producing
fully independent and Nix-reproducible pipelines.# Define multiple pipelines
p_etl = pipeline { ... }
p_stats = pipeline { ... }
# Compose into a meta-pipeline
meta = pipeline_of {
etl = p_etl
stats = p_stats
}
# Built-in commands automatically handle meta-pipelines
populate_pipeline(meta, build = true)
read_node(meta.stats.summary)
inspect_pipeline(meta)
meta_graph = pipeline_of {
raw = pipeline {
src = read_csv("raw.csv")
}
cleaned_a = pipeline {
a = clean(raw.src)
}
cleaned_b = pipeline {
b = clean(raw.src)
}
summary = pipeline {
val = summarize(cleaned_a.a, cleaned_b.b)
}
}
# T-Lang automatically infers the execution order:
# raw -> {cleaned_a, cleaned_b} -> summary
populate_pipeline(meta_graph, build = true)
meta_flatten combinator is not exposed as a
first-class function in the CLI or T-Lang AST. It is an internal
implementation detail of the pipeline engine that is automatically
invoked when working with pipeline_of.fivenum, ensuring parity with R’s
fivenum() output.Float.erfc, improving tail accuracy.t_quantile recursive to handle edge cases in quantile
computations correctly.ss_res formula used in leave_one_out_sigma
calculation in lm.ml.cut to
output spaces-free labels formatted with %g format,
matching R’s cut() label style.3.0 == 3) and improved
pnorm accuracy using Float.erfc.VFactor and VString values.read_csv to parse empty strings as NA with
allow-null-strings, and implemented proper dataframe
comparison semantics.jsonlite::write_json to serialize floats at full precision,
preventing rounding-induced mismatches.NA values as JSON
null for correct round-tripping.node.sub.field) in Nix dry-run evaluation expressions.pipeline_to_mermaid to prevent
collisions from similar node names.inspect_artifacts, and restored scalar
TypeError for invalid inputs.NixError fallback behavior for empty trimmed
last_part in builder_internal.ml.__node_result across all
runtimes), fixed R variable naming compatibility (dep_
prefix), and corrected dependency namespace generation.rename_node updated the assoc-list key in
p_nodes but left VComputedNode.cn_name
unchanged, causing downstream lookups (resolved_cn,
computed_node_resolver, read_node) to search
using the stale name and fail with <unbuilt> path
errors.The entire OCaml codebase underwent a systematic safety review following best practices for ML-family languages:
Option.get, bare List.hd on unvalidated lists,
and similar partial operations.match expression across ~100 files was audited and made
total, removing partial wildcard patterns where feasible.failwith, raise, and assert false
in user-facing code to structured VError returns.Float.compare..mli
interface files with abstract types for Arrow,
GroupedTable, and key FFI modules.AGENTS.md as a permanent reference for future
contributions.This release introduces interactive pipeline node debugging via
debug_node, native Nix orchestration features for granular
rebuild control, job parallelisation, Cachix binary caching, and
dry-runs, and the temporal introspection pair
build_log_history and node_diff for tracking
how pipeline outputs change across builds.
Status: Beta
debug_node(p.node)): Introduces a new built-in
function to drop developers directly from the T REPL into a sandboxed
guest REPL (Python, R, or Julia) to step through and debug code using
actual upstream outputs.py>, r>,
jl>) to cleanly signal that you are in a debugger
subshell session, returning immediately to the T REPL upon exit.p_env_vars) are programmatically inherited by the subshell
process.ValueError for unsupported runtimes
(like Quarto or Bash).debug_node(), running R, Julia, or Python directly inside
the development shell started via nix develop will
automatically intercept and block imperative package mutations
(install.packages(), Pkg.add(),
pip install, poetry, uv,
conda, python -m pip, etc.). Running these
commands displays a helpful instruction directing developers to declare
dependencies in tproject.toml, run t update,
and re-enter nix develop, protecting the workspace from
drift and preserving reproducible Nix derivation footprints.build_log_history(p, n = NA)): Exposes the
historical record of builds matching the current pipeline signature as a
sorted DataFrame, ordered from most recent to oldest. Uses the 1-indexed
build_rank convention (where 1 represents the
most recent build, 2 the second most recent, etc.).node_diff(node_a, node_b, log_a = "latest", log_b = "latest")):
Compares outputs of a specific node across two historical builds
(defaulting to the most recent vs. second most recent). Implements
type-sensitive comparison strategies:
diff -u to extract
precise line additions, removals, and diff summaries. Includes a robust
fallback if system tools are sandboxed or missing."default"/"tobj" Deserialization:
Fixed a major correctness bug in read_standard_node_value
where scalar nodes serialized with "default" or
"tobj" formats were not being deserialized when queried via
standard readers, returning a fallback VComputedNode token
instead. Standard readers now correctly deserialize value payloads (like
VInt, VFloat) using OCaml’s Marshal digestion,
enabling precise cross-node value and delta comparisons.targets, force, dry_run,
max_jobs, and cache parameters in
build_pipeline and pipeline_run.targets): Map
targets to -A <derivations> in the
underlying nix build command, allowing specific parts of
the pipeline to be built selectively.force): Map
force to native --check flags. Pass
true to force-rebuild the entire pipeline, or a string/list
of specific node names to force-rebuild only selected steps.max_jobs):
Mapped the max_jobs parameter directly to
--max-jobs <N>, enabling parallel compilation of
sandbox environments and derivations.cache):
Seamless Cachix binary cache integration by dynamically configuring
extra-substituters and
extra-trusted-public-keys (prioritizing
rstats-on-nix as the preferred default cache).dry_run):
Implemented a native dry-run mode that parses
nix-build --dry-run output into a structured T-Lang
DataFrame (containing columns node,
action, path) to inspect build execution plans
without mutating local store state.update_pipeline_with_build_paths) that reconciles
internal ComputedNode paths with the real store paths
generated by Nix.t doctor
Pipeline Dependency Analysist doctor now parses src/pipeline.t and
statically analyses each node’s command block to detect
runtime packages (library(...), import ...,
using ...) that are referenced but absent from
tproject.toml. Missing packages are reported as warnings
with an actionable suggestion to add them to the relevant
[r-dependencies], [py-dependencies], or
[jl-dependencies] section and run t update.
All pipeline definitions in the file are scanned, not just the first
one.src/pipeline.t found) is only emitted when the
project has at least one runtime dependency declared, avoiding noise for
pure R or Julia package projects.test_pipeline.ml to verify dry-run
DataFrame output, validation guards, and advanced parameter passthroughs
(2271/2271 tests passing).docs/pipeline_tutorial.md and
docs/api-reference.md to formally document the new
parameters, along with comparative command mapping tables.populate_pipeline() to support all the new Nix
orchestration arguments (targets, force,
dry_run, max_jobs, cache) in the
exact same manner as build_pipeline().targets and force
node lists in the OCaml pipeline compiler. T-Lang now instantly detects
misspelled or nonexistent node targets and raises highly readable
StructuralError warnings before spawning the Nix
interpreter.model) would erroneously match long node name store
paths (e.g. model_evaluation).node_diff improvementsnode_diff now splits the values
on newlines and produces a proper unified diff with context lines — the
same colourised format already used for text-file nodes. Calling
detailed_summary on the result shows added/removed lines
highlighted in green and red.NaN / NA handling in
DataFrames: Cells that contain NaN or
NA on both sides are no longer incorrectly reported as
changed.key that does not exist in one of the DataFrames,
node_diff now raises a clear error immediately instead of
silently producing wrong counts.node_diff requires ComputedNode
arguments: node_diff now enforces that both
arguments are pipeline node references
(e.g. node_diff(p.my_node, p.my_node)). Passing a plain
string or pipeline object raises a descriptive
TypeError.explain()
— Unicode display→, emoji, …) are displayed as-is in the REPL and inside
explain() tree output, instead of being shown as raw byte
sequences such as \226\134\146.This release finalizes end-to-end Julia ONNX serialization support, fixes pipeline compiler strategy dictionary parsing issues, strengthens runtime safety by protecting reserved keywords, and completes the migration of pipeline introspection to a strict, node-centric dot-access model.
Status: Beta
read_node() to strictly require ComputedNode
arguments (e.g., read_node(p.node_name)), disallowing
legacy string lookup paths.read_node OCaml resolution to prioritize the in-memory
registry (Ast.in_memory_node_values) over disk-based build
log artifacts, resolving transient FileError omissions when
accessing unbuilt or dynamically computed nodes.build_pipeline()
execution, instructing users how to read, inspect, and summarize their
pipeline using their actual variables and first-class node objects.t_demos workspace and workflows (79+ scripts and workflows)
to adopt the new strict dot-access design. Standalone helper scripts are
now automatically self-contained with explicit
import 'src/pipeline.t' prepends.build_log(p)):
Expose the underlying Nix build results as a VBuildLog
record containing node-by-node details, total duration, and a list of
failed nodes. build_pipeline(p) now returns a
BuildLog value instead of a raw output-path string (use
build_pipeline(p).out_path when you need the previous path
value).build_log_to_frame):
Added build_log_to_frame(log) to tabulate build results
(one row per node) for high-level analysis using colcraft
verbs."Pending" or
"Building" states to "Skipped" when the
nix-build process crashes/fails, avoiding confusing out-of-date
states.VBuildLog stringification and REPL pretty-printing to
dynamically count and print all status types
(e.g. 2 succeeded, 9 failed, 3 skipped) rather than
assuming a simple binary success/failure count.collect_exceptions(p)): Gathers all
VError values and warning diagnostics from computed nodes
of a built pipeline into a structured DataFrame (node,
status, code, message), replacing
the legacy collect_errors and error_summary
functions.collect_exceptions(p): Automatically cleans and
extracts the last non-empty line of multi-line error traces (such as
from Python or Arrow exceptions) and truncates the string to 100
characters max, maintaining a neat, legible table in the REPL.error_code(), error_msg(), and
error_context() builtins polymorphic. They now accept
either standard Error objects or first-class pipeline
ComputedNode values (e.g. p.X or
p.combined_df). They automatically resolve the node’s
underlying VError store artifact for soft-failures, or fall
back to parsing log traceback details for hard Nix-build failures.warning_msg() and a matching
.warning_msg property lookup on computed nodes to easily
inspect non-fatal build warnings from successful derivations.t_make():
Upon early termination/build crash, the Nix builder scans the store
paths of completed upstream nodes to extract soft-failed diagnostic
states, printing them directly in the final build failure summary
(e.g. showing (8 captured errors) and listing their node
names).35 characters to
32 characters followed by ... to keep columns
aligned and clean.error_chain(err1, err2)): Chains multiple errors
to preserve failure provenance and causality across dependent
nodes.build_log, print, mean, etc.) are
now strictly protected against accidental user reassignment or
overwriting.= or the
overwrite operator := will raise a highly visible
NameError
(e.g. Cannot overwrite build_log: it's a reserved keyword!).mean)
in their package scope without conflict.:Cast (pass-through identity) and
:Reshape (handling inferred -1 shapes mapping
to Julia Colon()) operators.Base.invokelatest to resolve world age lexical
method updates in isolated Nix builds.Umlaut dependency into [jl-dependencies] and
corrected column-major tracing dimension layouts.nix_emit_node.ml
(get_format) and builder_populate.ml
(extract_format) to correctly parse
VSerializer values inside pipeline deserialization mapping
dictionaries (e.g.,
deserializer = [ julia_model: ^onnx ]).onnx_julia_stress_t and
observability_hardening_t end-to-end stress test suites to
verify prediction parity, safety safeguards, and observability
logs.jn() alias: Eliminated the
undocumented jln() alias jn() from the
evaluator, tests, and all documentation. Use jln()
exclusively for Julia pipeline nodes.Returns docs:
All node-defining functions (node, rn,
pyn, jln, qn, shn)
now correctly document their return type as a NodeDef
pipeline node configuration object, not the evaluated result of the
enclosed code. The code is executed by build_pipeline(),
not immediately.jln serializer default:
Documentation previously stated the default serializer was
^csv; the actual default is the runtime-native binary
serializer (jl_serialize), consistent with rn
and pyn.The focus of this release is the introduction of first-class Julia support, enabling high-performance polyglot pipelines with seamless Julia integration.
Status: Beta
jln):
jln() for executing Julia code directly
within T pipelines.tproject.toml via the [jl-dependencies]
section.^pmml serializer.JavaCall.jl
integration.^onnx serializer.ONNXRunTime.jl for industry-standard
inference performance and ONNX.jl for model
serialization.MethodError: method is too new).Base.invokelatest.Flux.jl or Zygote.jl) remains accessible
within the same execution cycle, even in restricted environments like
the Nix build sandbox.JSON package in Julia nodes, enabling seamless JSON-based
data exchange for Julia-based pipeline steps.show_plot() now supports Julia plots via
TidierPlots.jl, Plots.jl, and
Makie.jl.Makie.jl
objects, CairoMakie is the mandatory backend for
reproducible headless rendering within the Nix sandbox. Ensuring
CairoMakie is in [jl-dependencies].packages is
required for successful visual inspection of Makie nodes.read_node Helpers: Introduced
lightweight packages for R, Python, and Julia (all named
tlang) to simplify consumption of T-Lang build artifacts
from external runtimes.pipeline_nodes() to all companion packages. It returns the
pipeline DAG as an idiomatic data structure (e.g.,
data.frame in R, dict in Python/Julia),
enabling easy programmatic traversal of node relationships.path: field from the default
ComputedNode REPL printer.path: <unbuilt> / path: status lines for
ComputedNodes; users who need explicit artifact paths in
the T runtime can obtain them via inspect_node(node).path
or inspect_log().return_path in Companion
Packages: Added return_path argument to
read_node() in the R, Python, and Julia companion packages.
When set to true, these helpers return the absolute path to the artifact
in the Nix store/project directory instead of deserializing it, allowing
for custom loading logic or direct file inspection.build_log_*.json in
the _pipeline/ directory, providing a stable way to access
node results during development and reporting (e.g., in Quarto). ###
Strict Serialization & Pipeline Stability^ symbols for node serializers and
deserializers (e.g., serializer = ^arrow).TypeError during evaluation,
eliminating a common source of pipeline configuration drift.write_arrow to surface detailed
VError traces instead of failing silently.dataframe as a core standard package,
ensuring stable resolution during Nix builds and preventing “package not
found” errors in isolated environments.to_factor was being incorrectly
emitted; now correctly uses the standard R factor() for
native R-node interoperability. ### API Standardization &
Ergonomicsto_ Naming Convention:
to_ prefix:
as_date() → to_date()as_datetime() → to_datetime()as_factor() / factor() →
to_factor()sym() → to_symbol()dataframe() → to_dataframe()str_string() → to_string()as_* and shorthand aliases
(fct(), fct_infreq() →
to_factor(..., ordered=true) etc.) to ensure a single,
canonical API path.augment() renamed to add_diagnostics() for
better clarity and consistency with the T-Lang philosophy of descriptive
names.to_string() now provides a unified interface for string
conversion across all T types, including proper level resolution for
Factors and recursive formatting for Lists and Vectors.fct() shorthand in favor of the
standardized to_factor().to_factor() now consistently
uses alphabetical sorting for derived levels, removing the previous
“first-appearance” behavior to align with industry standards and
internal consistency.augment() to add_diagnostics() to
better reflect its purpose of appending model-level diagnostics
(residuals, hat values, etc.) to data frames.broom::augment outputs.t_demos to adopt the new standardized API.The focus of this release was to improve language ergonomics for data guardrails, enhance package manager feedback, and increase test coverage across all packages.
Status: Beta
nest() and unnest() operations to eliminate
OCaml-side materialization bottlenecks.GroupedTable to use gint64 row
indices, enabling direct bulk transfer of group subsets to Arrow.merge_horizontal), enabling efficient
expansion of key columns during unnesting.t update feedback to explicitly report counts
for R, Python, Additional Tools, and LaTeX packages being synchronized
to flake.nix.get():
Enhanced the get() primitive to support default value
fallbacks. It now handles:
get(potential_error_or_na, default): Returns the
default if the first argument is an error or NA.get(target, selector, default): Returns the default if
the retrieval from the target fails.get(s.min_age, 0) >= 0, which gracefully handles missing
columns or empty summaries.generate_onnx.py compatibility with scikit-learn
1.6+ and ensured numeric output parity for classification models.1e-2 to preserve
cross-runtime stability without masking meaningful regressions.cv,
fivenum, trimmed_mean, mad,
iqr, range, var, and
cov against R baselines.skewness and kurtosis (excess kurtosis) using
population-moment calculations.pnorm (standard normal approximation), pt,
pf, and pchisq CDFs.winsorize, huber_loss, normalize,
and Pearson cor against R reference values.weights argument for lm()
to support Weighted Least Squares (WLS) regression.mean,
sd, var, cov, cor,
median, quantile, iqr,
fivenum, trimmed_mean, skewness,
and kurtosis.standardize and scale using
iris$Sepal.Length.coef, conf_int, sigma,
nobs, and df_residual for linear models.builder_utils.ml and test_misc_coverage.ml.
Switched to Unix.realpath for canonical path resolution on
macOS (handling /var vs /private/var) and
ensured GNU utilities are explicitly used via Nix environment
wrappers.X to float_input to match
scikit-learn 1.6+ exports.model_type
and mining_function metadata into lm and
PMML-loaded model objects. This ensures that fit_stats()
returns complete, R-compatible diagnostic tables without NA
placeholders for model categories.anova: Updated the
anova builtin to support model labels (e.g.,
anova(m1 = m1, m2 = m2)). The labels are now preserved in
the resulting DataFrame, matching R’s behavior in model comparison
tables.normal_quantile,
t_quantile) where tail approximations were incorrect,
leading to broken confidence intervals. Implemented high-precision
Acklam’s algorithm for normal quantiles and accurate Cornish-Fisher
expansion for t
quantiles.onnxruntime CPU vendor warnings in the golden test suite
and standardized the “✓” success indicator across all statistical test
scripts.base package
builtins, specifically targeting error handling, NA container logic, and
serialization.is_na
vectorization across Vectors and named Lists.serialize, deserialize,
t_write_json, and t_read_json, including
type-mismatch and file-system failure scenarios.core package builtins,
including args, help, apropos,
and write_text.args() builtin on both builtins and lambdas, ensuring
correct parameter name and type extraction.identical (deep equality), sum (edge cases),
seq (auto-descending ranges), and
head/tail (slicing boundaries).ifelse, case_when, and
identical (t_boolean.ml), get with all lens
types (t_get.ml), and all specialized rendering paths in
pretty_print.ml.fill, replace_na, complete,
relocate, count, slice,
unnest, separate, and uncount.
Verified downup direction logic and regex error
handling.pretty_print.help() and
apropos().lens
package, focusing on custom lenses, pipeline orchestration, and
recursive mapping.get and set
functions.node_meta_lens for serializer and
deserializer fields, and filter_lens for batch
updates to pipeline node values.col_lens and idx_lens across nested Lists of
Vectors and DataFrames.modify()
builtin.Functionlengthexpects...).packages.t-coverage Nix output for simplified code coverage
collection.bisect-ppx-report within the coverage derivation to
streamline local reporting workflows.Status: Beta
small, medium, full,
huge).huge reference generation: Implemented
a recursive build process in docs/build.sh that
concatenates the entire documentation ecosystem into a single,
comprehensive reference for high-context agents.t init to be fully interactive. The CLI now
prompts for the AI Agent Context Level during project
or package initialization.AGENTS.md: Automatically generates
project-specific onboarding guides for LLMs based on the workspace
type.T-LANGUAGE-REFERENCE.md in the project root and
automatically added to .gitignore.README, Getting Started, and
LLM Collaboration guides to emphasize T’s unique support
for agentic development.$param):
$param syntax in lambda and
function() parameter lists.$ automatically capture bare
names (like column names) as Symbols rather than
evaluating them.enquo() in simple forwarding cases.get() and New to_symbol()
Builtin:
to_symbol() core builtin for programmatic
symbol creation.get() dispatcher across core
and lens packages, ensuring a single, stable interface for
variable lookup, collection indexing, and lens-based retrieval.lens package is
loaded.StructuralError Category:
StructuralError as a new terminal diagnostic code
for fundamental pipeline orchestration failures.StructuralError.populate_pipeline (e.g., missing dependencies in
tproject.toml, missing Nix build tools, or stalled artifact
directories) now emit StructuralError.StructuralError as a
terminal event that bypasses “Resilient-by-Default”
(resilient=true) settings.1 / 0).TLANG_AUTO_ADD_PIPELINE_DEPS environment variable.StructuralError
instead of implicitly continuing into a broken Nix state.unbuilt states instead of resolved values in complex
dependency graphs.MissingArtifactError in the lens
system to provide precise feedback on unbuilt dependencies during lazy
evaluation.get() when targeting
plotting nodes, ensuring metadata dictionaries are returned
predictably.ggplot2 objects.matplotlib figures,
plotnine (ggplot-style), seaborn grids,
plotly figures, and altair charts.show_plot() Builtin:
show_plot() to render and open pipeline plot
artifacts locally.ggplot2), Python
(Matplotlib, Seaborn, Plotly, Altair, Plotnine), and Julia
(TidierPlots.jl, Plots.jl,
Makie.jl via CairoMakie) plots within the Nix
sandbox.kaleido) and Altair (via
vl-convert).tlang now
automatically suggests or injects cloudpickle when plotting
libraries are detected in Python nodes to ensure reliable serialization
of complex objects containing lambdas.read_node() for Plots:
read_node() now recognizes nodes of class
ggplot, matplotlib, plotnine,
seaborn, plotly, altair,
tidierplots, plotsjl, or
makie.VLens sum type.get() Integration: The
get() builtin now natively supports VLens for
data focus, providing a single, consistent interface for variable
lookup, indexing, and lens-based retrieval.get(), to_symbol(), and related
primitives.t_doc("parse") and t_doc("generate") workflows
for extracting and publishing reference pages for new core
functions.docs/language_overview.md and
docs/quotation.md with comprehensive examples of the new
$param auto-quoting feature.editors/tree-sitter-t.<{ }>
blocks when used inside rn(), pyn(), or
shn() calls (supporting both named and positional
arguments).qn()
as a first-class convenience wrapper around node() with
runtime = Quarto, matching the existing rn()
and pyn() helpers for R and Python nodes.nix_emit_node.ml to support the new visualization injection
logic and improve script-based node robustness.get_sym_demo_t comprehensive demo project with dedicated CI
validation and automated assertions.Printf.sprintf type error in the Python plot rendering
logic that prevented pipeline builds for Python-based
visualizations.show_plot calls so the rendered path
is reported cleanly before local viewer launch.lens.ml.filter_node(is_na($diagnostics.error)) and
which_nodes(is_na($diagnostics.error)) could evaluate
outside the node metadata scope and incorrectly exclude nodes without
diagnostics errors.resilient=true). This ensures that scripts
and pipelines continue execution upon encountering VError
values, aligning with the “Errors are Values” philosophy.--failfast Flag: Replaced the
--resilient CLI flag with --failfast. Users
can now explicitly opt-in to the usual, common behaviour of
short-circuiting upon the first error.t_make() & t_run()
Integration: Added failfast parameter to the main
pipeline orchestrator and script runner for granular control.VError values were deserialized as
Dictionaries. The system now correctly restores the native
Error type across node boundaries, even when using modern
JSON interchange.Status: Beta
VError
objects, allowing independent branches to complete.suppress_warnings combinator to silence high-noise nodes
while maintaining background auditability.node(s) and error(s) formatting,
with clear iconographic reporting (✖, ✓,
○, ?).read_node() &
read_pipeline(): Promoted to first-class tools.
They now accept in-memory objects and return structured results with
values and diagnostics.explain() function: Enhanced to
surface context, tracebacks, and missingness statistics for pipeline
results and errors.verbose=1
support to pipeline builders, mapping directly to Nix build logs for
improved debugging.node_name into all diagnostic records for clear error
attribution in complex DAGs.NAPredicateError: Dedicated error code
for NA values in boolean contexts, enabling robust logic in
filter() and if expressions.na_ignore
semantics across all core math transforms (abs,
log, sqrt, exp, pow)
and aggregations (min, max, sum,
mean).null keyword and VNull type have been
completely removed from the language grammar and AST.NA values.is_null() with is_na() as the
universal missingness predicate.:)
resolution in the native lm() and predict()
engines.fit_stats() API: Unified
goodness-of-fit statistics (R², AIC, BIC) into a single,
language-agnostic DataFrame output.^onnx serialization and native OCaml
scoring via onnxruntime FFI.== and !=. These
now require explicit broadcasting (.==) for collections to
prevent silent logic errors.identical(a, b): New core builtin for
deep structural equality of complex objects.to_dataframe() Constructor: Added
support for Dictionary-based construction and automatic scalar
recycling.pull() and column helpers to support VString
arguments for extraction of special-character column names.tproject.toml.TLANG_AUTO_ADD_PIPELINE_DEPS for CI automation.RSTATS-NIX-DATE for
reproducible, cache-friendly builds.t_demos into 30+ dedicated per-demo
workflows.repl.ml that was causing compilation errors
during scale-wide refactors.None results.:) resolution in native linear model
scoring.Status: Beta
Release Date: 2026-03-28
modify(): A variadic
builtin for applying multiple lens transformations in a single
pass.compose(): Now variadic,
allowing any number of lenses to be chained into a single declarative
path.node_lens() and env_var_lens() for inspecting
and modifying Pipeline node results and environment variables.idx_lens(i) for positional access in
Lists/Vectors, row_lens(i) for specific
DataFrame row targeting, and
filter_lens(p) for predicate-based focus
on elements and rows.rm() Function: New core language
feature for removing variables from the environment. Supports symbols,
strings, and list-based removal (e.g., rm(x, y),
rm("z"), rm(list = vars)).^
symbol prefix for resolving built-in serializers from a centralized
registry (e.g., ^csv, ^arrow,
^pmml, ^json, ^text).<{ ... }>) for reader/writer snippets, ensuring
syntactic separation between T and injected code.t_make()
builtin to the REPL. It defaults to building src/pipeline.t
and supports optional named arguments (e.g., max_jobs,
max_cores) that pass through to the underlying Nix
build.NameError reporting with “Did you mean …?” suggestions when
an unbound variable is accessed.match expression for declarative list and error
destructuring. Includes support for head/tail patterns,
Error { msg } patterns, and automatic error propagation for
unhandled error values.flush stderr after variable reassignment (:=)
warnings to ensure they appear promptly in the REPL.read_node() to automatically fall back to environment
variables (T_NODE_<name>) when build logs are
unavailable. This enables read_node to work inside Nix
build sandboxes (e.g., within Quarto nodes or nested pipeline steps) and
provides automatic deserialization for Arrow, JSON, and PMML artifacts
based on class hints.read_log() now
returns the Nix build log as a VString instead of printing
directly. This allows the log to be captured as a variable or formatted
with cat().print() and
cat() now correctly handle literal newlines and escape
sequences in strings and shell results, ensuring
?<{ls -l}> and logs display correctly.t init
interactive prompts and project scaffolding templates. The
t init command now defaults to the version of the T binary
being used.t init package
and t init project subcommands to
t init --package and t init --project flags
for better clarity.pyn(). Pipeline nodes are now correctly provided as global
variables in the Python runtime.import os to Python serialization snippets, ensuring
standard library access in the Nix sandbox.t update now
automatically handles untracked flake.nix in Git
repositories when running in a CI environment
(CI=true).docs/installation.md.|>) patterns.t_demos and examples/ with the latest
first-class serializer system and ^-prefix notation.Use ':=' to overwrite or rm() to delete the variable).Version history and roadmap for the T programming language.
Status: Beta Release Date: 21st of March 2026
t upgrade to
automatically update projects to the latest T version and refresh the
rstats-on-nix nixpkgs date.VERSION file and propagated across the project.t update and related flake generation logic.read_node
substitution in Quarto reports to prevent syntax errors in R/Python
chunks.Status: Alpha — Syntax and semantics frozen
Release Date: February 2026
t update)t update now
generates a flake.nix that points to this version by
default.min_version now use 0.51.0.✅ Implemented:
$column_name) for concise data
manipulation✅ Implemented:
$column_name for column
references$age > 30 →
\(row) row.age > 30summarize($total = sum($amount)),
mutate($bonus = $salary * 0.1)select, filter,
mutate, arrange, group_by,
summarize✅ Implemented:
✅ Implemented:
+, -, *,
/, %==, !=, <,
>, <=, >=and, or, not|> (conditional, short-circuits on error)?|> (always forwards, including
errors)~ (for regression models)✅ Core Package:
print, pretty_print, type,
length, head, tailmap, filter, sum,
seqis_error✅ Base Package:
error, error_code,
error_message, error_contextassertNA, na_int, na_float,
na_bool, na_string, is_na✅ Math Package:
sqrt, abs, log,
exp, powmin, max✅ Stats Package:
mean, sd, quantile,
cor (with na_rm parameter)lm (linear regression: y ~ x)✅ DataFrame Package:
read_csv (with separator,
skip_lines, skip_header,
clean_colnames)write_csvnrow, ncol, colnamesclean_colnames (symbol expansion, diacritics,
snake_case, collision resolution)✅ Colcraft Package (Data Verbs):
select, filter, mutate,
arrangegroup_by, summarize,
ungrouprow_number, min_rank,
dense_rank, cume_dist,
percent_rank, ntilelag, leadcumsum, cummin,
cummax, cummean, cumall,
cumany✅ Pipeline Package:
pipeline_nodes, pipeline_deps,
pipeline_node, pipeline_run✅ Explain Package:
explain, explain_jsonintent_fields, intent_get✅ Error Handling:
|> and
?|>✅ NA Handling:
na_int(), etc.)na_rm parameter for aggregations✅ Pipelines:
✅ Cross-Language Model Interchange (PMML):
lm) and Python
(scikit-learn)broom-style tidy summaries (summary(),
fit_stats()) for imported models✅ Intent Blocks:
✅ Arrow Integration & Data Formats:
explain(df) surfaces whether a DataFrame is still on
the native Arrow path (storage_backend,
native_path_active)✅ Reproducibility:
✅ Implemented:
✅ Implemented:
✅ Implemented:
T_PACKAGE_PATH flake configurations export the exact
built derivations rather than raw source mapssrc/ and
help/ directories instead of silently failing contextt-lang compiler successfully stripped out of packages’
default recursive buildInputs dependencieshelp() UX fallback bypasses closures gracefully by
searching locally bound environment lambda variables✅ Implemented (this release):
glimpse() documentation for quick DataFrame summaries.