@minato-aqukin/autodl-cli 0.1.0
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/LICENSE +21 -0
- package/README.md +415 -0
- package/README.zh-CN.md +383 -0
- package/dist/app-4E2WPQ3C.js +36151 -0
- package/dist/chunk-2TWWLI3Y.js +134 -0
- package/dist/chunk-5RZ4Q7T4.js +1458 -0
- package/dist/chunk-6QR4ZYQR.js +1432 -0
- package/dist/chunk-CWCG3MOC.js +433 -0
- package/dist/chunk-NBWWTYSL.js +46 -0
- package/dist/cli.js +1058 -0
- package/dist/index.d.ts +948 -0
- package/dist/index.js +188 -0
- package/dist/ink-devtools-QXLFHNC2.js +4 -0
- package/dist/tui-AARJCHRA.js +16 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Minato-Aqukin
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
# autodl-cli
|
|
2
|
+
|
|
3
|
+
> **Unofficial.** This project is not affiliated with, endorsed by, or sponsored by AutoDL.
|
|
4
|
+
> "AutoDL" is used only to identify the platform this tool talks to.
|
|
5
|
+
|
|
6
|
+
Manage [AutoDL](https://www.autodl.com/) GPU instances from the command line — and let
|
|
7
|
+
your coding agent do it too.
|
|
8
|
+
|
|
9
|
+
Built on AutoDL's **official open API**, so the developer token stays valid indefinitely
|
|
10
|
+
and nothing breaks when the web console is redesigned.
|
|
11
|
+
|
|
12
|
+
[简体中文](./README.zh-CN.md)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Why
|
|
17
|
+
|
|
18
|
+
When an AI agent needs a GPU box mid-task, it has no way to get one: AutoDL's instances
|
|
19
|
+
are created by clicking through a web console. This gives the agent three ways in, all
|
|
20
|
+
backed by the same core:
|
|
21
|
+
|
|
22
|
+
| Entry point | For | How |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| **CLI** | humans | `autodl create --gpu 4090 --ttl 2h` |
|
|
25
|
+
| **MCP server** | Claude Code, Cursor, Cline, … | `autodl mcp` over stdio |
|
|
26
|
+
| **SDK** | Node programs | `import { createInstance } from "@minato-aqukin/autodl-cli"` |
|
|
27
|
+
|
|
28
|
+
Every command speaks `--json` with a stable schema and a documented exit code, so an
|
|
29
|
+
agent can branch on the result without parsing prose.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install -g @minato-aqukin/autodl-cli # then: autodl <command>
|
|
35
|
+
npx @minato-aqukin/autodl-cli <command> # or without installing
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Requires Node.js 22+.
|
|
39
|
+
|
|
40
|
+
## The dashboard
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
autodl tui # or just `autodl` in an interactive terminal
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
On a machine with no token yet it opens on a login screen offering two things —
|
|
47
|
+
configure a token, or quit. Paste the token, it is verified against the API before
|
|
48
|
+
being saved, and you land on the dashboard. Once configured, `autodl` goes straight in.
|
|
49
|
+
|
|
50
|
+
A live table of your instances: status, GPU, region, **how long each has been powered on
|
|
51
|
+
and roughly what that has cost**, and how much TTL is left. Keys: `↑↓` move, `Enter`
|
|
52
|
+
detail, `s` start, `x` stop, `c` copy the SSH command to the clipboard, `ctrl+d` release, `g` GPU stock,
|
|
53
|
+
`n` new instance, `r` refresh, `ctrl+l` log out, `q` quit. The two that change or destroy
|
|
54
|
+
something take ctrl rather than a bare key; shift makes no difference to either, and the
|
|
55
|
+
hints are printed all-lowercase so they do not read as bindings you hold shift for.
|
|
56
|
+
|
|
57
|
+
`ctrl+d` release wipes the instance permanently, which is why it is not a bare `d`.
|
|
58
|
+
|
|
59
|
+
`ctrl+l` clears the saved token and returns to the login screen, after a confirmation — and
|
|
60
|
+
it says so when `AUTODL_TOKEN` or `--token` will outrank whatever you save next. If the
|
|
61
|
+
API rejects the token while the dashboard is open — expired, reset, verification lapsed —
|
|
62
|
+
polling stops and the same login screen is one keystroke away, rather than leaving a
|
|
63
|
+
frozen table above an endless stream of 401s.
|
|
64
|
+
|
|
65
|
+
It fills the terminal and shows your account id and balance in the header. Copying with
|
|
66
|
+
`c` puts only the SSH command on the clipboard — never the root password, which any
|
|
67
|
+
process could then read. Where no clipboard helper exists (SSH sessions, containers) it
|
|
68
|
+
falls back to OSC 52 and says so, since the terminal never confirms.
|
|
69
|
+
|
|
70
|
+
It runs on the terminal's alternate screen, so it owns a fixed canvas instead of
|
|
71
|
+
scrolling below whatever was already there, and quitting restores your prompt and
|
|
72
|
+
scrollback untouched.
|
|
73
|
+
|
|
74
|
+
It exists because AutoDL bills on power state: the expensive mistake is not a wrong
|
|
75
|
+
command, it's an instance nobody remembered to stop. Leaving this open makes that visible.
|
|
76
|
+
|
|
77
|
+
Two deliberate honesty constraints. A rate is only knowable from a **running** instance's
|
|
78
|
+
snapshot, so a stopped instance shows elapsed time and no money — inventing a number
|
|
79
|
+
would be worse than showing none. And while a rate is still loading the total says so
|
|
80
|
+
rather than quietly under-reporting.
|
|
81
|
+
|
|
82
|
+
The TUI never runs in a pipe, in CI, or under `--json`: it exits with code 2 and an
|
|
83
|
+
explanation instead of taking over a terminal that isn't there. A bare `autodl` outside
|
|
84
|
+
an interactive terminal still prints help exactly as before.
|
|
85
|
+
|
|
86
|
+
## Setup
|
|
87
|
+
|
|
88
|
+
The official API needs a developer token from an **identity-verified** account
|
|
89
|
+
(个人或企业实名认证). Get it from the AutoDL console → 设置 → 开发者 Token.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
autodl login # verifies the token, then saves it with 0600 permissions
|
|
93
|
+
autodl account # balance, vouchers, lifetime spend
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Token precedence: `--token` › `AUTODL_TOKEN` › `~/.config/autodl-cli/config.json`.
|
|
97
|
+
|
|
98
|
+
## Quick start
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Rent a GPU that shuts itself off after two hours, and wait until it's ready
|
|
102
|
+
autodl create --gpu 4090 --ttl 2h --wait
|
|
103
|
+
|
|
104
|
+
# Work with it
|
|
105
|
+
autodl ls
|
|
106
|
+
autodl ssh pro-76419909953e # interactive login
|
|
107
|
+
autodl exec pro-76419909953e "nvidia-smi" # one-off command, remote exit code
|
|
108
|
+
autodl push pro-76419909953e ./src /root/work # SFTP upload
|
|
109
|
+
autodl pull pro-76419909953e /root/work/out . # SFTP download
|
|
110
|
+
|
|
111
|
+
# Stop paying
|
|
112
|
+
autodl stop pro-76419909953e
|
|
113
|
+
autodl rm pro-76419909953e --yes # irreversible: wipes all data
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Or do the whole thing in one verb:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
autodl run "python train.py" \
|
|
120
|
+
--gpu 4090 --sync ./ --pull /root/autodl-cli/checkpoints --ttl 4h
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
That creates an instance, waits for it, uploads your code, streams the command's output,
|
|
124
|
+
downloads the results, and powers the instance off — including on Ctrl-C.
|
|
125
|
+
|
|
126
|
+
## Use it from an agent
|
|
127
|
+
|
|
128
|
+
### Claude Code
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
claude mcp add autodl -- npx -y @minato-aqukin/autodl-cli mcp
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Cursor / Cline / any MCP client
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"mcpServers": {
|
|
139
|
+
"autodl": {
|
|
140
|
+
"command": "npx",
|
|
141
|
+
"args": ["-y", "@minato-aqukin/autodl-cli", "mcp"],
|
|
142
|
+
"env": { "AUTODL_TOKEN": "your-token" }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Tools exposed: `autodl_account_info`, `autodl_list_instances`, `autodl_get_instance`,
|
|
149
|
+
`autodl_create_instance`, `autodl_power_on`, `autodl_power_off`,
|
|
150
|
+
`autodl_release_instance`, `autodl_exec`, `autodl_upload`, `autodl_download`,
|
|
151
|
+
`autodl_run`, `autodl_list_gpu_specs`, `autodl_list_images`, `autodl_save_image`,
|
|
152
|
+
`autodl_sweep_expired`. Plus an `autodl://instances` resource.
|
|
153
|
+
|
|
154
|
+
MCP defaults are deliberately stricter than the CLI's, because nobody is watching:
|
|
155
|
+
a 2-hour TTL is applied unless you ask for longer, releasing requires an explicit
|
|
156
|
+
`confirm: true`, and passwords come back redacted unless requested.
|
|
157
|
+
|
|
158
|
+
### Shell / CI
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
autodl ls --json | jq -r '.data[] | select(.status=="running") | .uuid'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Deploying a git project
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Rent a box, clone, auto-install dependencies, run it, then stop the instance
|
|
168
|
+
autodl deploy owner/repo --gpu 4090 --start "python train.py" --ttl 4h
|
|
169
|
+
|
|
170
|
+
# Long-running service: background it and keep the instance up
|
|
171
|
+
autodl deploy owner/repo --gpu 4090 --start "python app.py" --detach
|
|
172
|
+
|
|
173
|
+
# Come back later — powers the same box on and `git pull`s, no rebuild
|
|
174
|
+
autodl deploy owner/repo --instance pro-76419909953e --start "python train.py"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`deploy` differs from `run` in one deliberate way: it **stops** the instance at the end
|
|
178
|
+
instead of releasing it. A stopped instance keeps its disks, so the next deploy reuses
|
|
179
|
+
the environment you already built. `--on-finish release` opts out.
|
|
180
|
+
|
|
181
|
+
Code lands in `/root/autodl-tmp/<repo>` — the data disk. AutoDL's system disk is a fixed
|
|
182
|
+
30GB that also gets packed into any saved image; the data disk is separate, faster and
|
|
183
|
+
expandable. The trade-off worth knowing: **data-disk contents are not included when you
|
|
184
|
+
save an image**, so put the environment on the system disk and the code here.
|
|
185
|
+
|
|
186
|
+
Dependencies are auto-detected in this order, first hit wins — `environment.yml` →
|
|
187
|
+
`requirements.txt` → `pyproject.toml` → `package-lock.json`/`package.json`. Override with
|
|
188
|
+
`--setup "<cmd>"`, or skip with `--no-setup`.
|
|
189
|
+
|
|
190
|
+
Remote commands run through a **login shell**. AutoDL images keep `python`, `pip` and
|
|
191
|
+
`conda` in `/root/miniconda3/bin`, which only reaches `PATH` via the login profile — a
|
|
192
|
+
plain non-interactive `ssh host "pip install ..."` exits 127. This applies to
|
|
193
|
+
`autodl exec` too, so it behaves the way it does when you `autodl ssh` in by hand.
|
|
194
|
+
|
|
195
|
+
Cloning from GitHub or HuggingFace automatically enables AutoDL's academic proxy
|
|
196
|
+
(`source /etc/network_turbo`). Gitee is domestic and skips it. `--no-accel` disables it.
|
|
197
|
+
AutoDL notes the proxy is "for academic use, with no stability guarantee".
|
|
198
|
+
|
|
199
|
+
Private repos: `--git-token`, or `GIT_TOKEN` / `GITHUB_TOKEN` in the environment. The
|
|
200
|
+
token never reaches a log line, an error message, `--json` output, or the checkout's
|
|
201
|
+
stored git remote.
|
|
202
|
+
|
|
203
|
+
## Checking GPU stock
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
autodl stock --gpu 4090 # where are the free cards
|
|
207
|
+
autodl stock # everything, everywhere
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Read this table carefully — the numbers are less authoritative than they look.** They
|
|
211
|
+
come from AutoDL's elastic-deployment stock endpoint, the only capacity API that exists,
|
|
212
|
+
and it does not track Pro instance availability. Measured on 2026-08-23: it reported 140
|
|
213
|
+
idle RTX 4090D in `westDC3` while creating a Pro instance there answered *"暂无库存"* —
|
|
214
|
+
and the identical request with no region constraint succeeded, landing in `beijingDC2`.
|
|
215
|
+
|
|
216
|
+
Two consequences, both baked into the tool:
|
|
217
|
+
|
|
218
|
+
- **Creating an instance never narrows regions on its own.** Omitting `data_center_list`
|
|
219
|
+
gives AutoDL the widest choice, which empirically succeeds most often.
|
|
220
|
+
- **Only two regions accept a Pro instance at all**: `westDC3` (西北B区) and `beijingDC2`
|
|
221
|
+
(北京B区). The other nine in the stock table are elastic-deployment only; passing one
|
|
222
|
+
to `--region` is rejected up front rather than failing later with AutoDL's opaque
|
|
223
|
+
"请求参数错误". The `可建Pro` column marks which is which.
|
|
224
|
+
|
|
225
|
+
## The cost guard
|
|
226
|
+
|
|
227
|
+
**AutoDL bills purely on power state.** An instance that finished training an hour ago
|
|
228
|
+
costs exactly as much as one at 100% utilisation. This is the single easiest way for an
|
|
229
|
+
unattended agent to waste real money, so the protection is built in rather than optional.
|
|
230
|
+
|
|
231
|
+
Three layers:
|
|
232
|
+
|
|
233
|
+
1. **Inside the instance.** `--ttl 2h` arms a detached `sleep && shutdown` on the box
|
|
234
|
+
itself via `start_command`. It fires even if this CLI is killed, your laptop sleeps,
|
|
235
|
+
or the network dies. This is the layer that actually protects your wallet.
|
|
236
|
+
2. **A local ledger.** Every command opportunistically sweeps instances past their TTL
|
|
237
|
+
and powers them off. Catches the cases layer 1 can't — a `start_command` that
|
|
238
|
+
silently failed, or a manual power-on with no fresh timer.
|
|
239
|
+
3. **Idle detection.** `autodl guard idle <id>` samples GPU utilisation over SSH and
|
|
240
|
+
shuts down after a sustained lull.
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
autodl guard ttl pro-xxx 2h # arm/re-arm on a running instance
|
|
244
|
+
autodl guard cancel pro-xxx # disarm
|
|
245
|
+
autodl guard list # what this machine is tracking
|
|
246
|
+
autodl guard sweep # reclaim everything past its TTL now
|
|
247
|
+
autodl guard idle pro-xxx --threshold 5 --samples 6 --interval 1m
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
A **balance gate** also refuses to create an instance when your wallet is below
|
|
251
|
+
`--min-balance` (default ¥5). AutoDL doesn't reclaim instances the moment the balance
|
|
252
|
+
hits zero — it keeps them to protect your data — so a low balance turns into a stuck,
|
|
253
|
+
unusable instance rather than a clean failure.
|
|
254
|
+
|
|
255
|
+
## The agent contract
|
|
256
|
+
|
|
257
|
+
Stable across minor versions. Breaking changes require a major.
|
|
258
|
+
|
|
259
|
+
**stdout in `--json` mode is pure JSON.** Progress, prompts and warnings all go to
|
|
260
|
+
stderr, so `autodl ... --json | jq` is always safe.
|
|
261
|
+
|
|
262
|
+
```jsonc
|
|
263
|
+
// success
|
|
264
|
+
{ "ok": true, "data": { /* ... */ } }
|
|
265
|
+
|
|
266
|
+
// failure
|
|
267
|
+
{ "ok": false, "error": { "code": "NO_STOCK", "message": "…", "hint": "…", "requestId": "…" } }
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
| Exit | Meaning | Error codes |
|
|
271
|
+
|---:|---|---|
|
|
272
|
+
| 0 | Success | — |
|
|
273
|
+
| 1 | Generic failure | `GENERIC`, `API_ERROR`, `NETWORK` |
|
|
274
|
+
| 2 | Bad arguments | `USAGE` |
|
|
275
|
+
| 3 | Token missing or invalid | `AUTH_MISSING`, `AUTH_INVALID` |
|
|
276
|
+
| 4 | Resource not found | `NOT_FOUND` |
|
|
277
|
+
| 5 | Out of budget / blocked by a guard | `INSUFFICIENT_BALANCE`, `GUARD_BLOCKED` |
|
|
278
|
+
| 6 | No GPU stock | `NO_STOCK` |
|
|
279
|
+
| 7 | Timed out | `TIMEOUT` |
|
|
280
|
+
| 8 | SSH failure | `SSH_FAILED` |
|
|
281
|
+
|
|
282
|
+
`autodl exec` and `autodl run` instead exit with the **remote** command's exit code, so
|
|
283
|
+
`autodl exec box "make test" && deploy` behaves the way you'd expect.
|
|
284
|
+
|
|
285
|
+
## Commands
|
|
286
|
+
|
|
287
|
+
| Command | What it does |
|
|
288
|
+
|---|---|
|
|
289
|
+
| `login` / `logout` / `whoami` | Token management |
|
|
290
|
+
| `account` | Balance, vouchers, lifetime spend |
|
|
291
|
+
| `ls [--status]` | List instances |
|
|
292
|
+
| `info <id> [--show-password]` | Details, live SSH info, resource usage |
|
|
293
|
+
| `create --gpu <spec>` | Create a pay-as-you-go Pro instance |
|
|
294
|
+
| `start` / `stop` / `rm <id>` | Power on / off / release |
|
|
295
|
+
| `ssh <id>` | Interactive login (extra flags pass through to `ssh`) |
|
|
296
|
+
| `exec <id> <cmd…>` | Run a command, stream output, propagate exit code |
|
|
297
|
+
| `push` / `pull <id>` | SFTP transfer, recursive, respects ignore files |
|
|
298
|
+
| `run <cmd…>` | Create → sync → run → fetch → power off |
|
|
299
|
+
| `deploy <repo>` | Create → clone → install deps → start → **stop, keeping data** |
|
|
300
|
+
| `stock [--gpu] [--region]` | Live GPU stock per region |
|
|
301
|
+
| `guard ttl\|cancel\|idle\|list\|sweep` | Cost guards |
|
|
302
|
+
| `image save <id> <name>` / `images` | Private image management |
|
|
303
|
+
| `gpus` / `regions` | Catalogue lookup |
|
|
304
|
+
| `tui` | Interactive dashboard (also entered by a bare `autodl`) |
|
|
305
|
+
| `mcp` | Run as an MCP server |
|
|
306
|
+
|
|
307
|
+
Global flags: `--json`, `--yes`, `--token`, `--base-url`, `--lang zh|en`, `--verbose`,
|
|
308
|
+
`--no-color`, `--no-sweep`.
|
|
309
|
+
|
|
310
|
+
`push` and `pull` skip `.git`, `node_modules`, `__pycache__`, `.venv` and friends, then
|
|
311
|
+
apply `.autodlignore` if present, falling back to `.gitignore`.
|
|
312
|
+
|
|
313
|
+
## SDK
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
import {
|
|
317
|
+
AutoDLClient,
|
|
318
|
+
createInstance,
|
|
319
|
+
execCommand,
|
|
320
|
+
powerOffInstance,
|
|
321
|
+
waitForRunning,
|
|
322
|
+
} from "@minato-aqukin/autodl-cli";
|
|
323
|
+
|
|
324
|
+
const client = new AutoDLClient({ token: process.env.AUTODL_TOKEN! });
|
|
325
|
+
|
|
326
|
+
const uuid = await createInstance(client, {
|
|
327
|
+
gpuSpec: "v-48g",
|
|
328
|
+
gpuNum: 1,
|
|
329
|
+
imageUuid: "base-image-l2t43iu6uk",
|
|
330
|
+
cudaFrom: 118,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
await waitForRunning(client, uuid);
|
|
334
|
+
const { stdout } = await execCommand(client, uuid, "nvidia-smi");
|
|
335
|
+
console.log(stdout);
|
|
336
|
+
await powerOffInstance(client, uuid);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Everything re-exported from the package root is public API. Prices arrive as yuan
|
|
340
|
+
(`number`), timestamps as ISO strings, and Go's `sql.NullTime` shape is flattened to
|
|
341
|
+
`string | null`.
|
|
342
|
+
|
|
343
|
+
## What the official API cannot do
|
|
344
|
+
|
|
345
|
+
These are AutoDL's limits, not this tool's. Knowing them up front saves a lot of
|
|
346
|
+
confusion:
|
|
347
|
+
|
|
348
|
+
- **Pay-as-you-go only.** No daily/weekly/monthly plans and no renewal endpoint.
|
|
349
|
+
- **Pro instances only.** The seven specs in `autodl gpus` — the cheaper standard
|
|
350
|
+
instances aren't reachable through the open API.
|
|
351
|
+
- **No usable stock query for Pro.** The one capacity endpoint reports elastic-deployment
|
|
352
|
+
stock, which demonstrably does not match Pro availability (see above). Creation is
|
|
353
|
+
effectively a blind attempt; no capacity means exit code 6 and another spec to try.
|
|
354
|
+
- **Only two regions accept a Pro instance**: `westDC3` and `beijingDC2`.
|
|
355
|
+
- **No CPU-only boot _yet_.** AutoDL's own wording is deliberately provisional:
|
|
356
|
+
`payload` is documented as `"gpu:有卡开机, 暂不支持API以无卡模式开机"` — *not yet*
|
|
357
|
+
supported, rather than never. Confirmed on a live instance 2026-08-24: `cpu`,
|
|
358
|
+
`no_gpu`, `nogpu`, `cpu_only`, `cpu-only` and `none` all return
|
|
359
|
+
`ServerError | 不支持的启动模式`, and an empty `payload` is accepted but boots with the
|
|
360
|
+
GPU attached (`start_mode: "gpu"`). Use the web console for the ¥0.1/hr 无卡模式 in the
|
|
361
|
+
meantime; this tool will expose it once the API does.
|
|
362
|
+
- **Identity verification required** before the API will respond at all.
|
|
363
|
+
- **Missing operations:** rename, scheduled shutdown, resizing, migration, system reset.
|
|
364
|
+
- **SSH credentials can change on any power cycle** — port *and* root password. AutoDL
|
|
365
|
+
may reschedule the instance onto a different machine. It doesn't always happen (a real
|
|
366
|
+
stop/start was observed keeping both identical), which is precisely what makes caching
|
|
367
|
+
dangerous: a stale value works often enough to hide the bug until it doesn't. This tool
|
|
368
|
+
re-reads them on every connection, so you never have to think about it.
|
|
369
|
+
- **`running` does not mean sshd is ready.** A freshly created instance reports `running`
|
|
370
|
+
before it accepts connections. Connection attempts here are spaced out rather than
|
|
371
|
+
fired back to back.
|
|
372
|
+
- **A non-interactive SSH session has almost no PATH.** No python, pip or conda — they
|
|
373
|
+
live in `/root/miniconda3/bin` and arrive only through the login profile. Every remote
|
|
374
|
+
command here runs under `bash -lc` for that reason.
|
|
375
|
+
- **Releasing requires a completed shutdown**, and a second `power_off` on an instance
|
|
376
|
+
that is already stopping is an error. Both are handled internally.
|
|
377
|
+
|
|
378
|
+
Also worth knowing: **an instance left shut down for 15 consecutive days is released and
|
|
379
|
+
its data wiped.**
|
|
380
|
+
|
|
381
|
+
Verified against the live API on 2026-08-23: full lifecycle (create → SSH exec → SFTP
|
|
382
|
+
round trip → stop → start → exec again → release) on a 4090D, total cost ¥0.10.
|
|
383
|
+
|
|
384
|
+
The GPU spec, region and base-image tables are baked in because the API exposes no
|
|
385
|
+
catalogue endpoint. If AutoDL changes them, please
|
|
386
|
+
[open an issue](https://github.com/Minato-Aqukin/AutoDL-cli/issues).
|
|
387
|
+
|
|
388
|
+
## Development
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
npm install
|
|
392
|
+
npm run build
|
|
393
|
+
npm test # 325 tests, no network access, no cost
|
|
394
|
+
npm run lint
|
|
395
|
+
npm run typecheck
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Real end-to-end tests rent an actual GPU and cost actual money, so they're opt-in:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
AUTODL_E2E=1 AUTODL_TOKEN=<token> npm run test:e2e
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
They always power the instance down in an `afterAll`, even on failure. Add
|
|
405
|
+
`AUTODL_E2E_RELEASE=1` to release it too.
|
|
406
|
+
|
|
407
|
+
## Contributing
|
|
408
|
+
|
|
409
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](./CONTRIBUTING.md). Especially valuable:
|
|
410
|
+
corrections to the static catalogue, and real API error codes we haven't mapped yet
|
|
411
|
+
(AutoDL doesn't document them).
|
|
412
|
+
|
|
413
|
+
## License
|
|
414
|
+
|
|
415
|
+
[MIT](./LICENSE)
|