badgr-cli 1.1.3 → 1.1.5
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.
- package/README.md +176 -13
- package/package.json +2 -1
- package/src/api.js +28 -0
- package/src/badgr.js +3 -3
- package/src/commands/artifacts.js +5 -3
- package/src/commands/batch.js +6 -5
- package/src/commands/billing.js +3 -3
- package/src/commands/capacity.js +2 -2
- package/src/commands/deploy.js +2 -2
- package/src/commands/diagnose.js +576 -82
- package/src/commands/down.js +69 -14
- package/src/commands/embed.js +2 -2
- package/src/commands/heartbeat.js +3 -3
- package/src/commands/job.js +14 -3
- package/src/commands/login.js +4 -1
- package/src/commands/logs.js +35 -18
- package/src/commands/pull.js +4 -3
- package/src/commands/rerun.js +5 -3
- package/src/commands/restart.js +5 -3
- package/src/commands/run.js +5 -23
- package/src/commands/sbatch.js +2 -1
- package/src/commands/serve.js +95 -18
- package/src/commands/shell.js +2 -2
- package/src/commands/status.js +57 -13
- package/src/commands/test-run.js +2 -2
- package/src/commands/train.js +3 -3
- package/src/commands/transcribe.js +2 -2
- package/src/commands/up.js +2 -1
- package/src/config.js +19 -0
- package/src/deploymentLog.js +45 -0
- package/src/errors.js +12 -3
- package/src/fallback.js +55 -32
- package/src/onboarding.js +63 -4
- package/src/progress.js +5 -2
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Badgr supports many GPU workloads through two commands: `serve` for persistent e
|
|
|
13
13
|
npm install -g badgr-cli
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
**Jump to:** [Quick start](#quick-start) · [Coding agents (`badgr launch`)](#coding--testing-agents-badgr-launch) · [Image generation](#also-try-image-generation) · [`badgr doctor`](#something-not-working-badgr-doctor) · [Commands](#commands) · [`serve` options](#badgr-serve-options) · [`run` options](#badgr-run-options) · [Receipts](#receipts) · [OpenAI compatibility](#openai-compatibility) · [GPU options](#gpu-options) · [Advanced](#advanced) · [Requirements](#requirements)
|
|
16
|
+
**Jump to:** [Quick start](#quick-start) · [Coding agents (`badgr launch`)](#coding--testing-agents-badgr-launch) · [Image generation](#also-try-image-generation) · [`badgr doctor`](#something-not-working-badgr-doctor) · [`badgr diagnose`](#diagnose-a-gpu-issue-badgr-diagnose) · [Commands](#commands) · [`serve` options](#badgr-serve-options) · [`run` options](#badgr-run-options) · [Receipts](#receipts) · [OpenAI compatibility](#openai-compatibility) · [GPU options](#gpu-options) · [Advanced](#advanced) · [Requirements](#requirements)
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
@@ -159,21 +159,78 @@ Run `badgr doctor --help` for the full flag list. Details in
|
|
|
159
159
|
|
|
160
160
|
---
|
|
161
161
|
|
|
162
|
+
## Badgr Smoke Test: `badgr diagnose`
|
|
163
|
+
|
|
164
|
+
Paste a GitHub issue, a Docker image, a repo URL, a log file, a ComfyUI
|
|
165
|
+
workflow, or a raw conversation — Badgr auto-detects the input, redacts
|
|
166
|
+
secrets, and runs free static checks as part of a Badgr Smoke Test.
|
|
167
|
+
Nothing runs on a GPU without explicit `--approve`.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# badgr diagnose IS the Badgr Smoke Test — free, no login, no GPU.
|
|
171
|
+
# Applicable free structural checks run automatically, every time.
|
|
172
|
+
badgr diagnose "https://github.com/org/repo/issues/123"
|
|
173
|
+
badgr diagnose ajayrajtp/vllm_gemma412b:latest
|
|
174
|
+
badgr diagnose ./vllm-error.log
|
|
175
|
+
badgr diagnose "https://github.com/org/repo"
|
|
176
|
+
badgr diagnose workflow.json
|
|
177
|
+
|
|
178
|
+
# Start a real Badgr Run (paid GPU execution) after diagnosis (login required)
|
|
179
|
+
badgr diagnose "https://github.com/org/repo/issues/123" --approve
|
|
180
|
+
|
|
181
|
+
# Resume an existing case, e.g. one shared via a case link
|
|
182
|
+
badgr diagnose repro_xxxxxxxx --approve
|
|
183
|
+
badgr diagnose "https://aibadgr.com/repro/repro_xxxxxxxx" --approve
|
|
184
|
+
|
|
185
|
+
# Machine-readable output
|
|
186
|
+
badgr diagnose "https://github.com/org/repo/issues/123" --json
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
| Flag | Description |
|
|
190
|
+
|------|-------------|
|
|
191
|
+
| `--approve` | Start a real Badgr Run after diagnosis — actual GPU execution, capped at a hard maximum spend (opens browser sign-in automatically if not logged in) |
|
|
192
|
+
| `--smoke` | Deprecated, no-op. The free mechanical checks this used to gate (syntax, CLI-entrypoint corroboration, referenced-file presence, Docker `ENTRYPOINT`/`CMD` consistency, required env vars, plus a client-side local-file check) now always run as part of plain `badgr diagnose`. Kept only so existing scripts that pass it don't break. Not the same as `badgr run --smoke`, which launches a real, billable GPU job |
|
|
193
|
+
| `--docker <image>` | Force Docker-image intake (override auto-detect) |
|
|
194
|
+
| `--repo <url>` | Force repository intake (override auto-detect) |
|
|
195
|
+
| `--comfyui <path>` | Force ComfyUI workflow intake (override auto-detect) |
|
|
196
|
+
| `--github <url>` | Include a GitHub issue URL found inside pasted text as additional context (opt-in, never fetched automatically) |
|
|
197
|
+
| `--json` | Machine-readable JSON output |
|
|
198
|
+
|
|
199
|
+
Every run prints one status: `NEEDS INFO` (fields still missing) →
|
|
200
|
+
`READY` (complete evidence-backed command, no applicable checks to run) →
|
|
201
|
+
`SMOKE CHECKED` (applicable checks ran, all passed or were skipped) /
|
|
202
|
+
`INVALID` (an applicable check actually failed) → `VERIFIED` (reserved for
|
|
203
|
+
an actual successful Badgr Run — never assigned from diagnosis alone).
|
|
204
|
+
`READY`/`SMOKE CHECKED` results also print the canonical `badgr
|
|
205
|
+
run`/`badgr serve` command `--approve` would run, plus a shareable case
|
|
206
|
+
link — pass that case ID or URL back into `badgr diagnose
|
|
207
|
+
<case_id_or_url> --approve` to resume the same case without re-diagnosing.
|
|
208
|
+
|
|
209
|
+
`badgr run-issue` is an alias for `badgr diagnose`, matching the
|
|
210
|
+
[aibadgr.com/run-issue](https://aibadgr.com/run-issue) Badgr Smoke Test
|
|
211
|
+
web flow.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
162
215
|
## Commands
|
|
163
216
|
|
|
164
217
|
```text
|
|
165
218
|
login
|
|
166
219
|
connect
|
|
167
220
|
doctor
|
|
221
|
+
diagnose
|
|
168
222
|
run
|
|
169
223
|
launch
|
|
170
|
-
|
|
224
|
+
job
|
|
171
225
|
serve
|
|
172
226
|
status
|
|
173
227
|
logs
|
|
174
228
|
pull
|
|
175
229
|
artifacts
|
|
176
230
|
down
|
|
231
|
+
restart
|
|
232
|
+
rerun
|
|
233
|
+
heartbeat
|
|
177
234
|
receipts
|
|
178
235
|
test
|
|
179
236
|
```
|
|
@@ -183,6 +240,7 @@ test
|
|
|
183
240
|
| `badgr login` | Save API key to `~/.badgr/config.json` |
|
|
184
241
|
| `badgr connect <provider>` | Store a provider credential (`anthropic`, `openai`) for `badgr launch` |
|
|
185
242
|
| `badgr doctor` | Diagnose a GPU workload failure — read-only, no login needed |
|
|
243
|
+
| `badgr diagnose "<input>"` | Run a Badgr Smoke Test on a GitHub issue, Docker image, repo, log, or workflow — free, no GPU until `--approve` |
|
|
186
244
|
| `badgr run <command>` | Run a one-off GPU job (any container command) |
|
|
187
245
|
| `badgr launch cline\|claude\|codex\|playwright "<task>"` | Run a coding/testing agent on a CPU VM — image + command auto-selected |
|
|
188
246
|
| `badgr job <agent> "<instruction>" --check "<cmd>"` | Tracked coding-agent job via `POST /v1/jobs` (type: agent) |
|
|
@@ -192,10 +250,13 @@ test
|
|
|
192
250
|
| `badgr pull <id>` | Pull a code-editing agent's patch as a local git diff/branch |
|
|
193
251
|
| `badgr artifacts <id>` | Download non-patch outputs (test reports, screenshots, traces) |
|
|
194
252
|
| `badgr down <id>` | Terminate a deployment — stops billing immediately |
|
|
253
|
+
| `badgr restart <id>` | Relaunch an endpoint with the same config, on a new deployment ID, keeping its API key |
|
|
254
|
+
| `badgr rerun <id>` | Replay a past job or endpoint with its exact original spec, on a new deployment ID |
|
|
255
|
+
| `badgr heartbeat <id>` | Reset an endpoint's idle-timeout clock (see `--idle-timeout` under [`badgr serve` options](#badgr-serve-options)) |
|
|
195
256
|
| `badgr receipts [n]` | Cost, route, and retry receipts (default 10) |
|
|
196
257
|
| `badgr test` | Run an end-to-end test (provision → run → teardown) |
|
|
197
258
|
|
|
198
|
-
More commands below, under [Advanced](#advanced): `comfyui`, `train`, `transcribe`, `embed`, `workload`, `workspace`, `batch`, `sbatch`, `capacity`, `billing`.
|
|
259
|
+
More commands below, under [Advanced](#advanced): `comfyui`, `train`, `transcribe`, `embed`, `workload`, `workspace`, `batch`, `sbatch`, `capacity`, `billing`, `models`, `template`.
|
|
199
260
|
|
|
200
261
|
`badgr serve` — for anything that needs a persistent endpoint: LLM serving, embeddings, image generation APIs, transcription APIs.
|
|
201
262
|
|
|
@@ -228,16 +289,38 @@ Each command section below lists only its own extra flags.
|
|
|
228
289
|
badgr serve meta-llama/Llama-3.1-8B-Instruct --gpu L40S --region EU
|
|
229
290
|
```
|
|
230
291
|
|
|
292
|
+
Endpoints bill continuously, so `serve` requires either `--max-cost` or `--persistent` (or `--dry-run` to just preview) — it refuses to start otherwise.
|
|
293
|
+
|
|
231
294
|
| Flag | Default | Description |
|
|
232
295
|
|------|---------|-------------|
|
|
233
296
|
| `--image <img>` | — | Serve a custom container instead of a HuggingFace model |
|
|
234
297
|
| `--task <task>` | — | vLLM task override, e.g. `embed` for embedding models |
|
|
235
|
-
| `--
|
|
298
|
+
| `--runtime llama.cpp\|ollama` | vLLM | Serve via a different runtime instead of vLLM |
|
|
299
|
+
| `--hf-repo <repo>` | — | HuggingFace repo for a GGUF file (with `--runtime llama.cpp`), e.g. `org/model-repo` |
|
|
300
|
+
| `--hf-file <file>` | — | GGUF filename within that repo, e.g. `model.gguf` (required with `--runtime llama.cpp`) |
|
|
301
|
+
| `--idle-timeout <min>` | — | Auto-stop after N minutes with no `badgr heartbeat` call — see [`badgr heartbeat`](#badgr-heartbeat) |
|
|
302
|
+
| `--persistent` | off | Run until manually stopped — satisfies the cost-control requirement in place of `--max-cost` |
|
|
303
|
+
| `--check-nodes <n1,n2>` | — | For ComfyUI-shaped images: verify custom nodes are installed after startup |
|
|
304
|
+
| `--health-path <path>` | auto | Readiness path to poll (auto-detected: ComfyUI → `/system_stats`, llama.cpp → `/health`) |
|
|
236
305
|
| `--no-wait` | off | Skip endpoint health check and return immediately |
|
|
306
|
+
| `--yes` / `-y` | off | Skip duplicate-deployment warning |
|
|
307
|
+
| `--dry-run` | — | Preview the plan (GPU, price) without provisioning |
|
|
237
308
|
| `--list-aliases` | — | List blessed vLLM model aliases (`qwen-7b`, `llama-8b`, `qwen-coder-7b`) and exit — no provisioning, no API key required |
|
|
238
309
|
|
|
239
310
|
Blessed aliases expand to a full model ID + preset GPU, e.g. `badgr serve qwen-7b` → `Qwen/Qwen2.5-7B-Instruct` on an RTX 4090. Run `badgr serve --list-aliases` to see the current list.
|
|
240
311
|
|
|
312
|
+
```bash
|
|
313
|
+
# Serve a Hugging Face GGUF file via llama.cpp instead of vLLM
|
|
314
|
+
badgr serve --runtime llama.cpp --hf-repo org/model-repo --hf-file model.gguf --max-cost 10
|
|
315
|
+
|
|
316
|
+
# Serve Open WebUI, a chat UI, pointed at a model endpoint
|
|
317
|
+
badgr serve openwebui --model qwen-7b --max-cost 10
|
|
318
|
+
badgr serve openwebui --connect <existing-endpoint-url> # connect to an endpoint you already have
|
|
319
|
+
|
|
320
|
+
# Auto-stop only when idle — requires periodic badgr heartbeat calls to stay up
|
|
321
|
+
badgr serve qwen-7b --idle-timeout 30 --max-cost 10
|
|
322
|
+
```
|
|
323
|
+
|
|
241
324
|
### Model support levels
|
|
242
325
|
|
|
243
326
|
`badgr serve qwen-7b` is the happy path — a tested route with no extra setup. `badgr serve` also accepts any other model ID or a custom container:
|
|
@@ -269,10 +352,21 @@ badgr run . --image mycompany/custom:latest --cmd "python train.py" --max-cost 5
|
|
|
269
352
|
|
|
270
353
|
Badgr zips and uploads the folder (Flow 1) or clones the repo (Flow 2), picks a generic runner, installs deps, runs the command, stores outputs for 48 hours, and tears down the GPU. `--max-cost` is required.
|
|
271
354
|
|
|
355
|
+
```bash
|
|
356
|
+
# No GPU needed — run on a plain CPU VM instead
|
|
357
|
+
badgr run . --cmd "npm test" --no-gpu --max-cost 1
|
|
358
|
+
|
|
359
|
+
# Describe basic compute needs instead of a GPU model — Badgr finds a compatible machine
|
|
360
|
+
badgr run . --cpu 16 --memory 64GB --gpu-memory 24GB --max-cost 5
|
|
361
|
+
```
|
|
362
|
+
|
|
272
363
|
| Flag | Default | Description |
|
|
273
364
|
|------|---------|-------------|
|
|
274
365
|
| `--cmd <command>` | — | Command to run inside the uploaded project or cloned repo (required for folder/GitHub flows) |
|
|
275
|
-
| `--min-vram <GB>` | — | Minimum VRAM in GB — optional constraint for Auto routing |
|
|
366
|
+
| `--min-vram <GB>` | — | Minimum VRAM in GB — optional constraint for Auto routing (alias: `--gpu-memory`) |
|
|
367
|
+
| `--cpu <cores>` | — | Minimum CPU cores (for a CPU-only run) |
|
|
368
|
+
| `--memory <size>` | — | Minimum RAM, e.g. `64GB` |
|
|
369
|
+
| `--no-gpu` | off | Run on a CPU-only VM — no GPU is provisioned (conflicts with `--gpu`/`--min-vram`) |
|
|
276
370
|
| `--image <img>` | — | Custom Docker image — bypasses the runner |
|
|
277
371
|
| `--max-runtime <min>` | — | Auto-stop after N minutes |
|
|
278
372
|
| `--save <name>` | — | Save this job as a named workload after it completes |
|
|
@@ -320,13 +414,14 @@ Productized batch image generation — runs a list of prompts through a **blesse
|
|
|
320
414
|
```bash
|
|
321
415
|
badgr comfyui batch --workflow sdxl-basic --prompts prompts.txt --max-cost 10
|
|
322
416
|
badgr comfyui batch --workflow sdxl-basic --prompt "a cat on a beach" --prompt "a dog in the park" --max-cost 5
|
|
417
|
+
badgr comfyui batch --workflow flux-basic --prompt "a neon city at night" --max-cost 5
|
|
323
418
|
```
|
|
324
419
|
|
|
325
|
-
Blessed workflows: `sdxl-basic` (SDXL text-to-image, default sampler settings). Max 20 prompts per batch.
|
|
420
|
+
Blessed workflows: `sdxl-basic` (SDXL text-to-image, default sampler settings), `flux-basic` (FLUX.1-schnell text-to-image). Max 20 prompts per batch.
|
|
326
421
|
|
|
327
422
|
| Flag | Default | Description |
|
|
328
423
|
|------|---------|-------------|
|
|
329
|
-
| `--workflow <name>` | — | Blessed workflow ID (required) —
|
|
424
|
+
| `--workflow <name>` | — | Blessed workflow ID (required) — `sdxl-basic` or `flux-basic` |
|
|
330
425
|
| `--prompts <file>` | — | Text file, one prompt per line |
|
|
331
426
|
| `--prompt <text>` | — | Inline prompt (repeatable) — combine with `--prompts` if needed |
|
|
332
427
|
| `--max-runtime <min>` | 60 | Auto-stop after N minutes |
|
|
@@ -350,6 +445,37 @@ Each receipt includes runtime, estimated/settled cost, status, retries, teardown
|
|
|
350
445
|
|
|
351
446
|
---
|
|
352
447
|
|
|
448
|
+
## Managing a deployment
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
badgr status # what's running and billing
|
|
452
|
+
badgr logs dep-abc123 # fetch current log output
|
|
453
|
+
badgr logs dep-abc123 --follow # stream logs until the deployment reaches a terminal state
|
|
454
|
+
badgr pull dep-abc123 # pull a coding agent's patch as a local git diff
|
|
455
|
+
badgr pull dep-abc123 --branch # ...as a new local branch instead of a diff
|
|
456
|
+
badgr pull dep-abc123 --diff-only # print the diff, don't touch the working tree
|
|
457
|
+
badgr artifacts dep-abc123 # download non-patch outputs (test reports, screenshots, traces)
|
|
458
|
+
badgr down dep-abc123 # terminate one deployment, stop billing
|
|
459
|
+
badgr down --all # terminate everything running, with a confirmation prompt
|
|
460
|
+
badgr down --all --yes # ...skip the confirmation prompt
|
|
461
|
+
badgr restart dep-abc123 # relaunch an endpoint with the same config — new ID, same API key
|
|
462
|
+
badgr rerun dep-abc123 # replay a past job/endpoint with its exact original spec — new ID
|
|
463
|
+
badgr heartbeat dep-abc123 # reset an endpoint's idle-timeout clock (see --idle-timeout on badgr serve)
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
| Command | Flag | Description |
|
|
467
|
+
|---------|------|-------------|
|
|
468
|
+
| `badgr logs <id>` | `--follow` / `-f` | Stream/poll logs until the deployment reaches a terminal state instead of a one-shot fetch |
|
|
469
|
+
| `badgr pull <id>` | `--branch` | Create a new local git branch from the patch instead of leaving it as an unstaged diff |
|
|
470
|
+
| `badgr pull <id>` | `--diff-only` | Print the raw diff, don't touch the local working tree at all |
|
|
471
|
+
| `badgr pull <id>` | `--yes` / `-y` | Skip the confirmation prompt before applying |
|
|
472
|
+
| `badgr down <id\|--all>` | `--all` | Terminate every running deployment instead of one by ID |
|
|
473
|
+
| `badgr down <id\|--all>` | `--yes` / `-y` | Skip the confirmation prompt |
|
|
474
|
+
|
|
475
|
+
`badgr restart` is endpoint-only (it tears down the current pod and relaunches with the same GPU/model/price/runtime caps and endpoint API key, so existing clients keep working against a new URL). `badgr rerun` works for both one-off jobs and endpoints, replaying the exact original image/command/env/GPU/caps, and never tears down the source deployment.
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
353
479
|
## OpenAI compatibility
|
|
354
480
|
|
|
355
481
|
`badgr serve` provisions a vLLM endpoint that is fully OpenAI-compatible:
|
|
@@ -417,22 +543,26 @@ Less common commands — training, transcription, embeddings, and the workload/w
|
|
|
417
543
|
badgr train config.yaml --gpu A100 --max-runtime 240 --env HF_TOKEN=$HF_TOKEN
|
|
418
544
|
```
|
|
419
545
|
|
|
420
|
-
Detects framework (axolotl, unsloth, trl) from the config file
|
|
546
|
+
Detects framework (axolotl, unsloth, trl) from the config file. **Axolotl and TRL configs run today** — `unsloth`/unrecognized configs are blocked before provisioning rather than billing a GPU that's guaranteed to fail. Default max-runtime is 120 min.
|
|
421
547
|
|
|
422
548
|
```bash
|
|
423
549
|
badgr train lora --base-model mistralai/Mistral-7B-v0.1 --dataset ./train.jsonl --preset small --max-cost 20
|
|
550
|
+
|
|
551
|
+
# Resume from a prior job's checkpoint instead of starting over
|
|
552
|
+
badgr train lora --base-model mistralai/Mistral-7B-v0.1 --dataset ./train.jsonl --resume https://.../checkpoint --max-cost 20
|
|
424
553
|
```
|
|
425
554
|
|
|
426
555
|
Productized LoRA training — pass a base model and dataset, no Axolotl config file needed. Badgr generates the config from a preset and returns a downloadable adapter.
|
|
427
556
|
|
|
428
557
|
| Flag | Default | Description |
|
|
429
558
|
|------|---------|-------------|
|
|
430
|
-
| `--framework <name>` | auto-detect | Force framework: `axolotl`, `unsloth`, `trl` (
|
|
559
|
+
| `--framework <name>` | auto-detect | Force framework: `axolotl`, `unsloth`, `trl` (`axolotl`/`trl` currently run; `unsloth` is blocked pre-provisioning) |
|
|
431
560
|
| `--base-model <id>` | — | HuggingFace model ID (required for `train lora`) — validated to exist before provisioning |
|
|
432
561
|
| `--dataset <path\|url>` | — | Local file, direct URL, or `s3://` URI |
|
|
433
562
|
| `--file-id <id>` | — | Badgr upload ID instead of `--dataset` |
|
|
434
563
|
| `--preset small\|medium` | `small` | `small` = RTX 4090, rank 16, 3 epochs. `medium` = A100, rank 32, 5 epochs |
|
|
435
564
|
| `--gpu-type <type>` | preset default | GPU type override for `train lora` |
|
|
565
|
+
| `--resume <checkpoint-url>` | — | Continue training from a prior job's checkpoint instead of starting fresh |
|
|
436
566
|
| `--dry-run` | — | Preview the job without provisioning |
|
|
437
567
|
|
|
438
568
|
On completion, `train lora` prints an `adapter_url` — download with `GET /v1/jobs/{job_id}/adapter`, or via `badgr workload info` if saved.
|
|
@@ -502,8 +632,11 @@ badgr batch status dep-abc123
|
|
|
502
632
|
badgr batch artifacts dep-abc123
|
|
503
633
|
badgr batch receipt dep-abc123
|
|
504
634
|
badgr batch compare dep-abc123 dep-def456
|
|
635
|
+
badgr batch compare dep-abc123 dep-def456 --key accuracy --higher-is-better
|
|
505
636
|
```
|
|
506
637
|
|
|
638
|
+
`batch compare` reads each run's `success_metric` by default; `--key <metric>` compares a different field from the receipt instead, and `--higher-is-better` (default) / `--higher-is-better false` controls which run is reported as the winner.
|
|
639
|
+
|
|
507
640
|
For CV/video/scientific batch, simulation, and physical-AI eval workloads — runs a container from a `workload.yml` spec and captures output artifacts automatically.
|
|
508
641
|
|
|
509
642
|
**Fan-out** — run the same program once per file in a directory, one deployment per input, in parallel:
|
|
@@ -539,14 +672,44 @@ Translates `--cpus-per-task`/`--mem`/`--gres`/`--time`/`--export` from a real `.
|
|
|
539
672
|
| `--max-concurrency <n>` | 5 | Cap in-flight array tasks |
|
|
540
673
|
| `--dry-run` | — | Preview the translated job without provisioning |
|
|
541
674
|
|
|
542
|
-
###
|
|
675
|
+
### `badgr models` — GPU catalog and pricing
|
|
676
|
+
|
|
677
|
+
```bash
|
|
678
|
+
badgr models
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
Lists available GPU types cheapest-first, with VRAM and hourly rate — pulled live from your account when logged in, falling back to the local catalog otherwise. No flags.
|
|
682
|
+
|
|
683
|
+
### `badgr template` — pre-built workload templates
|
|
543
684
|
|
|
544
|
-
|
|
545
|
-
|
|
685
|
+
```bash
|
|
686
|
+
badgr template list
|
|
687
|
+
badgr template info axolotl
|
|
688
|
+
badgr serve template vllm --model meta-llama/Llama-3.1-8B-Instruct --max-cost 10
|
|
689
|
+
badgr run template axolotl --config ./config.yaml --max-cost 10
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
Provider-neutral templates for common frameworks (`vllm`, `invokeai`, `comfyui`, `axolotl`, `unsloth`, …). `template list`/`template info <name>` just browse the catalog; launching always goes through `badgr serve template <name>` or `badgr run template <name>`, which apply the template's default flags before handing off to the normal `serve`/`run` path.
|
|
693
|
+
|
|
694
|
+
### `badgr capacity` — check live availability
|
|
695
|
+
|
|
696
|
+
```bash
|
|
697
|
+
badgr capacity # cheapest runnable GPU across all types
|
|
698
|
+
badgr capacity --gpu A100 # a specific GPU type
|
|
699
|
+
badgr capacity --gpu A100 --region EU # region-filtered
|
|
700
|
+
badgr capacity --gpu A100 --max-price 2.50 # price-capped
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### `badgr billing`
|
|
704
|
+
|
|
705
|
+
```bash
|
|
706
|
+
badgr billing status # current balance
|
|
707
|
+
badgr billing add 20 # add funds — $5 minimum top-up
|
|
708
|
+
```
|
|
546
709
|
|
|
547
710
|
---
|
|
548
711
|
|
|
549
712
|
## Requirements
|
|
550
713
|
|
|
551
|
-
- Node.js
|
|
714
|
+
- Node.js 20.10+
|
|
552
715
|
- A Badgr account — sign up at [aibadgr.com](https://aibadgr.com)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "badgr-cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Badgr — run or serve GPU workloads from one command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@inquirer/prompts": "^8.5.2",
|
|
16
16
|
"archiver": "^7.0.1",
|
|
17
|
+
"badgr-shared": "^0.1.2",
|
|
17
18
|
"chalk": "^5.3.0",
|
|
18
19
|
"js-yaml": "^4.1.0",
|
|
19
20
|
"tar": "^7.4.3"
|
package/src/api.js
CHANGED
|
@@ -228,6 +228,34 @@ export async function terminateDeployment(config, deploymentId) {
|
|
|
228
228
|
throw lastErr;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
// ---- Admin (michaelhireitem@gmail.com only) ---------------------------------
|
|
232
|
+
// CLI counterparts to the web admin dashboard's own /admin/api/deployments/*
|
|
233
|
+
// routes (main.py) -- those are gated by a browser session cookie the CLI's
|
|
234
|
+
// Authorization: Bearer <api_key> auth can never satisfy, so
|
|
235
|
+
// deployment_routes.py exposes these two under /v1/admin/deployments/*
|
|
236
|
+
// instead, gated by the same is_admin_email() check via API key. A non-admin
|
|
237
|
+
// caller gets a plain 403 from callApi, same as any other access-denied route.
|
|
238
|
+
|
|
239
|
+
// Every non-terminal deployment across every user (not just the caller's
|
|
240
|
+
// own), each carrying its owner's user_email/username so a stuck or
|
|
241
|
+
// forgotten GPU can be identified without logging into that customer's
|
|
242
|
+
// account. Backs `badgr status --admin`.
|
|
243
|
+
export function listAllActiveDeploymentsAdmin(config) {
|
|
244
|
+
return callApi('/admin/deployments/active', { apiKey: config.apiKey, baseUrl: config.baseUrl, timeoutMs: 15_000 });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Force-terminate any deployment regardless of owner -- bypasses the
|
|
248
|
+
// per-user ownership check DELETE /deployments/{id} enforces. Backs
|
|
249
|
+
// `badgr down <id> --admin`.
|
|
250
|
+
export function adminTerminateDeployment(config, deploymentId) {
|
|
251
|
+
return callApi(`/admin/deployments/${deploymentId}`, {
|
|
252
|
+
method: 'DELETE',
|
|
253
|
+
apiKey: config.apiKey,
|
|
254
|
+
baseUrl: config.baseUrl,
|
|
255
|
+
timeoutMs: 20_000,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
231
259
|
export function restartDeployment(config, deploymentId) {
|
|
232
260
|
return callApi(`/deployments/${deploymentId}/restart`, {
|
|
233
261
|
method: 'POST',
|
package/src/badgr.js
CHANGED
|
@@ -47,7 +47,7 @@ ${chalk.bold('COMMANDS')}
|
|
|
47
47
|
${chalk.cyan('badgr job <agent> "<instruction>" --check "<command>"')} Bounded coding-agent job, tracked at /jobs (POST /v1/jobs, type: agent)
|
|
48
48
|
${chalk.cyan('badgr serve <model>')} Serve a model with an OpenAI-compatible endpoint
|
|
49
49
|
${chalk.cyan('badgr serve openwebui')} Serve Open WebUI — chat UI, connects to a model endpoint
|
|
50
|
-
${chalk.cyan('badgr diagnose "<input>"')}
|
|
50
|
+
${chalk.cyan('badgr diagnose "<input>"')} Run a free Badgr Smoke Test on any GPU issue — GitHub issue, Docker image, log, repo, or text
|
|
51
51
|
${chalk.cyan('badgr doctor')} Local GPU / model-fit diagnosis (read-only, no login needed)
|
|
52
52
|
${chalk.cyan('badgr status')} Show what's running and what's billing
|
|
53
53
|
${chalk.cyan('badgr logs <id>')} Stream logs for a running job or endpoint
|
|
@@ -113,13 +113,13 @@ ${chalk.bold('EXAMPLES')}
|
|
|
113
113
|
${chalk.dim('# badgr job — bounded coding-agent job with a pass/fail check, tracked at /jobs:')}
|
|
114
114
|
badgr job cline "Run the Chromium tests and tell me what failed" --check "npm run test:chromium" --max-cost 1
|
|
115
115
|
|
|
116
|
-
${chalk.dim('#
|
|
116
|
+
${chalk.dim('# Run a free Badgr Smoke Test on any GPU issue (no login needed):')}
|
|
117
117
|
badgr diagnose "https://github.com/org/repo/issues/123"
|
|
118
118
|
badgr diagnose ./error.log
|
|
119
119
|
badgr diagnose --docker ajayrajtp/vllm_gemma412b:latest
|
|
120
120
|
badgr diagnose --repo https://github.com/org/repo
|
|
121
121
|
badgr diagnose --comfyui workflow.json
|
|
122
|
-
badgr diagnose "https://github.com/org/repo/issues/123" --approve ${chalk.dim('#
|
|
122
|
+
badgr diagnose "https://github.com/org/repo/issues/123" --approve ${chalk.dim('# start a real Badgr Run')}
|
|
123
123
|
|
|
124
124
|
${chalk.dim('# Local model-fit and workload diagnosis (no network):')}
|
|
125
125
|
badgr doctor
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import { CONFIG_DIR } from '../config.js';
|
|
4
|
+
import { ensureLoggedInReady, withReauthRetry } from '../onboarding.js';
|
|
4
5
|
import { downloadAndExtractArtifact } from '../artifactDownload.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -37,7 +38,7 @@ export function listFilesRecursive(dir, prefix = '') {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export async function artifactsCommand(config, args, chalk) {
|
|
40
|
-
|
|
41
|
+
config = await ensureLoggedInReady(config, chalk);
|
|
41
42
|
const { deploymentId, flags } = parseArtifactsArgs(args);
|
|
42
43
|
if (!deploymentId) {
|
|
43
44
|
console.error(chalk.red('\n Usage: badgr artifacts <deployment-id> [--output <dir>]\n'));
|
|
@@ -49,7 +50,8 @@ export async function artifactsCommand(config, args, chalk) {
|
|
|
49
50
|
const destDir = flags.output ? path.resolve(flags.output) : defaultDestDir(deploymentId);
|
|
50
51
|
|
|
51
52
|
try {
|
|
52
|
-
await
|
|
53
|
+
const refreshed = await withReauthRetry(config, chalk, cfg => downloadAndExtractArtifact(cfg, deploymentId, destDir));
|
|
54
|
+
config = refreshed.config;
|
|
53
55
|
} catch (err) {
|
|
54
56
|
if (err.httpStatus === 404) {
|
|
55
57
|
console.error(chalk.red(`\n ✗ No artifact found for ${deploymentId}.\n`));
|
package/src/commands/batch.js
CHANGED
|
@@ -17,7 +17,8 @@ import { existsSync, readFileSync, unlinkSync, statSync, readdirSync } from 'fs'
|
|
|
17
17
|
import { join, resolve } from 'path';
|
|
18
18
|
import os from 'os';
|
|
19
19
|
|
|
20
|
-
import {
|
|
20
|
+
import { CONFIG_DIR } from '../config.js';
|
|
21
|
+
import { ensureBadgrReady, ensureLoggedInReady } from '../onboarding.js';
|
|
21
22
|
import { parseWorkloadYaml } from '../workloadSpec.js';
|
|
22
23
|
import { addReceipt, updateReceipt, generateReceiptId, loadStore, selectedComputeFromDeployment } from '../store.js';
|
|
23
24
|
import { normalizeTier, callWithFallback } from '../fallback.js';
|
|
@@ -392,7 +393,7 @@ async function runSubcommand(config, args, chalk) {
|
|
|
392
393
|
return;
|
|
393
394
|
}
|
|
394
395
|
|
|
395
|
-
|
|
396
|
+
config = await ensureBadgrReady(config, chalk);
|
|
396
397
|
|
|
397
398
|
let spec;
|
|
398
399
|
try {
|
|
@@ -593,7 +594,7 @@ async function statusSubcommand(config, args, chalk) {
|
|
|
593
594
|
process.exitCode = 1;
|
|
594
595
|
return;
|
|
595
596
|
}
|
|
596
|
-
|
|
597
|
+
config = await ensureLoggedInReady(config, chalk);
|
|
597
598
|
|
|
598
599
|
let dep;
|
|
599
600
|
try {
|
|
@@ -628,7 +629,7 @@ async function artifactsSubcommand(config, args, chalk) {
|
|
|
628
629
|
process.exitCode = 1;
|
|
629
630
|
return;
|
|
630
631
|
}
|
|
631
|
-
|
|
632
|
+
config = await ensureLoggedInReady(config, chalk);
|
|
632
633
|
|
|
633
634
|
let destDir;
|
|
634
635
|
try {
|
|
@@ -676,7 +677,7 @@ async function receiptSubcommand(config, args, chalk) {
|
|
|
676
677
|
process.exitCode = 1;
|
|
677
678
|
return;
|
|
678
679
|
}
|
|
679
|
-
|
|
680
|
+
config = await ensureLoggedInReady(config, chalk);
|
|
680
681
|
|
|
681
682
|
const local = findBatchRun(runId);
|
|
682
683
|
let dep = null;
|
package/src/commands/billing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ensureLoggedInReady } from '../onboarding.js';
|
|
2
2
|
import { callApi } from '../api.js';
|
|
3
3
|
import { openBrowser } from '../browser.js';
|
|
4
4
|
|
|
@@ -17,7 +17,7 @@ EXAMPLES
|
|
|
17
17
|
`;
|
|
18
18
|
|
|
19
19
|
async function billingStatus(config, chalk) {
|
|
20
|
-
|
|
20
|
+
config = await ensureLoggedInReady(config, chalk);
|
|
21
21
|
try {
|
|
22
22
|
const apiUrl = config.baseUrl.replace('/v1', '').replace('/api/v1', '');
|
|
23
23
|
const data = await callApi('/api/me', {
|
|
@@ -47,7 +47,7 @@ async function billingStatus(config, chalk) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
async function billingAdd(config, amount, chalk) {
|
|
50
|
-
|
|
50
|
+
config = await ensureLoggedInReady(config, chalk);
|
|
51
51
|
const amountInt = parseInt(amount, 10);
|
|
52
52
|
if (!amountInt || amountInt < 5) {
|
|
53
53
|
console.error(chalk.red(' Minimum top-up is $5. Example: badgr billing add 5'));
|
package/src/commands/capacity.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ensureLoggedInReady } from '../onboarding.js';
|
|
2
2
|
import { callApi } from '../api.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -19,7 +19,7 @@ function parseCapacityArgs(args) {
|
|
|
19
19
|
|
|
20
20
|
export async function capacityCommand(config, args, chalk) {
|
|
21
21
|
const flags = parseCapacityArgs(args);
|
|
22
|
-
|
|
22
|
+
config = await ensureLoggedInReady(config, chalk);
|
|
23
23
|
|
|
24
24
|
// No --max-price: no cap. Availability browsing shouldn't silently hide
|
|
25
25
|
// real capacity behind an unrequested price ceiling.
|
package/src/commands/deploy.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
2
|
import { findCheapest, findById } from '../router.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ensureBadgrReady } from '../onboarding.js';
|
|
4
4
|
|
|
5
5
|
export function parseDeployArgs(args) {
|
|
6
6
|
const nameFlag = args.indexOf('--name');
|
|
@@ -24,7 +24,7 @@ export async function deployCommand(config, args, chalk) {
|
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
config = await ensureBadgrReady(config, chalk);
|
|
28
28
|
|
|
29
29
|
const deployId = randomUUID().split('-')[0];
|
|
30
30
|
const name = rawName ?? script.replace(/[^a-z0-9]/gi, '-').replace(/-+/g, '-').toLowerCase();
|