@flop-labs/cli 0.0.0-stage → 0.4.1

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 (5) hide show
  1. package/CHANGELOG.md +233 -0
  2. package/LICENSE +238 -0
  3. package/README.md +501 -2
  4. package/dist/cli.js +13237 -0
  5. package/package.json +55 -3
package/README.md CHANGED
@@ -1,3 +1,502 @@
1
- # Temporary Holding Version
1
+ # @flop-labs/cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ FLOP Network CLI — interact with FLOP Network nodes from the command line.
4
+
5
+ ## Installation
6
+
7
+ The full CLI (key, miner, validator and model commands) needs Node.js 22+. Run a pinned release
8
+ from public npm without installing it globally:
9
+
10
+ ```bash
11
+ npx --yes --package @flop-labs/cli@0.4.0 flop --version
12
+ ```
13
+
14
+ Or run the promoted container image, which needs only Docker. For a reproducible digest pin,
15
+ use [releases.json](https://flop.network/releases.json). The image starts in `/app`, so mount
16
+ your working directory and pass absolute paths under it:
17
+
18
+ ```bash
19
+ docker run --rm --network host -v "$PWD:/work" \
20
+ ghcr.io/flop-labs/flop-core/cli:stable \
21
+ --version
22
+ ```
23
+
24
+ `npm install --global @flop-labs/cli` also works, but it puts a second `flop` on `PATH`: the
25
+ public Hermes launcher's installer below refuses to install next to it, and the two commands
26
+ shadow each other.
27
+
28
+ For the recommended public native Hermes provider path, install the standalone launcher without repository
29
+ or package-registry access:
30
+
31
+ ```sh
32
+ curl -fsSL https://flop.network/releases/cli/0.4.11/install.sh | sh -s -- --version 0.4.11
33
+ export PATH="$HOME/.local/bin:$PATH"
34
+ flop --network devnet hermes desktop --doctor
35
+ ```
36
+
37
+ This release needs Node.js 22+, curl and the qualified Hermes 0.22.2 release. It contains the hosted
38
+ Hermes commands and the native public provider 0.1.6 and preserves an existing full CLI. See the
39
+ public launcher guide (`docs/integrations/hermes-public-launcher.md` in the FLOP repository) for
40
+ the native setup sequence, checksums, the 24-hour trial and acceptance limits.
41
+ The alternate hosted launcher needs explicit preparation of its generated Hermes
42
+ home; it is not qualified as a one-step launch on a fresh managed installation. The full CLI
43
+ source build remains:
44
+
45
+ ```bash
46
+ pnpm install --frozen-lockfile
47
+ pnpm --filter @flop-labs/gateway-core build
48
+ pnpm --filter @flop-labs/sdk exec tsc
49
+ pnpm --filter @flop-labs/sdk run build:a2a-cjs
50
+ pnpm --filter @flop-labs/agent-sdk exec tsc
51
+ pnpm --filter @flop-labs/cli build
52
+ node sdk/cli/dist/cli.js --version # from the repository root
53
+ ```
54
+
55
+ ## Usage
56
+
57
+ ```bash
58
+ flop [options] [command]
59
+ ```
60
+
61
+ ### Global Options
62
+
63
+ | Option | Description | Default |
64
+ |--------|-------------|---------|
65
+ | `--network <name>` | `local`, `devnet`, `testnet`, or `mainnet` | `local` |
66
+ | `--rpc <url>` | Explicit RPC override | selected profile |
67
+ | `--signer <uri>` | Local signer URI | `//Alice` on local only |
68
+ | `--keystore <path>` | Encrypted Polkadot JSON keystore | — |
69
+ | `--password-env <name>` | Environment variable containing its password | — |
70
+ | `--output <mode>` | `human`, pretty `json`, or compact `agent` | `human` |
71
+ | `--json` | Output as JSON | false |
72
+
73
+ ### Commands
74
+
75
+ #### Unified role onboarding
76
+
77
+ The role commands provide one entry point for onboarding, diagnostics, status,
78
+ and lifecycle operations. `init` and `doctor` are read-only. Commands such as
79
+ `register`, `calibrate-start`, `commission`, `unjail`, `rejoin`, and `exit`
80
+ are explicit chain mutations.
81
+
82
+ ```bash
83
+ # Agents: the devnet tailnet MCP is read-only; local mode is signer-capable.
84
+ flop --network devnet agent init --client codex
85
+ flop --network devnet agent doctor
86
+ flop agent launch codex
87
+ flop agent proxy
88
+ flop agent hermes desktop
89
+ flop keys generate --out agent-key.json --password-env FLOP_KEY_PASSWORD
90
+ flop agent wallet create <agent-address>
91
+ flop agent session create --delegate <address>
92
+
93
+ # Miners: sim first, measured TDX for verified production, cloud is non-attested.
94
+ flop miner init --mode sim
95
+ flop miner doctor --mode sim
96
+ flop miner status [address]
97
+ flop --signer <MINER-URI> miner register --commission 10
98
+ flop --signer <MINER-URI> miner calibrate-start
99
+
100
+ # Validators: live stake minimum and PoUI-gated committee state are queried.
101
+ flop validator init --mode local
102
+ flop validator doctor
103
+ flop validator status [address]
104
+ flop --signer <VALIDATOR-URI> validator register
105
+ flop --signer <VALIDATOR-URI> validator commission 10
106
+ flop --signer <VALIDATOR-URI> validator unjail
107
+ flop --signer <VALIDATOR-URI> validator rejoin
108
+ flop --signer <VALIDATOR-URI> validator exit
109
+ ```
110
+
111
+ All role planning and diagnostic commands support `--json` for automation.
112
+ Global network and custody options work at any nesting depth.
113
+
114
+ #### Networks and faucet
115
+
116
+ ```bash
117
+ flop --network devnet network status
118
+ flop --network devnet faucet request <address>
119
+ flop --network testnet faucet request <address> --amount 25
120
+ flop --network mainnet network status # planned; no faucet
121
+ ```
122
+
123
+ Faucet requests compare the RPC and faucet `/chain` genesis hashes before
124
+ requesting funds. A recognized RPC conflicting with explicit `--network` is
125
+ rejected.
126
+
127
+ #### Agent-efficient output
128
+
129
+ Use `--output agent` for a stable, single-line JSON result with no banners,
130
+ emoji, indentation, or successful `doctor` checks:
131
+
132
+ ```bash
133
+ flop --output agent miner doctor --mode tdx
134
+ flop --output agent validator status <address>
135
+ flop --output agent agent init --client codex
136
+ ```
137
+
138
+ Successes include `ok:true`. Failures go to stderr with a nonzero exit and a
139
+ compact `code`, `message`, `retryable`, and optional `next` action. `--json`
140
+ remains the backward-compatible pretty JSON format. Interactive processes such
141
+ as `launch`, `proxy`, and Hermes itself retain their application output after
142
+ startup; use Hermes `--dry-run` for a one-shot agent-readable launch plan.
143
+
144
+ #### Health
145
+ ```bash
146
+ flop health # Human-readable
147
+ flop health --json # JSON output
148
+ ```
149
+
150
+ #### Balance
151
+ ```bash
152
+ flop balance 5Grwva8T1BQxqNJJM... # Check account balance
153
+ flop balance 5Grwva8... --json # JSON output
154
+ ```
155
+
156
+ #### GPU Detection
157
+ ```bash
158
+ flop gpu # Detect local GPUs
159
+ flop gpu --json # JSON output
160
+ ```
161
+
162
+ #### Declared GPU inventory
163
+ ```bash
164
+ nvidia-smi --query-gpu=name,memory.total --format=csv,noheader,nounits > gpus.csv
165
+ flop --keystore miner.json --password-env FLOP_KEY_PASSWORD miner declare-gpu --nvidia-smi gpus.csv
166
+ flop miner declare-gpu --detect --dry-run # on the GPU host itself; prints the remark only
167
+ flop --keystore miner.json --password-env FLOP_KEY_PASSWORD miner declare-gpu --retract # withdraw it
168
+ ```
169
+
170
+ A registered miner publishes the GPUs it runs as a signed `flop.gpu-inventory.v1` remark (format:
171
+ `docs/design/gpu-inventory-remark.md` in the FLOP repository), so explorers can show its hardware. It is
172
+ self-reported and display-only: calibration caps, SKU ceilings and rewards never read it. The CLI
173
+ image cannot run the host's `nvidia-smi`, so pass its output with `--nvidia-smi` (`-` reads stdin).
174
+
175
+ #### Stake Info
176
+ ```bash
177
+ flop info 5Grwva8... # Get miner stake info
178
+ ```
179
+
180
+ #### Session Keys
181
+ ```bash
182
+ flop session create --delegate <address> --daily-cap 50 --tx-limit 5
183
+ flop session list --owner <address>
184
+ flop --signer <DELEGATE-URI> chat --session-owner <OWNER> "hello"
185
+ flop --signer <DELEGATE-URI> proxy --session-owner <OWNER>
186
+ ```
187
+
188
+ Session inference checks activity, expiry, and per-tx/daily/lifetime budgets,
189
+ then submits the HTLC through `executeViaSession`. `chat` persists conversation
190
+ IDs and supports `--conversation`, `--history`, and `--delete`.
191
+
192
+ #### Named-miner inference
193
+
194
+ ```bash
195
+ flop --network devnet --keystore agent.json --password-env FLOP_KEY_PASSWORD \
196
+ session run --miner MINER_SS58 --model qwen/qwen2.5-0.5b-instruct \
197
+ --endpoint MINER_HTTPS_URL --prompt 'Reply OK.' --max-flop 0.01 --max-tokens 8 --json
198
+ ```
199
+
200
+ The completion limit defaults to 256 tokens. `--max-tokens` must be a positive safe
201
+ integer; `--max-flop` bounds escrow separately. JSON includes `finish_reason` and
202
+ `completion_tokens`; `length` means the response reached its token limit. The turn
203
+ deadline remains 60 seconds, so large token limits or slow inference can still time
204
+ out and follow normal channel recovery. Settlement separately waits for the miner's
205
+ on-chain calibrated allowance; faster inference does not bypass that limit. Legacy miners may require
206
+ `--auth-token-env MINER_SESSION_BEARER`.
207
+
208
+ #### Models
209
+
210
+ ```bash
211
+ flop model list
212
+ flop model get <hash-or-name> --precision FP16
213
+ flop model fetch <hash-or-name> --output-dir ./weights
214
+ flop model fetch <hash> --source hf:org/repo --precision INT8
215
+ flop --signer <PUBLISHER> model upload --model-hash <hash> --path ./weights
216
+ BASE=http://miner:8000 DECODE_POLICY_HASH=0x<hash> \
217
+ flop --network local model onboard --source org/model --precision BF16
218
+
219
+ # Existing-commitment recovery/advanced mode:
220
+ flop --signer <PUBLISHER> model upload \
221
+ --model-hash <hash> --commitment <0x-hash> --size <bytes>
222
+ ```
223
+
224
+ Fetch accepts `hf:`, `modelscope:`, HTTPS, and `da:` sources and writes only
225
+ after dm-verity matches the registered root. Full upload builds the canonical
226
+ image, runs `da-validator submit`, registers its leased blob, and binds it.
227
+ Onboard additionally registers the model, mirrors, per-precision measured root,
228
+ and decode policy, but only after the serving endpoint passes capture replay,
229
+ binding rejection, and output-coherence probes. Re-running it submits no writes.
230
+ `--hf-repo owner/model` gives a local `--source` a Hugging Face mirror, but only
231
+ after that repo reproduces the measured root. Re-running with it adds the mirror
232
+ to an already registered model.
233
+
234
+ #### Gateway configuration
235
+
236
+ ```bash
237
+ export MINER_GATEWAY_TOKEN='from-a-secret-manager'
238
+ flop gateway allowlist \
239
+ --miner https://miner.example \
240
+ --network devnet \
241
+ --auth-token-env MINER_GATEWAY_TOKEN \
242
+ --attestation ./gateway-attestation.json \
243
+ --json
244
+ ```
245
+
246
+ The command emits ready-to-use `GATEWAY_SESSION_ALLOWLIST` and
247
+ `GATEWAY_MODEL_CATALOG` string values. The selected network supplies the RPC
248
+ default. It anonymously probes `/session/info` first to require bearer auth,
249
+ then checks every advertised identity field against `model-registry`, including
250
+ the measured root and decode-policy allowlist, and checks the miner's calibration
251
+ against the finalized `hw-calibration` snapshot.
252
+
253
+ The attestation file uses `schema_version: "flop.gateway-attestation.v1"` and
254
+ contains `broker` limits, `deployment` evidence, and `catalog` evidence. The
255
+ catalog block is a `CanonicalModelRecord` without the generated identity fields
256
+ or `prices`; it carries one `price` snapshot instead. Deployment
257
+ `observedAt`/`expiresAt`, catalog price validity, and feature conformance are
258
+ used unchanged. Expired evidence is refused rather than refreshed.
259
+
260
+ ```bash
261
+ # GATEWAY_SESSION_ALLOWLIST / GATEWAY_MODEL_CATALOG hold the gateway's own values.
262
+ export GPUAI_API_KEY='from-a-secret-manager'
263
+ export GATEWAY_RENEWER_SIGNER_URI='dedicated funded account, not the broker signer'
264
+ flop --network devnet gateway renew \
265
+ --allowlist-env GATEWAY_SESSION_ALLOWLIST \
266
+ --catalog-env GATEWAY_MODEL_CATALOG --catalog-pricing chain \
267
+ --provider-key-env GPUAI_API_KEY \
268
+ --probe-signer-env GATEWAY_RENEWER_SIGNER_URI --probe-escrow 1 \
269
+ --out /opt/flop/gateway-evidence/gateway-evidence.json
270
+ ```
271
+
272
+ `gateway renew` re-makes that evidence instead of re-stamping it, and writes
273
+ the file the gateway hot-reloads as `GATEWAY_EVIDENCE_FILE`. A miner's
274
+ deployment is renewed only when GPU.ai still reports the instance named in
275
+ `deployment.source` (`operator-observed:gpu.ai/<instance> <region> <gpu>`,
276
+ optionally followed by a `(label)`) as `running` in that region on that GPU. The
277
+ GPU is GPU.ai's identifier (`rtx_a6000`) or its name in GPU.ai's GPU type table
278
+ (`RTX A6000`, with or without `NVIDIA`); any other name is not renewed. A
279
+ tailnet-hosted miner (`operator-observed:tailscale/<host> egress <ipv4> AS<n>`,
280
+ optionally followed by the network's name and a `(label)`) is renewed only while the
281
+ host's tailscaled (`--tailscale-socket`) sees exactly one node of that name online,
282
+ tagged `tag:miner`, on a direct path from that egress address; the country stamped
283
+ from that address therefore still holds. Its authenticated `/session/info` must also still advertise the pinned address,
284
+ enclave key, and identity that the
285
+ finalized chain still admits. A record's `tools` conformance is renewed only by
286
+ a real compute-channel turn, paid from the probe signer's escrow, whose signed
287
+ frames carry a `lookup` tool call with a JSON `query`. Each renewal keeps its
288
+ declared window length. Every other claimed feature has no probe yet and lapses.
289
+ Whatever is not renewed is left out of the file and lapses at its declared
290
+ expiry. The command exits 1 when anything lapses and never prints the allowlist.
291
+ Before each probe it requires one `--probe-escrow` free on the probe signer at the
292
+ finalized head. When the signer holds less, no further probe runs, and stderr says
293
+ `gateway renew: PROBE SIGNER UNDERFUNDED: …`.
294
+ The GPU.ai single-instance response shape (`status`, `region`, `gpu_type`) is
295
+ assumed from the pricing and create APIs, so watch the first run.
296
+
297
+ An operator can instead publish an already settled owner-requested tools qualification
298
+ without creating another probe or using the direct renewer's signer/provider credentials:
299
+
300
+ ```bash
301
+ flop --network devnet gateway renew \
302
+ --catalog-env GATEWAY_MODEL_CATALOG --catalog-pricing chain \
303
+ --qualification-receipt ./settled-tools-qualification.json \
304
+ --qualification-receipt-sha256 "$QUALIFICATION_RECEIPT_SHA256" \
305
+ --out /opt/flop/gateway-evidence/gateway-evidence.json
306
+ ```
307
+
308
+ The hash must identify the exact immutable receipt bytes. Receipt-only mode rejects the
309
+ direct-probe options. It verifies the original owner/resident/purpose envelope, signed
310
+ turn/prefix/ACK and canonical finalized positive settlement before appending one pass to
311
+ the existing evidence file. It preserves unrelated deployments and conformance entries,
312
+ keeps the proof-bound original probe time and existing declared window, and refuses a
313
+ conflicting re-publication. An identical receipt is a no-op. Concurrent `gateway renew`
314
+ commands using this version take an exclusive publication lock; a conflicting writer
315
+ fails rather than replacing its contents. Older or unrelated writers must be coordinated
316
+ separately. Receipt-only publication retains only this producer's latest unexpired pass
317
+ per exact model/feature identity, preserving its original times and all unrelated evidence.
318
+ A process killed while writing can leave `OUT.lock`; confirm that writer has stopped before
319
+ manually recovering that lock, and never remove another active writer's lock.
320
+ No fresh inference, escrow, signature submission or automatic publication by
321
+ the qualification endpoint occurs. Ordinary chat continues to require fresh tools
322
+ admission; a qualification request is not permission to run arbitrary stale-tools chat.
323
+
324
+ #### Keys, hardware, multisig, and air-gapped signing
325
+
326
+ ```bash
327
+ export FLOP_KEY_PASSWORD='from-a-secret-manager'
328
+ flop keys generate --name treasury --out treasury.json \
329
+ --password-env FLOP_KEY_PASSWORD
330
+ export FLOP_IMPORTED_SECRET='mnemonic from a secret manager'
331
+ flop keys import --secret-env FLOP_IMPORTED_SECRET --out imported.json \
332
+ --password-env FLOP_KEY_PASSWORD
333
+ flop keys export treasury.json --source-password-env FLOP_KEY_PASSWORD \
334
+ --out treasury-backup.json --password-env FLOP_BACKUP_PASSWORD
335
+ flop keys inspect treasury.json
336
+ flop keys hardware
337
+
338
+ flop multisig address --threshold 2 --signatory <A> <B> <C>
339
+ flop --keystore treasury.json --password-env FLOP_KEY_PASSWORD \
340
+ multisig propose --threshold 2 --other <B> <C> --call <0x-call>
341
+ flop multisig list --account <MULTISIG>
342
+
343
+ flop tx build --address <ADDRESS> --call <0x-call> \
344
+ --out unsigned.json --qr
345
+ flop tx broadcast unsigned.json --signature <0x-multisignature>
346
+ ```
347
+
348
+ `tx build` pins genesis, runtime, transaction version, and nonce. Broadcast
349
+ rejects drift. Terminal QR uses optional `qrencode`; the JSON envelope works
350
+ with Polkadot Vault, hardware wallets, HSM/MPC custody, or other detached
351
+ signers.
352
+
353
+ #### Wallets
354
+ ```bash
355
+ flop wallet agent create <agent-address> --daily-cap 50 --tx-limit 5
356
+ ```
357
+
358
+ #### Shared devnet agent credential
359
+ Provision one key for any supported agent client without launching Hermes:
360
+ ```bash
361
+ flop --network devnet agent credential # path, live model, quota; no bearer
362
+ flop --network devnet agent credential --json # non-secret metadata
363
+ flop --network devnet agent credential --print-key # secret on stdout for local auth helpers
364
+ flop --network devnet agent credential --tailnet # private lane for approved Tailscale users
365
+ ```
366
+ The command requires explicit `--network devnet`. By default it enrolls at the
367
+ public gateway `https://api.flop.network` with a wallet signature. On first use
368
+ it creates a local sr25519 account in `~/.flop/devnet-enroll-wallet.json`
369
+ (unencrypted, devnet only, mode 0600; its secret is never printed). If that
370
+ account holds less than 1 FLOP, it requests a grant from
371
+ `https://faucet.flop.network/fund` and waits for the grant to finalize on
372
+ `wss://rpc.devnet.flop.network` (`--rpc` overrides). It then signs the
373
+ gateway's single-use challenge. The key is cached in
374
+ `~/.flop/devnet-wallet-agent-key.json`. The operator must explicitly fund and configure the allowance; the recommended
375
+ casual-use grant is 20,000 devnet FLOP, scoped to the exact model returned by
376
+ enrollment, and expires within 24 hours. Re-enrolling
377
+ rotates the bearer but never renews quota or expiry.
378
+
379
+ `--tailnet` keeps the private lane for approved Tailscale users. It enrolls at
380
+ `http://gateway.ts.flop.network:3201/enroll` and gives a seven-day allowance,
381
+ cached in `~/.flop/devnet-agent-key.json` and shared with the Hermes provider.
382
+ Both caches are mode 0600 in a mode-0700 directory on POSIX systems. A `.lock`
383
+ directory per cache serializes enrollment across local clients. The
384
+ `--print-key` form is deliberately explicit; redirect or consume it privately
385
+ rather than recording terminal output. A stale `.lock` directory after a crash
386
+ can be removed only after confirming no enrollment is running.
387
+
388
+ `flop --network devnet agent init` and `agent doctor` use the public
389
+ `https://mcp.flop.network/mcp` read-only service by default; pass `--mcp-url`
390
+ to target another verified endpoint.
391
+
392
+ #### Hermes Desktop
393
+ The public native provider (`sdk/hermes_public`) is bundled with the
394
+ standalone launcher 0.4.5. Use `flop hermes plugin install` in an isolated
395
+ `HERMES_HOME` after `hermes pm repair`, then `hermes auth add flop-public`, `hermes model` and
396
+ `hermes desktop`. The separate private provider (`sdk/hermes_native`)
397
+ requires an approved Tailscale identity and FLOP repository access.
398
+ Follow the public native setup guide (`docs/integrations/hermes-public-launcher.md`,
399
+ "Native public provider") for the recommended public route. The full CLI also retains the private tailnet lane:
400
+ ```bash
401
+ flop --network devnet hermes desktop --dry-run --json # inspect without provisioning
402
+ flop --network devnet hermes desktop --gateway http://gateway.ts.flop.network # tailnet lane
403
+ ```
404
+ From a source checkout, replace `flop` with `node sdk/cli/dist/cli.js` after
405
+ the build above.
406
+ The alternate public hosted launcher requires managed-home preparation described
407
+ in the public guide; an immediate Desktop launch is not qualified. With the
408
+ tailnet `--gateway`, your Tailscale user ID must be approved first; request it with an
409
+ [access request](https://github.com/flop-labs/network/issues/new?template=access.yml). The CLI then obtains a seven-day, 25 FLOP model-scoped allowance and
410
+ stores the key in `~/.flop/devnet-agent-key.json` (mode 0600). Later launches
411
+ and other local agent clients check and reuse the cached key.
412
+ If the local key is lost or rejected, enrollment rotates the bearer while preserving
413
+ its spent amount and expiry. Exhausted, expired, and revoked allowances require an
414
+ operator to renew or reapprove them. Normal CLI output does not print the key.
415
+
416
+ Without `--network devnet`, the command starts the embedded signer proxy as before:
417
+ ```bash
418
+ flop hermes desktop # embedded proxy + launch Hermes
419
+ flop --signer //Bob hermes desktop # settle under //Bob
420
+ flop hermes desktop --model llama-3-8b-instruct --max-flop 10 --max-tokens 4096
421
+ flop hermes desktop --proxy-port 1234 # embedded proxy on a custom port
422
+ flop --network devnet --signer "$FLOP_SIGNER" hermes desktop --proxy # funded signer
423
+ flop hermes desktop --configure # also persist via `hermes config set`
424
+ flop hermes desktop --no-proxy \
425
+ --gateway http://gateway.ts.flop.network --model "$FLOP_MODEL"
426
+ flop hermes desktop --dry-run --json # print resolved env/launch plan, don't launch
427
+ ```
428
+ It wires Hermes to the embedded proxy via the env vars Hermes reads for a custom
429
+ OpenAI-compatible endpoint — `OPENAI_BASE_URL` (→ proxy `/v1`), `OPENAI_API_KEY`,
430
+ and `HERMES_INFERENCE_MODEL` (`api_mode` auto-detects `chat_completions`) — plus
431
+ `FLOP_WS_URL`/`FLOP_SIGNER` for the `@flop-labs/hermes-plugin`. `--configure`
432
+ additionally persists the wiring through the real `hermes config set` CLI
433
+ (`model.provider=custom`, `model.base_url`, `model.api_mode`, `model.default`).
434
+ Requires the Hermes binary (`hermes-desktop` or `hermes`) on `PATH`; use
435
+ `--dry-run` to inspect without it. A custom hosted `--gateway` requires
436
+ `FLOP_API_KEY` supplied privately and an explicit `--model` from the live
437
+ catalog. The CLI checks gateway health, model availability, and key validity
438
+ before launching. The private devnet gateway is reachable only from the FLOP
439
+ tailnet.
440
+
441
+ #### Local OpenAI Proxy
442
+ Expose a local OpenAI-compatible API (like LM Studio / Ollama's local server)
443
+ where **every request is submitted and settled on-chain under your signer**.
444
+ The proxy estimates G_n, submits the PoI task, waits for a TEE miner to settle
445
+ it, then returns the result — all behind the OpenAI REST schema:
446
+ ```bash
447
+ flop proxy # http://127.0.0.1:3201/v1
448
+ flop --signer //Bob proxy --max-flop 10
449
+ flop proxy --port 1234 --host 0.0.0.0 # expose beyond localhost
450
+ ```
451
+ | Endpoint | Purpose |
452
+ |----------|---------|
453
+ | `POST /v1/chat/completions` | Chat inference (OpenAI-compatible), `stream: true` supported |
454
+ | `POST /v1/completions` | Text completion, `stream: true` supported |
455
+ | `GET /v1/models` | List models (live from the payload gateway, falls back to defaults) |
456
+ | `GET /v1/models/{id}` | Retrieve a single model |
457
+ | `POST /v1/embeddings` | Embeddings, computed **locally** (no chain) — see below |
458
+ | `GET /health` | Liveness |
459
+ | `OPTIONS *` | CORS preflight (permissive, for browser/Electron clients) |
460
+
461
+ **Embeddings** are a cheap, high-frequency RAG primitive and don't need on-chain
462
+ settlement, so the proxy computes them **locally** with a small embedding model
463
+ (default `Xenova/all-MiniLM-L6-v2`, L2-normalized output like Ollama's
464
+ `/api/embed`). This needs the optional runtime dependency — install once:
465
+ ```bash
466
+ pnpm add @huggingface/transformers
467
+ ```
468
+ Without it, `/v1/embeddings` returns `501` with this hint (chat/completions are
469
+ unaffected). Override the model with `--embedding-model <hf-id>`.
470
+
471
+ **Streaming:** `stream: true` returns OpenAI SSE chunks (`data: {…}` … `data: [DONE]`),
472
+ incl. an optional usage chunk via `stream_options.include_usage`. FLOP settles a
473
+ task atomically, so this is *settle-then-stream*: the result is awaited, then
474
+ emitted as chunks (latency-to-first-token = settlement time), not incremental
475
+ miner generation.
476
+
477
+ **Models:** `/v1/models` reflects the payload gateway's registry
478
+ (`<payload-gateway>/v1/models`), falling back to the built-in defaults if it's
479
+ unreachable.
480
+
481
+ Options: `--port` (3201), `--host` (127.0.0.1), `--payload-gateway`
482
+ (off-chain prompt/result data plane, default `http://localhost:3200`),
483
+ `--model`, `--max-tokens` (default 2048), `--max-flop`. Uses global
484
+ `--rpc`/`--signer`. Point any OpenAI client at it via
485
+ `OPENAI_BASE_URL=http://127.0.0.1:3201/v1`.
486
+
487
+ ## Architecture
488
+
489
+ - Built with Commander.js
490
+ - Uses local SDK via `"@flop-labs/sdk": "file:../typescript"`
491
+ - TypeScript with ES modules, compiled via `tsc`
492
+ - All commands use `FlopClient.create()` from the SDK with `--rpc` and `--signer` global options
493
+ - Role groups reuse existing launch, proxy, key, wallet, session, staking, TDX,
494
+ and provider workflows rather than introducing parallel implementations.
495
+
496
+ Operator images: use `ghcr.io/flop-labs/flop-core/cli:stable` (minimum 0.1.172),
497
+ `ghcr.io/flop-labs/flop-core/miner-worker:stable` (minimum 0.1.172), and
498
+ `ghcr.io/flop-labs/flop-core/miner-vllm-toploc:stable` (minimum 0.1.172).
499
+ For a reproducible pin, use the version and digest in [releases.json](https://flop.network/releases.json).
500
+ `just miner-pack /tmp/flop-miner-pack` checks that manifest against the minimums, copies it, and sets the images to `:stable`.
501
+ The pack is for the public path, without the tailnet: public RPC, mailbox and sponsor, and
502
+ `docker-compose.tls.yml` for the session endpoint.