CLI Reference
Every KynML CLI command, flag, example, and exit behavior.
Invocation
KynML exposes a CLI entry point registered at install time:
kynml <command> [OPTIONS] [ARGS]
The entry point delegates to kynml.cli:app. Alternatively, invoke without the entry point (e.g. in a venv without bin on PATH):
python -m kynml.cli <command> [OPTIONS] [ARGS]
Both forms are equivalent. Examples below use python -m kynml.cli for explicitness.
Global Help
python -m kynml.cli --help
Usage: python -m kynml.cli [OPTIONS] COMMAND [ARGS]...
KynML: train models without boilerplate.
Options:
--help Show this message and exit.
Commands:
ast Print the parsed AST for a .kyn file.
compare Show where KynML fits next to adjacent ML tools.
compile Compile a .kyn file into a Python + PyTorch script.
fmt Format a .kyn file in canonical form.
lsp Start the KynML Language Server (LSP).
sweep Expand a sweep block and run all parameter combinations.
train Compile and execute a .kyn training program.
validate Parse and validate a .kyn file.
validate
Parse and semantically validate a .kyn file. Does not generate code or invoke PyTorch.
Synopsis
python -m kynml.cli validate <PATH>
Arguments
| Argument | Required | Description |
|---|---|---|
PATH |
yes | Path to a .kyn source file. |
Flags
None beyond --help.
Behavior
- Reads
PATHand strips blank lines and comments. - Runs the parser (syntax check).
- Runs semantic validation: checks block references, required fields, value ranges, and supported keywords.
- On success, prints
Valid KynML program: <PATH>to stdout and exits0. - On any error, prints
KynMLError: <message>to stderr and exits1. Error messages include the file name and line number.
Examples
# Validate a spec
python -m kynml.cli validate examples/house_price.kyn
# → Valid KynML program: examples/house_price.kyn
# Catch a bad activation
python -m kynml.cli validate bad.kyn
# stderr → KynMLError: bad.kyn:8: Unsupported activation 'elu' in model 'Net'
# exit code 1
Exit Codes
| Code | Meaning |
|---|---|
0 |
File is a valid KynML program. |
1 |
Parse error, semantic error, or file not found. |
ast
Parse a .kyn file and pretty-print its abstract syntax tree. Useful for debugging specs and exploring the parsed structure. Does not validate semantics.
Synopsis
python -m kynml.cli ast <PATH>
Arguments
| Argument | Required | Description |
|---|---|---|
PATH |
yes | Path to a .kyn source file. |
Flags
None beyond --help.
Behavior
- Reads and parses
PATH(syntax only — no semantic validation). - Converts the
Programdataclass to a dict viadataclasses.asdict. - Pretty-prints the dict to stdout using
pprint. - On parse error, prints
KynMLError: <message>to stderr and exits1.
Example
python -m kynml.cli ast examples/house_price.kyn
Produces output like:
{'datasets': [{'name': 'HouseData',
'normalize': True,
'num_workers': 0,
'pin_memory': False,
'prefetch': None,
'shuffle': True,
'source': {'args': ['data/housing.csv'], 'kwargs': {}, 'name': 'csv'},
'split': 0.8,
'target': 'price'}],
'evaluate': {'metrics': ['mae', 'rmse']},
'export': {'format': 'torch',
'input_shape': None,
'opset': 17,
'path': 'models/house_price_model.pt'},
'models': [{'layers': [{'size': 10},
{'activation': 'relu', 'units': 64},
{'activation': 'relu', 'units': 32},
{'activation': 'linear', 'units': 1}],
'name': 'HousePriceModel'}],
'train': {'batch': 32,
'checkpoint': None,
'compile': False,
'data': 'HouseData',
'device': 'auto',
'early_stop': None,
'epochs': 20,
'loss': 'mse',
'model': 'HousePriceModel',
'optimizer': {'args': [], 'kwargs': {'lr': 0.001}, 'name': 'adam'},
'precision': 'fp32',
'scheduler': None}}
Exit Codes
| Code | Meaning |
|---|---|
0 |
Parsed successfully; AST printed to stdout. |
1 |
Parse error or file not found. |
compile
Transpile a .kyn file to a standalone Python + PyTorch training script. The compile pipeline (parse → semantic → codegen) is pure Python — no torch import occurs at compile time.
Synopsis
python -m kynml.cli compile <PATH> --out <OUTPUT>
Arguments
| Argument | Required | Description |
|---|---|---|
PATH |
yes | Path to the .kyn source file. |
Options
| Option | Short | Required | Description |
|---|---|---|---|
--out |
-o |
yes | Destination path for the generated Python file. Parent directories are created automatically. |
--param KEY=VALUE |
-p |
no | Override a params block value. Repeatable. Value is coerced to int, then float, then string. |
Behavior
- Parses
PATH. - Applies composition passes: resolves
importstatements, substitutes$namereferences from theparams:block, applying any--paramoverrides (highest priority). - Runs semantic validation.
- Runs the PyTorch code generator.
- Writes the generated Python to
--out. - On success, prints
Generated <output-path>to stdout and exits0. - On any error, prints
KynMLError: <message>to stderr and exits1.
The generated script is self-contained. It embeds the resolved absolute path to the dataset CSV, all hyperparameters as module-level constants, and the full training/evaluation/export loop. It can be run directly with any Python installation that has torch, numpy, pandas, and scikit-learn.
Examples
# Compile to an explicit output path
python -m kynml.cli compile examples/house_price.kyn --out generated/house_price.py
# → Generated /path/to/generated/house_price.py
# Short flag
python -m kynml.cli compile examples/house_price.kyn -o out/train.py
# Override params at compile time
python -m kynml.cli compile specs/model.kyn -o out/model.py --param hidden=128 --param lr=0.01
Exit Codes
| Code | Meaning |
|---|---|
0 |
Generated script written successfully. |
1 |
Parse error, semantic error, codegen error, or I/O error. |
compare
Print a competitor-positioning map for adjacent ML tools. This command does not call the network at runtime; it renders checked-in positioning data from kynml.competitors.
Synopsis
python -m kynml.cli compare [--focus NAME] [--format table|markdown|json]
Options
| Option | Short | Required | Description |
|---|---|---|---|
--focus NAME |
-q |
no | Filter rows by case-insensitive competitor name text. |
--format FORMAT |
-f |
no | Output as table, markdown, or json. Defaults to table. |
Behavior
- Loads built-in competitor profiles for PyTorch Lightning, Keras, Ludwig, and ZenML.
- Applies
--focusif present. - Renders a human table, Markdown table, or JSON payload.
- On an empty focused match, prints an error and exits
1.
Examples
python -m kynml.cli compare
python -m kynml.cli compare --format markdown
python -m kynml.cli compare --focus keras --format json
Exit Codes
| Code | Meaning |
|---|---|
0 |
Comparison rendered successfully. |
1 |
Unknown format or no focused competitor match. |
train
Compile a .kyn file and immediately execute the generated training script in a subprocess.
Synopsis
python -m kynml.cli train <PATH>
Arguments
| Argument | Required | Description |
|---|---|---|
PATH |
yes | Path to the .kyn source file. |
Options
| Option | Short | Required | Description |
|---|---|---|---|
--param KEY=VALUE |
-p |
no | Override a params block value. Repeatable. Value is coerced to int, then float, then string. |
--manifest / --no-manifest |
no | No-op; kept for forward compatibility. run_manifest.json is always written. |
--param overrides
--param injects or overrides values from the .kyn params: block without editing the source file. The value is coerced: tried as int, then float, then left as a bare string (surrounding quotes are stripped).
# Run with a different learning rate and batch size
python -m kynml.cli train specs/model.kyn --param lr=0.01 --param batch=64
# Override a string param
python -m kynml.cli train specs/model.kyn --param device=cuda
Behavior
- Parses
PATH. - Applies composition passes: resolves
importstatements, substitutes$namereferences from theparams:block, applying any--paramoverrides (highest priority). - Runs semantic validation.
- Writes the generated Python script to
generated/<stem>.py(relative to cwd), creating the directory if needed. The script always writesrun_manifest.jsonafter training. See Reproducibility. - Invokes
sys.executable generated/<stem>.pyas a subprocess, capturing stdout and stderr. - Streams subprocess stdout to the terminal.
- Streams subprocess stderr to terminal stderr.
- If the subprocess exits non-zero,
trainexits with the same code.
The generated/ directory is always generated/ relative to the working directory when train is called, regardless of where the .kyn file lives.
Examples
# Train from a spec
python -m kynml.cli train examples/house_price.kyn
# stdout → Epoch 1/20 - loss: 0.9234
# ...
# mae: 0.1234
# rmse: 0.1876
# Saved model to /abs/path/models/house_price_model.pt
# Train with CUDA explicitly set in the spec
python -m kynml.cli train specs/gpu_model.kyn
# Override params at the command line
python -m kynml.cli train specs/model.kyn --param lr=0.005 --param epochs=50
Training Output
Each epoch prints:
Epoch <N>/<EPOCHS> - loss: <value>
After training, if an evaluate block is present, metrics are printed:
mae: 0.1234
rmse: 0.1876
If an export block is present:
Saved model to /abs/path/to/model.pt
Or for ONNX:
Saved ONNX model to /abs/path/to/model.onnx
If early stopping triggers:
Early stopping at epoch <N>
If a checkpoint is resumed:
Resumed from /path/to/ckpt.pt at epoch <N>
Exit Codes
| Code | Meaning |
|---|---|
0 |
Training completed and (if specified) model exported. |
1 |
KynML compile-time error (parse, semantic, codegen). |
N |
The training subprocess exited with code N (e.g. 1 for a Python runtime error in the generated script). |
sweep
Expand a sweep: block into the Cartesian product of all axis combinations, generate one PyTorch script per combo, run them sequentially, and aggregate results into sweep_results.json. If the .kyn file has no sweep: block the program is run once (equivalent to kynml train).
See Language-Reference for the params: / sweep: syntax.
Synopsis
python -m kynml.cli sweep <PATH> [--out-dir DIR] [--run/--no-run]
Arguments
| Argument | Required | Description |
|---|---|---|
PATH |
yes | Path to the .kyn source file. |
Options
| Option | Short | Default | Description |
|---|---|---|---|
--out-dir |
-o |
generated/ |
Directory for per-combo scripts and sweep_results.json. |
--run / --no-run |
--run |
Execute combos after generating scripts. --no-run generates scripts only. |
Behavior
- Parses
PATHand applies import resolution. - Expands the
sweep:block into the Cartesian product of all axis value lists. For two axeslr = [0.001, 0.01]andhidden = [32, 64]this produces four combos. - For each combo: resolves
$namereferences (sweep axis values overrideparams:defaults), validates, and generates a script named<stem>_sweep_<idx>.pyin--out-dir. - If
--run(the default), generates a sweep orchestrator script<stem>_sweep_runner.pyand executes it. The orchestrator runs each combo script sequentially and collects each run'srun_manifest.jsonintosweep_results.json. - Prints a summary line per combo and the final results path.
Examples
# Run a 2×2 grid (4 combos)
python -m kynml.cli sweep specs/model.kyn
# Generate scripts without running
python -m kynml.cli sweep specs/model.kyn --no-run --out-dir /tmp/sweep
# Custom output directory
python -m kynml.cli sweep specs/model.kyn --out-dir runs/grid_search
A .kyn file with a sweep block:
params:
hidden = 32
lr = 0.001
sweep:
lr = [0.001, 0.01]
hidden = [32, 64]
dataset D:
source = csv("data/x.csv")
target = "y"
model M:
input 4
dense $hidden relu
dense 1 linear
train:
model = M
data = D
loss = mse
optimizer = adam(lr=$lr)
epochs = 10
batch = 32
Running kynml sweep specs/model.kyn prints:
Expanding sweep: 4 combo(s)
[1/4] lr=0.001, hidden=32 -> generated/model_sweep_0.py
[2/4] lr=0.001, hidden=64 -> generated/model_sweep_1.py
[3/4] lr=0.01, hidden=32 -> generated/model_sweep_2.py
[4/4] lr=0.01, hidden=64 -> generated/model_sweep_3.py
Sweep orchestrator: generated/model_sweep_runner.py
...
Sweep complete. Results written to generated/sweep_results.json
sweep_results.json is an array with one entry per combo:
[
{
"combo": {"hidden": 32, "lr": 0.001},
"exit_code": 0,
"manifest": { ... },
"script": "/abs/path/generated/model_sweep_0.py"
},
...
]
Each manifest entry is the run_manifest.json written by that combo's training script. See Reproducibility.
Exit Codes
| Code | Meaning |
|---|---|
0 |
All combos ran (or generated with --no-run). |
1 |
KynML compile-time error in any combo. |
N |
A combo subprocess exited with code N. |
fmt
Format a .kyn file in canonical form. The formatter parses the source into the AST and re-emits it, so it validates syntax as a side-effect and normalises equivalent representations.
Canonical rules: 4-space indentation, exactly one blank line between top-level blocks, no trailing whitespace, single trailing newline, canonical key order per block type, normalised value spacing. The operation is idempotent.
Also available as python -m kynml.format <file.kyn> [--write]. See Tooling.
Synopsis
python -m kynml.cli fmt <PATH> [--write] [--check]
Arguments
| Argument | Required | Description |
|---|---|---|
PATH |
yes | Path to the .kyn source file. |
Options
| Option | Short | Description |
|---|---|---|
--write |
-w |
Overwrite the file in place with the formatted result. |
--check |
-c |
Exit 1 if the file would change (CI use). |
Without either flag, prints the formatted source to stdout and exits 0.
Examples
# Print canonical form to stdout
python -m kynml.cli fmt specs/model.kyn
# Format in place
python -m kynml.cli fmt specs/model.kyn --write
# CI lint gate — fail if any spec is not already formatted
find specs/ -name "*.kyn" -exec python -m kynml.cli fmt --check {} \;
Exit Codes
| Code | Meaning |
|---|---|
0 |
Success (or --check and already formatted). |
1 |
Parse error, or --check and file would change. |
lsp
Start the KynML Language Server over stdio. Point your editor's LSP client at kynml lsp. The server publishes diagnostics (parse errors, semantic errors, shape errors, and warnings) on open, change, and save events.
Requires the pygls package: pip install 'kynml[lsp]'. The diagnostics API (kynml.lsp.diagnostics.diagnose) works without pygls. See Tooling.
Synopsis
python -m kynml.cli lsp [--stdio]
Options
| Option | Default | Description |
|---|---|---|
--stdio / --no-stdio |
--stdio |
Use stdio transport. Required by most editors; currently the only supported transport. |
Editor configuration
Point any LSP-capable editor at the kynml lsp command. Example Neovim config (via nvim-lspconfig or vim.lsp.start):
vim.lsp.start({
name = "kynml",
cmd = { "kynml", "lsp" },
filetypes = { "kyn" },
root_dir = vim.fn.getcwd(),
})
Exit Codes
| Code | Meaning |
|---|---|
0 |
Server exited cleanly (editor closed connection). |
1 |
pygls not installed, or server error. |
Error Format
All KynML errors follow this format:
KynMLError: <source>:<line>: <message>
For example:
KynMLError: specs/model.kyn:14: Unsupported loss 'focal'. Supported: bce, cross_entropy, huber, l1, mae, mse, nll
When the error is semantic and a close match exists, a suggestion is appended:
KynMLError: specs/model.kyn:6: Unknown dataset 'HouseDate'. Did you mean 'HouseData'?
Scripting and CI
validate is the lightweight gate for syntax and semantic checks:
# Fail fast on any invalid spec
find specs/ -name "*.kyn" -exec python -m kynml.cli validate {} \;
fmt --check enforces formatting in CI:
# Fail if any spec is not already in canonical form
find specs/ -name "*.kyn" -exec python -m kynml.cli fmt --check {} \;
compile with --out /dev/null is not meaningful — use validate for lint-only checks.
train returns the training process exit code:
python -m kynml.cli train specs/smoke_test.kyn || exit 1
# With a param override
python -m kynml.cli train specs/smoke_test.kyn --param epochs=1 || exit 1
sweep --no-run generates all combo scripts for inspection without executing them:
python -m kynml.cli sweep specs/grid.kyn --no-run --out-dir /tmp/inspect