openroboto 0.1.0a1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openroboto-0.1.0a1/LICENSE +21 -0
- openroboto-0.1.0a1/PKG-INFO +310 -0
- openroboto-0.1.0a1/README.md +286 -0
- openroboto-0.1.0a1/pyproject.toml +187 -0
- openroboto-0.1.0a1/src/openroboto/__init__.py +61 -0
- openroboto-0.1.0a1/src/openroboto/backend_api.py +341 -0
- openroboto-0.1.0a1/src/openroboto/chain/__init__.py +35 -0
- openroboto-0.1.0a1/src/openroboto/chain/commitment.py +215 -0
- openroboto-0.1.0a1/src/openroboto/chain/connection.py +108 -0
- openroboto-0.1.0a1/src/openroboto/chain/weights.py +138 -0
- openroboto-0.1.0a1/src/openroboto/cli.py +139 -0
- openroboto-0.1.0a1/src/openroboto/commands/__init__.py +7 -0
- openroboto-0.1.0a1/src/openroboto/commands/announce.py +138 -0
- openroboto-0.1.0a1/src/openroboto/commands/build.py +104 -0
- openroboto-0.1.0a1/src/openroboto/commands/burn.py +117 -0
- openroboto-0.1.0a1/src/openroboto/commands/check.py +94 -0
- openroboto-0.1.0a1/src/openroboto/commands/doctor.py +400 -0
- openroboto-0.1.0a1/src/openroboto/commands/init.py +124 -0
- openroboto-0.1.0a1/src/openroboto/commands/status.py +165 -0
- openroboto-0.1.0a1/src/openroboto/commands/submit.py +78 -0
- openroboto-0.1.0a1/src/openroboto/commands/train.py +184 -0
- openroboto-0.1.0a1/src/openroboto/commands/upload.py +87 -0
- openroboto-0.1.0a1/src/openroboto/commands/validator.py +108 -0
- openroboto-0.1.0a1/src/openroboto/config/__init__.py +22 -0
- openroboto-0.1.0a1/src/openroboto/config/control.py +158 -0
- openroboto-0.1.0a1/src/openroboto/config/environments.py +194 -0
- openroboto-0.1.0a1/src/openroboto/config/settings.py +307 -0
- openroboto-0.1.0a1/src/openroboto/console.py +26 -0
- openroboto-0.1.0a1/src/openroboto/http_client.py +59 -0
- openroboto-0.1.0a1/src/openroboto/huggingface/__init__.py +19 -0
- openroboto-0.1.0a1/src/openroboto/huggingface/repository.py +49 -0
- openroboto-0.1.0a1/src/openroboto/huggingface/upload.py +149 -0
- openroboto-0.1.0a1/src/openroboto/logging.py +51 -0
- openroboto-0.1.0a1/src/openroboto/payment/__init__.py +9 -0
- openroboto-0.1.0a1/src/openroboto/payment/burn.py +153 -0
- openroboto-0.1.0a1/src/openroboto/preflight.py +146 -0
- openroboto-0.1.0a1/src/openroboto/py.typed +0 -0
- openroboto-0.1.0a1/src/openroboto/round_state.py +110 -0
- openroboto-0.1.0a1/src/openroboto/runner/Dockerfile +56 -0
- openroboto-0.1.0a1/src/openroboto/runner/train_runner.py +431 -0
- openroboto-0.1.0a1/src/openroboto/templates/README-miner.md +86 -0
- openroboto-0.1.0a1/src/openroboto/templates/README-validator.md +48 -0
- openroboto-0.1.0a1/src/openroboto/templates/example/train_strategy.py +113 -0
- openroboto-0.1.0a1/src/openroboto/templates/gitignore +31 -0
- openroboto-0.1.0a1/src/openroboto/templates/miner.yaml +81 -0
- openroboto-0.1.0a1/src/openroboto/templates/simple/train_strategy.py +167 -0
- openroboto-0.1.0a1/src/openroboto/templates/validator.yaml +35 -0
- openroboto-0.1.0a1/src/openroboto/training/__init__.py +30 -0
- openroboto-0.1.0a1/src/openroboto/training/container.py +354 -0
- openroboto-0.1.0a1/src/openroboto/training/dataset.py +117 -0
- openroboto-0.1.0a1/src/openroboto/training/round.py +266 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OpenRoboto
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openroboto
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: OpenRoboto subnet (Bittensor netuid 80) CLI — everything a miner or external validator types.
|
|
5
|
+
Keywords: bittensor,openroboto,subnet,miner,cli
|
|
6
|
+
Author: OpenRoboto
|
|
7
|
+
Author-email: OpenRoboto <cameron@moonshotcommons.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Dist: openroboto-protocol==0.2.0
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Requires-Dist: bittensor>=10.5,<11
|
|
19
|
+
Requires-Dist: huggingface-hub>=0.24.0
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Project-URL: Homepage, https://github.com/openroboto-ai/openroboto-cli
|
|
22
|
+
Project-URL: Issues, https://github.com/openroboto-ai/openroboto-cli/issues
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# openroboto
|
|
26
|
+
|
|
27
|
+
The command-line tool for mining on **OpenRoboto**, a Bittensor mainnet subnet
|
|
28
|
+
(netuid 80) that rewards improvements to vision-language-action models.
|
|
29
|
+
|
|
30
|
+
You fine-tune π₀.₅ on LIBERO, publish the checkpoint to Hugging Face, pay a small
|
|
31
|
+
on-chain evaluation fee, and announce it. The subnet evaluates every submission in
|
|
32
|
+
simulation with a seed nobody can predict, ranks the results, and pays emissions by
|
|
33
|
+
rank.
|
|
34
|
+
|
|
35
|
+
Everything you type is this one package. **There is nothing to clone.**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install openroboto
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
[Docs index](docs/README.md) · [How the subnet works](docs/SUBNET_OVERVIEW.md) ·
|
|
42
|
+
[Migrating from `rt.py`](docs/MIGRATION.md) ·
|
|
43
|
+
[Evaluation toolkit](https://github.com/openroboto-ai/openroboto-evaluation)
|
|
44
|
+
|
|
45
|
+
> **Upgrading from a clone of this repository?** `python miner.py` and
|
|
46
|
+
> `python rt.py submit` were removed on 2026-08-19. See
|
|
47
|
+
> [docs/MIGRATION.md](docs/MIGRATION.md) for the command map — your existing
|
|
48
|
+
> `miner.yaml` and `state/round_N.json` still work.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Requirements
|
|
53
|
+
|
|
54
|
+
- Linux, an NVIDIA GPU (24 GB VRAM minimum) and a recent driver
|
|
55
|
+
- Python **3.11**
|
|
56
|
+
- Docker with the NVIDIA Container Toolkit — training runs in a container because
|
|
57
|
+
openpi needs `numpy<2.0` and bittensor needs `numpy>=2.0`; one interpreter cannot
|
|
58
|
+
hold both
|
|
59
|
+
- A registered Bittensor mainnet hotkey with enough TAO for the evaluation fee
|
|
60
|
+
- A Hugging Face account and a write token
|
|
61
|
+
|
|
62
|
+
## Your first submission
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# 1. Install and scaffold
|
|
66
|
+
pip install openroboto
|
|
67
|
+
openroboto init my-miner # a ready-to-use workspace: miner.yaml,
|
|
68
|
+
# train_strategy.py, README.md, .gitignore
|
|
69
|
+
cd my-miner
|
|
70
|
+
$EDITOR miner.yaml # hotkey_ss58, HF token + username, control.json URL
|
|
71
|
+
|
|
72
|
+
# 2. Check everything BEFORE anything costs money
|
|
73
|
+
openroboto doctor # GPU, Docker, HF permissions, balance, config
|
|
74
|
+
|
|
75
|
+
# 3. Build the training image, then train one round
|
|
76
|
+
openroboto build
|
|
77
|
+
openroboto train
|
|
78
|
+
|
|
79
|
+
# 4. Verify the checkpoint format — still free
|
|
80
|
+
openroboto check
|
|
81
|
+
|
|
82
|
+
# 5. Upload, pay the fee, announce on chain
|
|
83
|
+
openroboto submit
|
|
84
|
+
|
|
85
|
+
# 6. See what the subnet made of it
|
|
86
|
+
openroboto status
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Steps 2 and 4 exist for one reason: **burns are not refundable.** The most expensive
|
|
90
|
+
mistake on this subnet is discovering after paying that the upload was a bare LoRA
|
|
91
|
+
adapter. `doctor` and `check` are free and catch that.
|
|
92
|
+
|
|
93
|
+
Full walkthrough: [docs/MINER.md](docs/MINER.md).
|
|
94
|
+
Real-machine setup, systemd, custom strategies: [docs/MINER_DEPLOY.md](docs/MINER_DEPLOY.md).
|
|
95
|
+
|
|
96
|
+
## Commands
|
|
97
|
+
|
|
98
|
+
| Command | What it does |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `openroboto init [DIR] [-s simple\|example] [--validator]` | 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 |
|
|
101
|
+
| `openroboto doctor` | Environment check: Python, config, `control.json`, Docker, GPU, image, HF token, wallet balance |
|
|
102
|
+
| `openroboto build` | Build the training image from the build context shipped inside the package (no clone, no network) |
|
|
103
|
+
| `openroboto train [-s script.py]` | Run one round; your strategy script is mounted into the container |
|
|
104
|
+
| `openroboto check [PATH]` | Verify checkpoint layout with the rules the evaluator uses — **no GPU, no network, no second repository** |
|
|
105
|
+
| `openroboto upload / burn / announce` | The three submission steps, individually — for recovery, not routine use |
|
|
106
|
+
| `openroboto submit [--force]` | All three, resumable from `state/round_N.json` |
|
|
107
|
+
| `openroboto status [--hotkey]` | Submission history and scanner rejection reasons (no API key needed) |
|
|
108
|
+
| `openroboto validator run` | External validator: read published weights, set them on chain |
|
|
109
|
+
| `openroboto --version` | CLI version and protocol package version |
|
|
110
|
+
|
|
111
|
+
⚠️ **`openroboto merge` does not exist yet.** Training produces a LoRA adapter, and a
|
|
112
|
+
bare adapter is rejected — merging it into the base model is currently a manual step.
|
|
113
|
+
`openroboto check` catches an unmerged upload before you pay.
|
|
114
|
+
|
|
115
|
+
## Things that will cost you TAO if you skip them
|
|
116
|
+
|
|
117
|
+
The fee is published live in `control.json`; on mainnet today it is 0.1 TAO. Never
|
|
118
|
+
hard-code it — the CLI reads it, and **refuses to burn if it cannot** rather than
|
|
119
|
+
guessing an amount the backend would reject.
|
|
120
|
+
|
|
121
|
+
**Do not run `burn` and `announce` as separate steps unless you are recovering.** The
|
|
122
|
+
backend only accepts a submission whose burn is within **50 blocks (~10 minutes)** of
|
|
123
|
+
the chain commitment; this stops a single fee being reused across submissions. Past
|
|
124
|
+
that window the submission is rejected and the fee is gone. `openroboto submit` runs
|
|
125
|
+
the three steps back-to-back so you stay inside it, and `announce` refuses to publish
|
|
126
|
+
once the window has closed instead of charging you a second fee for a doomed
|
|
127
|
+
submission.
|
|
128
|
+
|
|
129
|
+
Details: [docs/PAYMENT.md](docs/PAYMENT.md).
|
|
130
|
+
|
|
131
|
+
## Submission format
|
|
132
|
+
|
|
133
|
+
The evaluator accepts **complete model checkpoints** — an openpi JAX `params/`
|
|
134
|
+
directory or a PyTorch `model.safetensors`, plus
|
|
135
|
+
`assets/physical-intelligence/libero/norm_stats.json`. A bare LoRA adapter is rejected
|
|
136
|
+
by a CPU pre-check before any GPU time is spent.
|
|
137
|
+
|
|
138
|
+
Exact requirements: [docs/SUBNET_OVERVIEW.md](docs/SUBNET_OVERVIEW.md).
|
|
139
|
+
|
|
140
|
+
## Verify your evaluation seed
|
|
141
|
+
|
|
142
|
+
Your seed is derived from three public values that did not exist when you submitted —
|
|
143
|
+
the block hash that carried your commitment, the round number, and a drand beacon
|
|
144
|
+
value. Nobody, including the subnet operator, can pick a seed for a specific miner.
|
|
145
|
+
You can recompute it:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
pip install openroboto-protocol
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from openroboto_protocol.seed import derive_seed
|
|
153
|
+
|
|
154
|
+
seed = derive_seed(block_hash, round_num, drand_randomness)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The backend and this CLI import that exact function — not a copy of it.
|
|
158
|
+
Formula, drand chain identifier and security assumptions:
|
|
159
|
+
[docs/SEED_GENERATION.md](docs/SEED_GENERATION.md).
|
|
160
|
+
|
|
161
|
+
## Docker: what runs where
|
|
162
|
+
|
|
163
|
+
Training **always** runs in a container — openpi needs `numpy<2.0` and bittensor
|
|
164
|
+
needs `numpy>=2.0`, so one interpreter cannot hold both. You do not have to
|
|
165
|
+
arrange that:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
openroboto build # builds the training image, once
|
|
169
|
+
openroboto train # starts it for you, data and strategy mounted in
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The training image definition ships **inside the package**. There is nothing to
|
|
173
|
+
clone, nothing to keep in sync, and no network needed to build it. You do need
|
|
174
|
+
Docker on the host.
|
|
175
|
+
|
|
176
|
+
### Running the CLI in a container too (optional, needs a clone)
|
|
177
|
+
|
|
178
|
+
Separately, the `Dockerfile` and `docker-compose.yml` **in this repository** put
|
|
179
|
+
the CLI itself in a container, for people who would rather not install it into
|
|
180
|
+
their host Python. That is a repository-level convenience: `openroboto init` does
|
|
181
|
+
**not** write these files into your workspace, because a compose file that builds
|
|
182
|
+
the CLI image would need this repository's build context anyway.
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
git clone https://github.com/openroboto-ai/openroboto-cli && cd openroboto-cli
|
|
186
|
+
docker compose up train
|
|
187
|
+
docker compose run --rm train submit --config miner.yaml
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
There is deliberately no `submit` service — a compose service can be restarted, and
|
|
191
|
+
restarting a command that burns non-refundable TAO is not something to leave to a
|
|
192
|
+
restart policy.
|
|
193
|
+
|
|
194
|
+
⚠️ This compose file mounts the Docker socket so the containerised CLI can start
|
|
195
|
+
the training container. That grants host root to the container; run it only on
|
|
196
|
+
your own machine. Installing with `pip` avoids that entirely, which is why it is
|
|
197
|
+
the documented path.
|
|
198
|
+
|
|
199
|
+
## Public trust boundary
|
|
200
|
+
|
|
201
|
+
Public: miner participation, local training, Hugging Face upload, burn and chain
|
|
202
|
+
announcement; chain commitment formats and weight-setting logic; evaluation rules,
|
|
203
|
+
baseline methodology, LIBERO tooling and seed derivation; the miner-visible
|
|
204
|
+
`control.json` schema and the read-only API contract.
|
|
205
|
+
|
|
206
|
+
Not here: held-out task data, the scoring-service deployment, and subnet-owner
|
|
207
|
+
operational tooling.
|
|
208
|
+
|
|
209
|
+
Seed derivation is public precisely because publishing it gives nothing away — the
|
|
210
|
+
future block hash and drand value do not exist at submission time.
|
|
211
|
+
|
|
212
|
+
## Development
|
|
213
|
+
|
|
214
|
+
For contributors. Skip this if you installed from PyPI.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
git clone https://github.com/openroboto-ai/openroboto-cli
|
|
218
|
+
cd openroboto-cli
|
|
219
|
+
uv sync --locked
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
One repository is enough: `openroboto-protocol` is installed from PyPI at the exact
|
|
223
|
+
version pinned in `pyproject.toml`. To work against unreleased protocol changes,
|
|
224
|
+
override it in your environment only —
|
|
225
|
+
`uv pip install -e ../openroboto-protocol` — and do not commit a
|
|
226
|
+
`[tool.uv.sources]` path entry. A path source **bypasses the version constraint**,
|
|
227
|
+
which is how the pin once read `==1.0.0` while every local and CI run was actually
|
|
228
|
+
using `0.2.0`.
|
|
229
|
+
|
|
230
|
+
`--locked` is deliberate: it fails when `uv.lock` no longer matches `pyproject.toml`
|
|
231
|
+
instead of silently resolving a different dependency tree. The interpreter is pinned to
|
|
232
|
+
Python 3.11 by `.python-version` — the version miners run.
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
bash scripts/lint.sh # mypy + ruff check + ruff format
|
|
236
|
+
uv run pytest -q # no GPU, no chain, no network
|
|
237
|
+
uv run coverage run --source=src -m pytest -q
|
|
238
|
+
uv run coverage report # fails below the threshold in pyproject.toml
|
|
239
|
+
uvx pre-commit install # optional: the same lint on every commit
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`.github/workflows/ci.yml` runs these same commands — `scripts/lint.sh` is the single
|
|
243
|
+
definition of "lint", so local and CI cannot drift. CI also fails on any skipped test:
|
|
244
|
+
nothing here needs hardware or credentials, so a skip means a test was switched off.
|
|
245
|
+
|
|
246
|
+
Protocol constants (commitment encoding, seed derivation, shared vocabularies) come
|
|
247
|
+
from `openroboto-protocol` and are never copied in here.
|
|
248
|
+
`.github/workflows/protocol-guards.yml` enforces that and that the dependency is pinned
|
|
249
|
+
to an exact version — a floating range would let the miner side and the backend side
|
|
250
|
+
resolve different code, which is the one thing that package exists to prevent.
|
|
251
|
+
|
|
252
|
+
## Releasing
|
|
253
|
+
|
|
254
|
+
Both pre-releases and stable releases go to PyPI, and the version number is what
|
|
255
|
+
separates them:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
git tag v0.1.0a1 && git push origin v0.1.0a1 # internal testing build
|
|
259
|
+
git tag v0.1.0 && git push origin v0.1.0 # stable
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The tag triggers the same gates every pull request runs, and the `pypi`
|
|
263
|
+
environment only accepts `v*` tags, so a stray branch build cannot reach the
|
|
264
|
+
index.
|
|
265
|
+
|
|
266
|
+
It then waits for a reviewer to approve the `pypi` environment. Uploads cannot be
|
|
267
|
+
undone and a version number can never be reused, so that approval is the last
|
|
268
|
+
thing standing between a typo and every miner.
|
|
269
|
+
|
|
270
|
+
Testers install a pre-release by pinning it exactly — no extra index flags:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
pip install openroboto==0.1.0a1
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
pip does not pick pre-releases when a stable release exists, so a miner running
|
|
277
|
+
`pip install openroboto` will never land on one.
|
|
278
|
+
|
|
279
|
+
> ⚠️ **One exception, while it lasts.** `openroboto` has no stable release yet,
|
|
280
|
+
> and pip *does* select a pre-release when nothing stable is available. Until
|
|
281
|
+
> `0.1.0` ships, an alpha on PyPI is what a bare `pip install openroboto` gets.
|
|
282
|
+
> Either publish `0.1.0` early, or yank the alphas once testing is done — a
|
|
283
|
+
> yanked version is skipped by the resolver unless pinned exactly, and anyone who
|
|
284
|
+
> already installed it keeps working.
|
|
285
|
+
|
|
286
|
+
`workflow_dispatch` publishes to TestPyPI instead. That path exists to rehearse
|
|
287
|
+
the pipeline itself — `uv publish`, the OIDC exchange, the approval gate — not to
|
|
288
|
+
distribute test builds. It can never reach real PyPI.
|
|
289
|
+
|
|
290
|
+
## Repository map
|
|
291
|
+
|
|
292
|
+
| Path | Purpose |
|
|
293
|
+
|---|---|
|
|
294
|
+
| `src/openroboto/` | The package: `commands/`, `chain/`, `huggingface/`, `payment/`, `config/`, `training/`, `templates/` |
|
|
295
|
+
| `src/openroboto/runner/` | Training-image build context (Dockerfile + the in-container entry script), **shipped in the wheel** so `openroboto build` works offline |
|
|
296
|
+
| `docs/` | Miner, validator and reproducibility documentation — index at [docs/README.md](docs/README.md) |
|
|
297
|
+
| `tests/` | Mirrors `src/`; needs no GPU, chain or network |
|
|
298
|
+
| `Dockerfile`, `docker-compose.yml` | Optional containerised way to run the CLI |
|
|
299
|
+
|
|
300
|
+
The old flat layout (`rt.py`, `miner.py`, `payment.py`, `validator.py`, `miner/`,
|
|
301
|
+
`utils/`, `protocol/`) was removed on 2026-08-19; the package replaces all of it. It
|
|
302
|
+
remains in git history, and [docs/MIGRATION.md](docs/MIGRATION.md) maps every old
|
|
303
|
+
command to its replacement.
|
|
304
|
+
|
|
305
|
+
Local configuration, runtime state, logs, caches and model weights are excluded by
|
|
306
|
+
`.gitignore`.
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# openroboto
|
|
2
|
+
|
|
3
|
+
The command-line tool for mining on **OpenRoboto**, a Bittensor mainnet subnet
|
|
4
|
+
(netuid 80) that rewards improvements to vision-language-action models.
|
|
5
|
+
|
|
6
|
+
You fine-tune π₀.₅ on LIBERO, publish the checkpoint to Hugging Face, pay a small
|
|
7
|
+
on-chain evaluation fee, and announce it. The subnet evaluates every submission in
|
|
8
|
+
simulation with a seed nobody can predict, ranks the results, and pays emissions by
|
|
9
|
+
rank.
|
|
10
|
+
|
|
11
|
+
Everything you type is this one package. **There is nothing to clone.**
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install openroboto
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
[Docs index](docs/README.md) · [How the subnet works](docs/SUBNET_OVERVIEW.md) ·
|
|
18
|
+
[Migrating from `rt.py`](docs/MIGRATION.md) ·
|
|
19
|
+
[Evaluation toolkit](https://github.com/openroboto-ai/openroboto-evaluation)
|
|
20
|
+
|
|
21
|
+
> **Upgrading from a clone of this repository?** `python miner.py` and
|
|
22
|
+
> `python rt.py submit` were removed on 2026-08-19. See
|
|
23
|
+
> [docs/MIGRATION.md](docs/MIGRATION.md) for the command map — your existing
|
|
24
|
+
> `miner.yaml` and `state/round_N.json` still work.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
- Linux, an NVIDIA GPU (24 GB VRAM minimum) and a recent driver
|
|
31
|
+
- Python **3.11**
|
|
32
|
+
- Docker with the NVIDIA Container Toolkit — training runs in a container because
|
|
33
|
+
openpi needs `numpy<2.0` and bittensor needs `numpy>=2.0`; one interpreter cannot
|
|
34
|
+
hold both
|
|
35
|
+
- A registered Bittensor mainnet hotkey with enough TAO for the evaluation fee
|
|
36
|
+
- A Hugging Face account and a write token
|
|
37
|
+
|
|
38
|
+
## Your first submission
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# 1. Install and scaffold
|
|
42
|
+
pip install openroboto
|
|
43
|
+
openroboto init my-miner # a ready-to-use workspace: miner.yaml,
|
|
44
|
+
# train_strategy.py, README.md, .gitignore
|
|
45
|
+
cd my-miner
|
|
46
|
+
$EDITOR miner.yaml # hotkey_ss58, HF token + username, control.json URL
|
|
47
|
+
|
|
48
|
+
# 2. Check everything BEFORE anything costs money
|
|
49
|
+
openroboto doctor # GPU, Docker, HF permissions, balance, config
|
|
50
|
+
|
|
51
|
+
# 3. Build the training image, then train one round
|
|
52
|
+
openroboto build
|
|
53
|
+
openroboto train
|
|
54
|
+
|
|
55
|
+
# 4. Verify the checkpoint format — still free
|
|
56
|
+
openroboto check
|
|
57
|
+
|
|
58
|
+
# 5. Upload, pay the fee, announce on chain
|
|
59
|
+
openroboto submit
|
|
60
|
+
|
|
61
|
+
# 6. See what the subnet made of it
|
|
62
|
+
openroboto status
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Steps 2 and 4 exist for one reason: **burns are not refundable.** The most expensive
|
|
66
|
+
mistake on this subnet is discovering after paying that the upload was a bare LoRA
|
|
67
|
+
adapter. `doctor` and `check` are free and catch that.
|
|
68
|
+
|
|
69
|
+
Full walkthrough: [docs/MINER.md](docs/MINER.md).
|
|
70
|
+
Real-machine setup, systemd, custom strategies: [docs/MINER_DEPLOY.md](docs/MINER_DEPLOY.md).
|
|
71
|
+
|
|
72
|
+
## Commands
|
|
73
|
+
|
|
74
|
+
| Command | What it does |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `openroboto init [DIR] [-s simple\|example] [--validator]` | 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 |
|
|
77
|
+
| `openroboto doctor` | Environment check: Python, config, `control.json`, Docker, GPU, image, HF token, wallet balance |
|
|
78
|
+
| `openroboto build` | Build the training image from the build context shipped inside the package (no clone, no network) |
|
|
79
|
+
| `openroboto train [-s script.py]` | Run one round; your strategy script is mounted into the container |
|
|
80
|
+
| `openroboto check [PATH]` | Verify checkpoint layout with the rules the evaluator uses — **no GPU, no network, no second repository** |
|
|
81
|
+
| `openroboto upload / burn / announce` | The three submission steps, individually — for recovery, not routine use |
|
|
82
|
+
| `openroboto submit [--force]` | All three, resumable from `state/round_N.json` |
|
|
83
|
+
| `openroboto status [--hotkey]` | Submission history and scanner rejection reasons (no API key needed) |
|
|
84
|
+
| `openroboto validator run` | External validator: read published weights, set them on chain |
|
|
85
|
+
| `openroboto --version` | CLI version and protocol package version |
|
|
86
|
+
|
|
87
|
+
⚠️ **`openroboto merge` does not exist yet.** Training produces a LoRA adapter, and a
|
|
88
|
+
bare adapter is rejected — merging it into the base model is currently a manual step.
|
|
89
|
+
`openroboto check` catches an unmerged upload before you pay.
|
|
90
|
+
|
|
91
|
+
## Things that will cost you TAO if you skip them
|
|
92
|
+
|
|
93
|
+
The fee is published live in `control.json`; on mainnet today it is 0.1 TAO. Never
|
|
94
|
+
hard-code it — the CLI reads it, and **refuses to burn if it cannot** rather than
|
|
95
|
+
guessing an amount the backend would reject.
|
|
96
|
+
|
|
97
|
+
**Do not run `burn` and `announce` as separate steps unless you are recovering.** The
|
|
98
|
+
backend only accepts a submission whose burn is within **50 blocks (~10 minutes)** of
|
|
99
|
+
the chain commitment; this stops a single fee being reused across submissions. Past
|
|
100
|
+
that window the submission is rejected and the fee is gone. `openroboto submit` runs
|
|
101
|
+
the three steps back-to-back so you stay inside it, and `announce` refuses to publish
|
|
102
|
+
once the window has closed instead of charging you a second fee for a doomed
|
|
103
|
+
submission.
|
|
104
|
+
|
|
105
|
+
Details: [docs/PAYMENT.md](docs/PAYMENT.md).
|
|
106
|
+
|
|
107
|
+
## Submission format
|
|
108
|
+
|
|
109
|
+
The evaluator accepts **complete model checkpoints** — an openpi JAX `params/`
|
|
110
|
+
directory or a PyTorch `model.safetensors`, plus
|
|
111
|
+
`assets/physical-intelligence/libero/norm_stats.json`. A bare LoRA adapter is rejected
|
|
112
|
+
by a CPU pre-check before any GPU time is spent.
|
|
113
|
+
|
|
114
|
+
Exact requirements: [docs/SUBNET_OVERVIEW.md](docs/SUBNET_OVERVIEW.md).
|
|
115
|
+
|
|
116
|
+
## Verify your evaluation seed
|
|
117
|
+
|
|
118
|
+
Your seed is derived from three public values that did not exist when you submitted —
|
|
119
|
+
the block hash that carried your commitment, the round number, and a drand beacon
|
|
120
|
+
value. Nobody, including the subnet operator, can pick a seed for a specific miner.
|
|
121
|
+
You can recompute it:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pip install openroboto-protocol
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from openroboto_protocol.seed import derive_seed
|
|
129
|
+
|
|
130
|
+
seed = derive_seed(block_hash, round_num, drand_randomness)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The backend and this CLI import that exact function — not a copy of it.
|
|
134
|
+
Formula, drand chain identifier and security assumptions:
|
|
135
|
+
[docs/SEED_GENERATION.md](docs/SEED_GENERATION.md).
|
|
136
|
+
|
|
137
|
+
## Docker: what runs where
|
|
138
|
+
|
|
139
|
+
Training **always** runs in a container — openpi needs `numpy<2.0` and bittensor
|
|
140
|
+
needs `numpy>=2.0`, so one interpreter cannot hold both. You do not have to
|
|
141
|
+
arrange that:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
openroboto build # builds the training image, once
|
|
145
|
+
openroboto train # starts it for you, data and strategy mounted in
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The training image definition ships **inside the package**. There is nothing to
|
|
149
|
+
clone, nothing to keep in sync, and no network needed to build it. You do need
|
|
150
|
+
Docker on the host.
|
|
151
|
+
|
|
152
|
+
### Running the CLI in a container too (optional, needs a clone)
|
|
153
|
+
|
|
154
|
+
Separately, the `Dockerfile` and `docker-compose.yml` **in this repository** put
|
|
155
|
+
the CLI itself in a container, for people who would rather not install it into
|
|
156
|
+
their host Python. That is a repository-level convenience: `openroboto init` does
|
|
157
|
+
**not** write these files into your workspace, because a compose file that builds
|
|
158
|
+
the CLI image would need this repository's build context anyway.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
git clone https://github.com/openroboto-ai/openroboto-cli && cd openroboto-cli
|
|
162
|
+
docker compose up train
|
|
163
|
+
docker compose run --rm train submit --config miner.yaml
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
There is deliberately no `submit` service — a compose service can be restarted, and
|
|
167
|
+
restarting a command that burns non-refundable TAO is not something to leave to a
|
|
168
|
+
restart policy.
|
|
169
|
+
|
|
170
|
+
⚠️ This compose file mounts the Docker socket so the containerised CLI can start
|
|
171
|
+
the training container. That grants host root to the container; run it only on
|
|
172
|
+
your own machine. Installing with `pip` avoids that entirely, which is why it is
|
|
173
|
+
the documented path.
|
|
174
|
+
|
|
175
|
+
## Public trust boundary
|
|
176
|
+
|
|
177
|
+
Public: miner participation, local training, Hugging Face upload, burn and chain
|
|
178
|
+
announcement; chain commitment formats and weight-setting logic; evaluation rules,
|
|
179
|
+
baseline methodology, LIBERO tooling and seed derivation; the miner-visible
|
|
180
|
+
`control.json` schema and the read-only API contract.
|
|
181
|
+
|
|
182
|
+
Not here: held-out task data, the scoring-service deployment, and subnet-owner
|
|
183
|
+
operational tooling.
|
|
184
|
+
|
|
185
|
+
Seed derivation is public precisely because publishing it gives nothing away — the
|
|
186
|
+
future block hash and drand value do not exist at submission time.
|
|
187
|
+
|
|
188
|
+
## Development
|
|
189
|
+
|
|
190
|
+
For contributors. Skip this if you installed from PyPI.
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
git clone https://github.com/openroboto-ai/openroboto-cli
|
|
194
|
+
cd openroboto-cli
|
|
195
|
+
uv sync --locked
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
One repository is enough: `openroboto-protocol` is installed from PyPI at the exact
|
|
199
|
+
version pinned in `pyproject.toml`. To work against unreleased protocol changes,
|
|
200
|
+
override it in your environment only —
|
|
201
|
+
`uv pip install -e ../openroboto-protocol` — and do not commit a
|
|
202
|
+
`[tool.uv.sources]` path entry. A path source **bypasses the version constraint**,
|
|
203
|
+
which is how the pin once read `==1.0.0` while every local and CI run was actually
|
|
204
|
+
using `0.2.0`.
|
|
205
|
+
|
|
206
|
+
`--locked` is deliberate: it fails when `uv.lock` no longer matches `pyproject.toml`
|
|
207
|
+
instead of silently resolving a different dependency tree. The interpreter is pinned to
|
|
208
|
+
Python 3.11 by `.python-version` — the version miners run.
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
bash scripts/lint.sh # mypy + ruff check + ruff format
|
|
212
|
+
uv run pytest -q # no GPU, no chain, no network
|
|
213
|
+
uv run coverage run --source=src -m pytest -q
|
|
214
|
+
uv run coverage report # fails below the threshold in pyproject.toml
|
|
215
|
+
uvx pre-commit install # optional: the same lint on every commit
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`.github/workflows/ci.yml` runs these same commands — `scripts/lint.sh` is the single
|
|
219
|
+
definition of "lint", so local and CI cannot drift. CI also fails on any skipped test:
|
|
220
|
+
nothing here needs hardware or credentials, so a skip means a test was switched off.
|
|
221
|
+
|
|
222
|
+
Protocol constants (commitment encoding, seed derivation, shared vocabularies) come
|
|
223
|
+
from `openroboto-protocol` and are never copied in here.
|
|
224
|
+
`.github/workflows/protocol-guards.yml` enforces that and that the dependency is pinned
|
|
225
|
+
to an exact version — a floating range would let the miner side and the backend side
|
|
226
|
+
resolve different code, which is the one thing that package exists to prevent.
|
|
227
|
+
|
|
228
|
+
## Releasing
|
|
229
|
+
|
|
230
|
+
Both pre-releases and stable releases go to PyPI, and the version number is what
|
|
231
|
+
separates them:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
git tag v0.1.0a1 && git push origin v0.1.0a1 # internal testing build
|
|
235
|
+
git tag v0.1.0 && git push origin v0.1.0 # stable
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The tag triggers the same gates every pull request runs, and the `pypi`
|
|
239
|
+
environment only accepts `v*` tags, so a stray branch build cannot reach the
|
|
240
|
+
index.
|
|
241
|
+
|
|
242
|
+
It then waits for a reviewer to approve the `pypi` environment. Uploads cannot be
|
|
243
|
+
undone and a version number can never be reused, so that approval is the last
|
|
244
|
+
thing standing between a typo and every miner.
|
|
245
|
+
|
|
246
|
+
Testers install a pre-release by pinning it exactly — no extra index flags:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
pip install openroboto==0.1.0a1
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
pip does not pick pre-releases when a stable release exists, so a miner running
|
|
253
|
+
`pip install openroboto` will never land on one.
|
|
254
|
+
|
|
255
|
+
> ⚠️ **One exception, while it lasts.** `openroboto` has no stable release yet,
|
|
256
|
+
> and pip *does* select a pre-release when nothing stable is available. Until
|
|
257
|
+
> `0.1.0` ships, an alpha on PyPI is what a bare `pip install openroboto` gets.
|
|
258
|
+
> Either publish `0.1.0` early, or yank the alphas once testing is done — a
|
|
259
|
+
> yanked version is skipped by the resolver unless pinned exactly, and anyone who
|
|
260
|
+
> already installed it keeps working.
|
|
261
|
+
|
|
262
|
+
`workflow_dispatch` publishes to TestPyPI instead. That path exists to rehearse
|
|
263
|
+
the pipeline itself — `uv publish`, the OIDC exchange, the approval gate — not to
|
|
264
|
+
distribute test builds. It can never reach real PyPI.
|
|
265
|
+
|
|
266
|
+
## Repository map
|
|
267
|
+
|
|
268
|
+
| Path | Purpose |
|
|
269
|
+
|---|---|
|
|
270
|
+
| `src/openroboto/` | The package: `commands/`, `chain/`, `huggingface/`, `payment/`, `config/`, `training/`, `templates/` |
|
|
271
|
+
| `src/openroboto/runner/` | Training-image build context (Dockerfile + the in-container entry script), **shipped in the wheel** so `openroboto build` works offline |
|
|
272
|
+
| `docs/` | Miner, validator and reproducibility documentation — index at [docs/README.md](docs/README.md) |
|
|
273
|
+
| `tests/` | Mirrors `src/`; needs no GPU, chain or network |
|
|
274
|
+
| `Dockerfile`, `docker-compose.yml` | Optional containerised way to run the CLI |
|
|
275
|
+
|
|
276
|
+
The old flat layout (`rt.py`, `miner.py`, `payment.py`, `validator.py`, `miner/`,
|
|
277
|
+
`utils/`, `protocol/`) was removed on 2026-08-19; the package replaces all of it. It
|
|
278
|
+
remains in git history, and [docs/MIGRATION.md](docs/MIGRATION.md) maps every old
|
|
279
|
+
command to its replacement.
|
|
280
|
+
|
|
281
|
+
Local configuration, runtime state, logs, caches and model weights are excluded by
|
|
282
|
+
`.gitignore`.
|
|
283
|
+
|
|
284
|
+
## License
|
|
285
|
+
|
|
286
|
+
See [LICENSE](LICENSE).
|