Docs CLI Reference

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

  1. Reads PATH and strips blank lines and comments.
  2. Runs the parser (syntax check).
  3. Runs semantic validation: checks block references, required fields, value ranges, and supported keywords.
  4. On success, prints Valid KynML program: <PATH> to stdout and exits 0.
  5. On any error, prints KynMLError: <message> to stderr and exits 1. 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

  1. Reads and parses PATH (syntax only — no semantic validation).
  2. Converts the Program dataclass to a dict via dataclasses.asdict.
  3. Pretty-prints the dict to stdout using pprint.
  4. On parse error, prints KynMLError: <message> to stderr and exits 1.

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

  1. Parses PATH.
  2. Applies composition passes: resolves import statements, substitutes $name references from the params: block, applying any --param overrides (highest priority).
  3. Runs semantic validation.
  4. Runs the PyTorch code generator.
  5. Writes the generated Python to --out.
  6. On success, prints Generated <output-path> to stdout and exits 0.
  7. On any error, prints KynMLError: <message> to stderr and exits 1.

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

  1. Loads built-in competitor profiles for PyTorch Lightning, Keras, Ludwig, and ZenML.
  2. Applies --focus if present.
  3. Renders a human table, Markdown table, or JSON payload.
  4. 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

  1. Parses PATH.
  2. Applies composition passes: resolves import statements, substitutes $name references from the params: block, applying any --param overrides (highest priority).
  3. Runs semantic validation.
  4. Writes the generated Python script to generated/<stem>.py (relative to cwd), creating the directory if needed. The script always writes run_manifest.json after training. See Reproducibility.
  5. Invokes sys.executable generated/<stem>.py as a subprocess, capturing stdout and stderr.
  6. Streams subprocess stdout to the terminal.
  7. Streams subprocess stderr to terminal stderr.
  8. If the subprocess exits non-zero, train exits 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

  1. Parses PATH and applies import resolution.
  2. Expands the sweep: block into the Cartesian product of all axis value lists. For two axes lr = [0.001, 0.01] and hidden = [32, 64] this produces four combos.
  3. For each combo: resolves $name references (sweep axis values override params: defaults), validates, and generates a script named <stem>_sweep_<idx>.py in --out-dir.
  4. If --run (the default), generates a sweep orchestrator script <stem>_sweep_runner.py and executes it. The orchestrator runs each combo script sequentially and collects each run's run_manifest.json into sweep_results.json.
  5. 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