Metadata-Version: 2.4
Name: vlakit
Version: 0.1.0
Summary: Config-driven CLI to launch, monitor, and ship VLA fine-tunes across ephemeral GPU boxes.
Project-URL: Homepage, https://github.com/kkipngenokoech/vlakit
Project-URL: Issues, https://github.com/kkipngenokoech/vlakit/issues
Author-email: kkipngenokoech <kkipngenokoech22@gmail.com>
License: MIT
License-File: LICENSE
Keywords: fine-tuning,lerobot,molmoact,openpi,robotics,vla
Classifier: Environment :: Console
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Provides-Extra: all
Requires-Dist: numpy; extra == 'all'
Requires-Dist: pyarrow; extra == 'all'
Requires-Dist: pyyaml; extra == 'all'
Requires-Dist: wandb; extra == 'all'
Provides-Extra: stats
Requires-Dist: numpy; extra == 'stats'
Requires-Dist: pyarrow; extra == 'stats'
Provides-Extra: wandb
Requires-Dist: wandb; extra == 'wandb'
Provides-Extra: yaml
Requires-Dist: pyyaml; extra == 'yaml'
Description-Content-Type: text/markdown

# vlakit

`vlakit` is a config-driven command-line tool for launching VLA fine-tunes across **ephemeral GPU boxes**, keeping them alive through crashes, and shipping verified weights to durable storage. You describe a run in YAML and drive everything with a single `vla` command from your laptop; the actual work runs on a GPU box over ssh, and the durable artifacts land on Weights & Biases and a storage box — never on the GPU box, which you throw away.

It packages a set of battle-tested shell and Python scripts (the ones that encode the hard-won operational lessons) behind a friendly CLI. The scripts ship with the install as read-only package data, while your environment — the boxes, datasets, baselines, and runs — lives in a `configs/` directory you own and edit.

## Install

`vlakit` is best installed as an isolated CLI with [pipx](https://pipx.pypa.io):

```bash
pipx install vlakit
```

Or with pip. The core install is dependency-light because the laptop-side commands need almost nothing; the heavier pieces are opt-in extras:

```bash
pip install vlakit                 # laptop-side: config / remote / launch
pip install "vlakit[stats]"        # adds numpy + pyarrow for `vla stats`
pip install "vlakit[wandb]"        # adds wandb for publish / pull / eval logging
pip install "vlakit[all]"          # everything
```

## Quickstart

```bash
vla init                           # scaffold an editable ./configs from templates
# edit configs/boxes.yaml, datasets.yaml, baselines.yaml, and a runs/<name>.yaml
# then copy configs/secrets.example.env -> configs/secrets.local.env and fill it

vla config <run>                   # resolve + print the run config (local, no box)
vla remote <box> deploy            # rsync the toolkit + your configs onto the box
vla remote <box> push-secrets      # install ~/.secrets.env on the box (mode 600)
vla remote <box> ensure-swap       # provision swap (absorbs the checkpoint-save spike)
vla launch <run>                   # launch detached + auto-resume (box read from the run cfg)
vla remote <box> monitor           # step / rate / ETA + liveness
```

## Where each command runs

`vlakit` keeps a clean split between your laptop and the GPU box. Commands that resolve or inspect configuration — `init`, `config`, `stats`, `split`, `eval`, `doctor` — run entirely on your **laptop** and need no box. Commands that operate on a machine — everything under `vla remote ...`, and `vla launch` — open an ssh connection from your laptop and run the work **on the box** defined in your `boxes.yaml`.

Run `vla doctor` to see exactly which scripts directory and config directory were resolved, and which optional dependencies are installed.

## Commands

| Command | Runs | What it does |
|---|---|---|
| `vla init [dir]` | laptop | Scaffolds an editable `configs/` directory from the bundled templates. |
| `vla config <run>` | laptop | Resolves a run (defaults merged under the run) and prints the config plus the exact command, running nothing. |
| `vla remote <box> <subcmd> [args]` | box | Runs an operational subcommand on the box: `deploy`, `push-secrets`, `ensure-swap`, `launch`, `autoresume`, `monitor`, `kill`, `rescale`, `pull`, `gpus`, `exec`, `shell`. |
| `vla launch <run>` | box | Launches the run detached and auto-resuming; the box is read from the run's `box:` field. |
| `vla stats [args]` | laptop/box | Computes the full dataset statistics (quantiles + image stats) that lerobot and molmo need. Requires the `[stats]` extra. |
| `vla split [args]` | laptop | Produces a deterministic held-out episode split for validation/eval. |
| `vla eval [args]` | laptop/box | Ranks a checkpoint by held-out error or rollout, not loss. Try `vla eval --self-test` to verify the harness with no box. |
| `vla doctor` | laptop | Prints the resolved scripts/config directories and optional-dependency status. |

## Configuration

Your `configs/` directory holds everything dynamic, and no secrets ever live in it: keys resolve on the box via `~/.secrets.env`. The directory is resolved from `--config-dir`, then the `VLA_CONFIG_DIR` environment variable, then `./configs`. A run file under `runs/` is a thin recipe that names a `box`, a `dataset`, and a `baseline` — each a pointer into the corresponding registry — plus a few hyperparameters; everything else is inherited from `_defaults.yaml`.

## Status

The local commands (`init`, `config`, `stats`, `split`, `eval`, `doctor`) are implemented and tested. The remote commands shell out to the bundled, proven ops scripts; `vla remote <box> deploy` now ships both the toolkit and your `configs/` to the box. The `eval` offline comparator is implemented and self-tested (`vla eval --self-test`); its sim and robot rollout modes are still stubs.

## Publishing (maintainers)

Releases publish to PyPI automatically through [Trusted Publishing](https://docs.pypi.org/trusted-publishers/) (OIDC), so no API token is stored anywhere. The workflow is [`.github/workflows/release.yml`](.github/workflows/release.yml).

One-time setup:

1. On PyPI, add a **pending** Trusted Publisher (Account → Publishing) with these exact values:
   - PyPI Project Name: `vlakit`
   - Owner: `kkipngenokoech`
   - Repository name: `vlakit`
   - Workflow name: `release.yml`
   - Environment name: `pypi`
2. In the GitHub repo, create an Environment named `pypi` (Settings → Environments).

To cut a release, tag a version that matches `pyproject.toml` and push it:

```bash
git tag v0.1.0
git push origin v0.1.0
```

The workflow builds the sdist + wheel, verifies the bundled scripts/templates are inside the wheel, checks the tag matches the package version, and publishes. After the first successful run the pending publisher becomes a normal one, and `pipx install vlakit` works for everyone.

## License

MIT — see [LICENSE](LICENSE).
