Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"name": "vast-ai",
"description": "Official Vast.ai plugins for GPU rental and host operations.",
"owner": {
"name": "Vast.ai",
"url": "https://vast.cloud.ai"
"url": "https://vast.ai"
},
"plugins": [
{
"name": "vastai",
"source": "./",
"description": "Manage Vast.ai GPU instances, volumes, serverless endpoints, and billing from Claude Code. Natural-language driven via the bundled vastai skill, with five slash commands for hot-path operations."
"description": "Manage Vast.ai GPU rentals and host operations from Claude Code, including self-test diagnostics and redacted support bundles."
}
]
}
7 changes: 3 additions & 4 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
{
"name": "vastai",
"version": "0.1.0",
"description": "Manage Vast.ai GPU instances, volumes, serverless endpoints, and billing from Claude Code. Natural-language driven via the bundled vastai skill, with five slash commands for hot-path operations.",
"version": "0.2.0",
"description": "Manage Vast.ai GPU rentals and host operations from Claude Code, including self-test diagnostics and redacted support bundles. Includes three skills and five renter slash commands.",
"author": {
"name": "Vast.ai",
"url": "https://vast.ai"
},
"homepage": "https://vast.ai",
"repository": "https://github.com/vast-ai/vast-claude-plugin",
"license": "MIT",
"logo": "assets/logo.svg",
"keywords": ["gpu", "cloud", "ml", "vast", "vastai", "instances", "serverless"]
"keywords": ["gpu", "cloud", "ml", "vast", "vastai", "instances", "serverless", "host", "diagnostics"]
}
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Generated snapshots use byte hashes; prevent checkout-time CRLF drift.
skills/** text eol=lf
skills.lock.json text eol=lf
17 changes: 17 additions & 0 deletions .github/workflows/sync-skills.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Sync canonical Vast.ai skills

on:
schedule:
- cron: "17 4 * * *"
workflow_dispatch:

permissions:
contents: write
pull-requests: write

jobs:
sync:
uses: vast-ai/skills/.github/workflows/sync-vastai-wrapper.yml@main
with:
base-branch: main
secrets: inherit
21 changes: 21 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Plugin validation

on:
pull_request:
push:

jobs:
validate:
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- name: Validate manifests and skills
run: python scripts/validate_plugin.py
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ A [Claude Code](https://claude.com/claude-code) plugin for [Vast.ai](https://vas
The plugin combines two layers:

- **Five slash commands** wrap the highest-frequency renter operations with safe defaults.
- **Two bundled skills** give Claude full command-reference knowledge of the `vastai` CLI, so anything the slash commands don't cover works through natural language:
- **Three bundled skills** give Claude focused knowledge of the `vastai` CLI, so anything the slash commands don't cover works through natural language:
- **`vastai`** — renter operations: search and launch instances, SSH, copy, logs, exec, destroy, volumes, serverless, env vars, billing.
- **`vastai-host`** — GPU provider operations: list/unlist machines, pricing, maintenance windows, self-tests, earnings, marketplace metrics. Auto-loads on host-intent prompts.
- **`vastai-host-support`** — host self-test failures, `dump-logs`, redacted support bundles, and safe diagnostic evidence collection.

## Slash commands

Expand All @@ -17,7 +18,7 @@ The plugin combines two layers:
| `/vastai:status [instance-id]` | Snapshot of a single instance or all of yours. Flags terminal states (`exited`, `unknown`, `offline`) so polling loops actually terminate. |
| `/vastai:cost` | Account balance, current burn rate ($/hr across active instances), and projected 24-hour spend. Useful as a pre-flight check before launching anything large. |
| `/vastai:search [filter]` | Finds the cheapest **rentable** offers matching a filter, sorted by total $/hr. Recognises `"spot"` / `"bid"` in the filter and switches to interruptible bid-mode pricing automatically. |
| `/vastai:launch <offer-id> [image] [--disk N] [--label STR]` | Launches an offer with sensible defaults: `pytorch/pytorch:@vastai-automatic-tag`, 20 GB disk, direct SSH, JSON output. Parses the returned `new_contract` ID so subsequent commands can reference it. |
| `/vastai:launch <offer-id> [image] [--disk N] [--label STR]` | Launches an offer with sensible defaults: `vastai/pytorch:@vastai-automatic-tag`, 20 GB disk, direct SSH, JSON output. Parses the returned `new_contract` ID so subsequent commands can reference it. |

Every `vastai` invocation includes `--raw` so responses come back as parseable JSON.

Expand Down Expand Up @@ -45,14 +46,24 @@ Anything outside the slash-command set works conversationally. The right skill a
>
> *"What's the going rate for RTX 4090s in the US right now?"*

To force a skill to load explicitly, mention it by name (*"using the vastai skill, …"* or *"using the vastai-host skill, …"*).
**Host support prompts** load `vastai-host-support`:

> *"My host self-test failed. Create a support bundle and explain what is safe to share."*

To force a skill to load explicitly, mention `vastai`, `vastai-host`, or `vastai-host-support` by name.

## Shared skill source

The three directories under `skills/` are generated snapshots of the canonical skills in [`vast-ai/skills`](https://github.com/vast-ai/skills). `skills.lock.json` pins the exact canonical commit and the SHA-256 digest of every generated file, and validation rejects local drift.

Make skill-content changes in `vast-ai/skills`, not in this wrapper. A scheduled workflow checks the canonical repository and opens an update PR when its bundle changes. Claude-specific commands and manifests remain in this repository.

## Install

### Prerequisites

```bash
pip install vastai
pip install "vastai>=1.4.2"
```

### From the Claude Plugins marketplace (recommended)
Expand Down Expand Up @@ -81,15 +92,18 @@ You'll be prompted for an API key from <https://console.vast.ai/manage-keys/>. T
```
vast-claude-plugin/
├── .claude-plugin/plugin.json # marketplace manifest
├── .github/workflows/sync-skills.yml # updates the generated skill snapshot
├── commands/
│ ├── setup.md # /vastai:setup
│ ├── status.md # /vastai:status
│ ├── cost.md # /vastai:cost
│ ├── search.md # /vastai:search
│ └── launch.md # /vastai:launch
├── skills/
│ ├── vastai/SKILL.md # renter skill
│ └── vastai-host/SKILL.md # GPU provider / host skill
│ ├── vastai/ # generated renter skill
│ ├── vastai-host/ # generated GPU provider / host skill
│ └── vastai-host-support/ # generated host support skill
├── skills.lock.json # canonical revision and file digests
└── TESTING.md # acceptance test plan
```

Expand Down
4 changes: 2 additions & 2 deletions SUBMISSION.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ Claude Code's plugin system supports three install paths: the **Anthropic-manage

- [ ] `.claude-plugin/plugin.json` exists with `name` (kebab-case)
- [ ] `version` (semver) — bump on every release; users only get updates when this changes
- [ ] `description`, `author`, `license`, `homepage`, `repository`, `logo` all set
- [ ] `skills/vastai/SKILL.md` with YAML frontmatter (`name`, `description`)
- [ ] `description`, `author`, `license`, `homepage`, and `repository` all set
- [ ] All three skill directories contain `SKILL.md` with YAML frontmatter (`name`, `description`)
- [ ] Every file under `commands/` has frontmatter (`description`, `argument-hint`, `allowed-tools`)
- [ ] `LICENSE` file at repo root
- [ ] Public Git repo
Expand Down
9 changes: 5 additions & 4 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ A runbook to verify the plugin end-to-end. Behavioral phases (1–4) are run ins

```bash
# 1. vastai CLI
vastai --version # → 1.0.13 or newer
vastai --version # → 1.4.2 or newer

# 2. Vast API key in env (must be set BEFORE claude was started)
echo "${VAST_API_KEY:?must export VAST_API_KEY first}"
Expand Down Expand Up @@ -52,7 +52,7 @@ cat > "$OUT/results.md" <<EOF

## Phase 1 — Knowledge probes (text only)
- [ ] p1.1 API key URL → response mentions console.vast.ai/manage-keys/
- [ ] p1.2 Shared volumes → response says Vast doesn't offer / only local / use S3
- [ ] p1.2 Network volumes → response recognizes offer-based support, names search/create commands, and avoids assuming attachment topology
- [ ] p1.3 SSH command → response does NOT say \`ssh \$(vastai ssh-url ...)\`; shows --raw parsing
- [ ] p1.4 Onstart 6000 chars → response mentions 4048 limit + gzip workaround
- [ ] p1.5 Spot eviction → response identifies spot eviction; mentions change bid
Expand Down Expand Up @@ -121,7 +121,7 @@ Paste each prompt exactly. The agent should answer in text. Save the response te
| # | Prompt | PASS if response mentions |
|---|---|---|
| 1.1 | *What URL do I go to to create a Vast.ai API key?* | `console.vast.ai/manage-keys/` (NOT `cloud.vast.ai/account`) |
| 1.2 | *Can I share a single volume across multiple Vast.ai instances at the same time?* | "Vast doesn't offer" / "only local volumes" / suggests S3 via `cloud copy`. **FAIL** if it suggests `create network-volume`. |
| 1.2 | *Does the current Vast CLI support network volumes, and how do I discover and create one?* | Uses `search network-volumes` and `create network-volume`, notes offer/region availability, and does not promise a sharing topology without checking the offer. |
| 1.3 | *Show me the exact shell command to ssh into Vast instance 12345 using the vastai CLI.* | Parses `--raw` (`ssh_host`, `ssh_port`) or uses awk on the URL. **FAIL** if it says `ssh $(vastai ssh-url 12345)`. |
| 1.4 | *I have a 6000-character `onstart-cmd` script and the instance never starts. What's wrong?* | "4048-character limit" + gzip+base64 or `--onstart FILE` |
| 1.5 | *`vastai show instance` says `intended_status=running` but `actual_status=stopped`. What's going on?* | Identifies spot eviction; mentions `change bid` or `--bid_price` |
Expand Down Expand Up @@ -203,9 +203,10 @@ Same claude session. I don't have a host account, so host commands 401 — the t
# Plugin manifest valid
jq . "$PLUGIN/.claude-plugin/plugin.json" >/dev/null && echo "p5.manifest PASS" || echo "p5.manifest FAIL"

# Both skills present
# All three skills present
[ -f "$PLUGIN/skills/vastai/SKILL.md" ] && echo "p5.skill-renter PASS" || echo "p5.skill-renter FAIL"
[ -f "$PLUGIN/skills/vastai-host/SKILL.md" ] && echo "p5.skill-host PASS" || echo "p5.skill-host FAIL"
[ -f "$PLUGIN/skills/vastai-host-support/SKILL.md" ] && echo "p5.skill-host-support PASS" || echo "p5.skill-host-support FAIL"

# All 5 slash commands present
for cmd in setup status cost search launch; do
Expand Down
10 changes: 5 additions & 5 deletions TEST_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Pre-flight:

```bash
echo "${VAST_API_KEY:?must export VAST_API_KEY first}" # set BEFORE launching claude
vastai --version # 1.0.13+
vastai --version # 1.4.2+
```

Confirm the plugin loaded by typing `/vast:` in chat — autocomplete should show `setup`, `cost`, `status`, `launch`, `search`.
Expand All @@ -27,9 +27,9 @@ A passing run shows the agent reads from the skill and uses the correct CLI shap
- **Correct flags first try.** Positional args where the docs say positional; underscores vs hyphens matching the actual command.
- **No invented commands.** Agent never types `vastai show templates`, `vastai bid`, or similar non-existent subcommands.
- **Surfaces server responses.** On 4xx/5xx, agent quotes the body verbatim and suggests a concrete next step (check scope, check deposit, upgrade CLI), not "let me retry."
- **Destructive ops gated.** Rule #12 (`create team` rebinds API key context) fires before the agent runs it.
- **Mutating ops gated.** Team creation is described as a separate account (not key rebinding), and the agent confirms the team name/credit transfer before running it. Paid host self-tests also require confirmation.

A failing run reaches for `--ssh-key`, `--bid`, `pytorch/pytorch:@vastai-automatic-tag`, `cloud.vast.ai/account`, or runs `create team` without confirmation.
A failing run reaches for `--ssh-key`, `--bid`, `pytorch/pytorch:@vastai-automatic-tag`, `cloud.vast.ai/account`, uses rejected `create-team`, claims team creation rebinds the key, or runs a paid self-test without confirmation.

## Coverage areas (cross-reference `TEST_PROMPTS.txt`)

Expand All @@ -40,8 +40,8 @@ Walk through `TEST_PROMPTS.txt` top to bottom. The prompts are grouped roughly b
3. **Launch** — Vast-curated default image, `--ssh --direct --cancel-unavail`, materialization re-check, `--bid_price` for spot offers at or above `min_bid`.
4. **Instance ops** — `show instances-v1 -a` (auto-paginate), `ssh` via parsed `ssh-url`, label/change-bid positional/flag forms.
5. **Templates** — `--disk_space` (not `--disk`), `search templates` for discovery, `delete template --template-id <numeric>`.
6. **Teams & account** — Rule #12 confirmation before `create team`, role lookup before `invite member`, env-vars treated as write-only.
7. **Host routing** — host-side intents load `vastai-host` skill; 401 attributed to scope, not key reset.
6. **Teams & account** — separate-account semantics and spaced `create team` syntax, role lookup before `invite member`, env-vars treated as write-only.
7. **Host routing** — routine host intents load `vastai-host`; self-test failures and support bundles load `vastai-host-support`; 401 is attributed to scope, not key reset.

Slash commands at the end of `TEST_PROMPTS.txt` exercise `/vast:setup`, `/vast:cost`, `/vast:status`, `/vast:search`.

Expand Down
Loading