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.
Files changed (51) hide show
  1. openroboto-0.1.0a1/LICENSE +21 -0
  2. openroboto-0.1.0a1/PKG-INFO +310 -0
  3. openroboto-0.1.0a1/README.md +286 -0
  4. openroboto-0.1.0a1/pyproject.toml +187 -0
  5. openroboto-0.1.0a1/src/openroboto/__init__.py +61 -0
  6. openroboto-0.1.0a1/src/openroboto/backend_api.py +341 -0
  7. openroboto-0.1.0a1/src/openroboto/chain/__init__.py +35 -0
  8. openroboto-0.1.0a1/src/openroboto/chain/commitment.py +215 -0
  9. openroboto-0.1.0a1/src/openroboto/chain/connection.py +108 -0
  10. openroboto-0.1.0a1/src/openroboto/chain/weights.py +138 -0
  11. openroboto-0.1.0a1/src/openroboto/cli.py +139 -0
  12. openroboto-0.1.0a1/src/openroboto/commands/__init__.py +7 -0
  13. openroboto-0.1.0a1/src/openroboto/commands/announce.py +138 -0
  14. openroboto-0.1.0a1/src/openroboto/commands/build.py +104 -0
  15. openroboto-0.1.0a1/src/openroboto/commands/burn.py +117 -0
  16. openroboto-0.1.0a1/src/openroboto/commands/check.py +94 -0
  17. openroboto-0.1.0a1/src/openroboto/commands/doctor.py +400 -0
  18. openroboto-0.1.0a1/src/openroboto/commands/init.py +124 -0
  19. openroboto-0.1.0a1/src/openroboto/commands/status.py +165 -0
  20. openroboto-0.1.0a1/src/openroboto/commands/submit.py +78 -0
  21. openroboto-0.1.0a1/src/openroboto/commands/train.py +184 -0
  22. openroboto-0.1.0a1/src/openroboto/commands/upload.py +87 -0
  23. openroboto-0.1.0a1/src/openroboto/commands/validator.py +108 -0
  24. openroboto-0.1.0a1/src/openroboto/config/__init__.py +22 -0
  25. openroboto-0.1.0a1/src/openroboto/config/control.py +158 -0
  26. openroboto-0.1.0a1/src/openroboto/config/environments.py +194 -0
  27. openroboto-0.1.0a1/src/openroboto/config/settings.py +307 -0
  28. openroboto-0.1.0a1/src/openroboto/console.py +26 -0
  29. openroboto-0.1.0a1/src/openroboto/http_client.py +59 -0
  30. openroboto-0.1.0a1/src/openroboto/huggingface/__init__.py +19 -0
  31. openroboto-0.1.0a1/src/openroboto/huggingface/repository.py +49 -0
  32. openroboto-0.1.0a1/src/openroboto/huggingface/upload.py +149 -0
  33. openroboto-0.1.0a1/src/openroboto/logging.py +51 -0
  34. openroboto-0.1.0a1/src/openroboto/payment/__init__.py +9 -0
  35. openroboto-0.1.0a1/src/openroboto/payment/burn.py +153 -0
  36. openroboto-0.1.0a1/src/openroboto/preflight.py +146 -0
  37. openroboto-0.1.0a1/src/openroboto/py.typed +0 -0
  38. openroboto-0.1.0a1/src/openroboto/round_state.py +110 -0
  39. openroboto-0.1.0a1/src/openroboto/runner/Dockerfile +56 -0
  40. openroboto-0.1.0a1/src/openroboto/runner/train_runner.py +431 -0
  41. openroboto-0.1.0a1/src/openroboto/templates/README-miner.md +86 -0
  42. openroboto-0.1.0a1/src/openroboto/templates/README-validator.md +48 -0
  43. openroboto-0.1.0a1/src/openroboto/templates/example/train_strategy.py +113 -0
  44. openroboto-0.1.0a1/src/openroboto/templates/gitignore +31 -0
  45. openroboto-0.1.0a1/src/openroboto/templates/miner.yaml +81 -0
  46. openroboto-0.1.0a1/src/openroboto/templates/simple/train_strategy.py +167 -0
  47. openroboto-0.1.0a1/src/openroboto/templates/validator.yaml +35 -0
  48. openroboto-0.1.0a1/src/openroboto/training/__init__.py +30 -0
  49. openroboto-0.1.0a1/src/openroboto/training/container.py +354 -0
  50. openroboto-0.1.0a1/src/openroboto/training/dataset.py +117 -0
  51. 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).