Skip to content

About

OpenRoboto CLI (PyPI: openroboto) — everything a miner types: init, upload, submit, status. Subnet netuid 80.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

openroboto

The command-line tool for mining on OpenRoboto, a Bittensor mainnet subnet (netuid 80) that rewards improvements to vision-language-action models.

You fine-tune the current season's base model — LingBot-VLA 2.0 today — publish the checkpoint to Hugging Face, pay a small on-chain evaluation fee, and announce it. The subnet evaluates every submission in simulation with a seed nobody can predict, ranks the results, and pays emissions by rank.

Everything you type is this one package. There is nothing to clone.

pip install openroboto

Docs index · How the subnet works · This season's base model · Evaluation toolkit

Real-robot documentation: parallel tracks · miner preparation · workstation and reference data. These pages describe π0.5 and LingBot as parallel physical tracks and publish the confirmed joint-space interface. Publication does not announce a new competition as open.


Requirements

  • Linux, an NVIDIA GPU (24 GB VRAM minimum) and a recent driver
  • Python 3.11
  • Docker with the NVIDIA Container Toolkit — training runs in a container because openpi needs numpy<2.0 and bittensor needs numpy>=2.0; one interpreter cannot hold both
  • A registered Bittensor mainnet hotkey with enough TAO for the evaluation fee
  • A Hugging Face account and a write token

Your first submission

# 1. Install and scaffold
pip install openroboto
openroboto init my-miner          # a ready-to-use workspace: miner.yaml,
                                  # train_strategy.py, README.md, .gitignore
cd my-miner
$EDITOR miner.yaml                # hotkey_ss58, HF token + username

# 2. Check everything BEFORE anything costs money
openroboto doctor                 # config, season + fee, HF permissions, balance, Docker, GPU

# 3. Build the training image, then train
openroboto build
openroboto train

# 4. Verify the checkpoint format — still free
openroboto check

# 5. Upload, pay the fee, announce on chain
openroboto submit

# 6. See what the subnet made of it
openroboto status

Steps 2 and 4 exist for one reason: entry fees are not refundable. The most expensive mistake on this subnet is discovering after paying that the upload was not something the evaluator can load — a bare LoRA adapter, or a checkpoint buried in a subdirectory. doctor and check are free and catch both.

Full walkthrough: docs/MINER.md. Real-machine setup, systemd, custom strategies: docs/MINER_DEPLOY.md.

Commands

Command What it does
openroboto init [DIR] [-s simple|example] [--validator] [--refresh] [--backend-url URL] [--force] Create a working workspace: config, a training strategy to edit, a README with the exact next commands, and a .gitignore that keeps your wallet password out of git. ⚠️ This is the one command that needs the network: the open competitions come from GET /api/v1/competitions, and if that cannot be reached it writes no file at all rather than guessing a season. --refresh rewrites only the competition: section of an existing miner.yaml; --backend-url says which backend to ask (and the whole workspace is then written to match it); --force overwrites existing files
openroboto doctor Environment check: Python, config, the season's own spec, Docker, GPU, image, HF token, wallet balance against this season's fee
openroboto build Build the training image from the build context shipped inside the package (no clone, no network). Refuses for a competition this client has no image for, rather than filling that competition's image name with the π0.5 one
openroboto train [-s script.py] Train once; your strategy script is mounted into the container
openroboto check [PATH] Verify checkpoint layout with the rules the evaluator uses — no GPU, no network, no second repository
openroboto submit [--config] [--output-dir] [--force] Upload → re-check the season against the backend → check the repository layout → pay the entry fee → announce on chain. Resumable from state/competition_<id>.json: an upload already done is not repeated and a fee already paid is not paid again
openroboto status [--hotkey] [--competition] Submission history and scanner rejection reasons (no API key needed)
openroboto validator run External validator: read published weights, set them on chain
openroboto --version CLI version and protocol package version

⚠️ There is no openroboto merge, and none is planned. Exporting a full checkpoint is part of training — it needs the model libraries, which cannot live in the same interpreter as bittensor — so it belongs in your training script, inside the training container. The bundled strategies leave that step blank on purpose and say so; openroboto train tells you what the run actually produced, and openroboto check gives the verdict before you pay.

⚠️ openroboto submit checks the layout too, and it is not optional. Between the upload and the payment it reads the file listing of your HuggingFace repository — the same listing the subnet reads after the fee — and stops without paying anything if that listing would not earn a score. There is no flag to skip it, because past that point a rejection is final and the TAO is not refunded. If the listing cannot be fetched at all, it also stops: an answer we could not get is not one this will spend your money on. Run openroboto check first anyway — it is free, it runs before the multi-gigabyte upload, and it checks two more rules that need the weight index on your disk.

Things that will cost you TAO if you skip them

The fee is published on the competition you are entering (params.fee), and the simulation and real-hardware seasons do not charge the same thing, which is why no figure belongs in your config — or in this file. Never hard-code it: openroboto submit confirms it against the backend in the moment before paying, and refuses to pay at all if it cannot, rather than reaching for an amount that says how much but not which competition.

submit is the only command that pays, and that is on purpose. The backend only accepts a submission whose payment is within 50 blocks (~10 minutes) of the chain commitment; this stops a single fee being reused across submissions. Past that window the submission is rejected and the fee is gone. openroboto submit runs upload, payment and announcement back-to-back so you stay inside it, and it refuses to publish once the window has closed instead of charging you a second fee for a doomed submission. upload / burn / announce were removed as separate commands in 1.0 for exactly this reason: running one alone is how a fee gets paid for a submission that is never announced.

Details: docs/PAYMENT.md.

Submission format

The evaluator accepts complete model checkpoints — an openpi JAX params/ directory or a PyTorch model.safetensors, plus assets/physical-intelligence/libero/norm_stats.json. A bare LoRA adapter is rejected by a CPU pre-check before any GPU time is spent.

Put them at the top of the directory you upload. The evaluator descends two levels looking for the weights and stops; the LingBot exporter's own layout, checkpoints/global_step_N/hf_ckpt/, is one level past that, so an unedited upload of a training output is admitted and then never loaded.

Exact requirements: docs/SUBNET_OVERVIEW.md.

Verify your evaluation seed

Your seed is derived from three public values, two of which did not exist when you submitted — the block hash that carried your commitment, the competition id your submission was admitted to, and a drand beacon value. Nobody, including the subnet operator, can pick a seed for a specific miner. You can recompute it:

pip install openroboto-protocol
from openroboto_protocol.seed import derive_seed

# The middle argument is the competition id, not the payload's `r` and not the
# season ordinal the API displays. It is passed by position.
seed = derive_seed(block_hash, competition_id, drand_randomness)

The backend and this CLI import that exact function — not a copy of it. Formula, drand chain identifier and security assumptions: docs/SEED_GENERATION.md.

Docker: what runs where

Training always runs in a container — openpi needs numpy<2.0 and bittensor needs numpy>=2.0, so one interpreter cannot hold both. You do not have to arrange that:

openroboto build     # builds the training image, once
openroboto train     # starts it for you, data and strategy mounted in

The training image definition ships inside the package. There is nothing to clone, nothing to keep in sync, and no network needed to build it. You do need Docker on the host.

The package ships two image definitions, one per base model: runner/ (openpi, π0.5) and runner/lingbot/ (LingBot-VLA 2.0). Which one is used follows competition.base_model_family, never the adapter name. A competition whose base model has no image here is refused by build and train — they stop rather than build another base model's image under that competition's name. Train such a season your own way, then come back for openroboto check and openroboto submit, which both work on a checkpoint this CLI did not produce.

Running the CLI in a container too (optional, needs a clone)

Separately, the Dockerfile and docker-compose.yml in this repository put the CLI itself in a container, for people who would rather not install it into their host Python. That is a repository-level convenience: openroboto init does not write these files into your workspace, because a compose file that builds the CLI image would need this repository's build context anyway.

git clone https://github.com/openroboto-ai/openroboto-cli && cd openroboto-cli
docker compose up train
docker compose run --rm train submit --config miner.yaml

There is deliberately no submit service — a compose service can be restarted, and restarting a command that spends a non-refundable entry fee is not something to leave to a restart policy.

⚠️ This compose file mounts the Docker socket so the containerised CLI can start the training container. That grants host root to the container; run it only on your own machine. Installing with pip avoids that entirely, which is why it is the documented path.

Public trust boundary

Public: miner participation, local training, Hugging Face upload, fee payment and chain announcement; chain commitment formats and weight-setting logic; evaluation rules, baseline methodology, LIBERO tooling and seed derivation; and the read-only API contract. (control.json is documented for external validators, who fetch public_key from it — no miner command reads it.)

Not here: held-out task data, the scoring-service deployment, and subnet-owner operational tooling.

Seed derivation is public precisely because publishing it gives nothing away — the future block hash and drand value do not exist at submission time.

Development

For contributors. Skip this if you installed from PyPI.

git clone https://github.com/openroboto-ai/openroboto-cli
cd openroboto-cli
uv sync --locked

One repository is enough: openroboto-protocol is installed from PyPI at the exact version pinned in pyproject.toml. To work against unreleased protocol changes, override it in your environment only — uv pip install -e ../openroboto-protocol — and do not commit a [tool.uv.sources] path entry. A path source bypasses the version constraint, A path source that disagrees with the pin leaves every local and CI run green while resolving a different version than the one published.

--locked is deliberate: it fails when uv.lock does not match pyproject.toml instead of silently resolving a different dependency tree. The interpreter is pinned to Python 3.11 by .python-version — the version miners run.

bash scripts/lint.sh                             # mypy + ruff check + ruff format
uv run pytest -q                                 # no GPU, no chain, no network
uv run coverage run --source=src -m pytest -q
uv run coverage report                           # fails below the threshold in pyproject.toml
uvx pre-commit install                           # optional: the same lint on every commit

.github/workflows/ci.yml runs these same commands — scripts/lint.sh is the single definition of "lint", so local and CI cannot drift. CI also fails on any skipped test: nothing here needs hardware or credentials, so a skip means a test was switched off.

Protocol constants (commitment encoding, seed derivation, shared vocabularies) come from openroboto-protocol and are never copied in here. .github/workflows/protocol-guards.yml enforces that and that the dependency is pinned to an exact version — a floating range would let the miner side and the backend side resolve different code, which is the one thing that package exists to prevent.

Releasing

git tag v1.0.1   && git push origin v1.0.1      # stable
git tag v1.1.0a1 && git push origin v1.1.0a1    # pre-release, for testing

The tag triggers the same gates every pull request runs, and the pypi environment only accepts v* tags, so a stray branch build cannot reach the index. It then waits for a reviewer to approve that environment: uploads cannot be undone and a version number can never be reused, so that approval is the last thing standing between a typo and every miner.

pip install openroboto resolves to the newest stable release. A tester takes a pre-release by pinning it exactly (pip install openroboto==1.1.0a1); no miner lands on one by accident.

Repository map

Path Purpose
src/openroboto/ The package: commands/, chain/, huggingface/, payment/, config/, training/, templates/
src/openroboto/runner/, src/openroboto/runner/lingbot/ One training-image build context per base model (Dockerfile + the in-container entry script), both shipped in the wheel so openroboto build works offline
docs/ Miner, validator and reproducibility documentation — index at docs/README.md
tests/ Mirrors src/; needs no GPU, chain or network
Dockerfile, docker-compose.yml Optional containerised way to run the CLI

Local configuration, runtime state, logs, caches and model weights are excluded by .gitignore.

License

See LICENSE.

About

OpenRoboto CLI (PyPI: openroboto) — everything a miner types: init, upload, submit, status. Subnet netuid 80.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages