@meshy-ai/cli 0.3.1 → 0.4.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/README.md +69 -565
- package/dist/cmd/auth.d.ts.map +1 -1
- package/dist/cmd/auth.js +14 -12
- package/dist/cmd/auth.js.map +1 -1
- package/dist/cmd/download.d.ts.map +1 -1
- package/dist/cmd/download.js +3 -2
- package/dist/cmd/download.js.map +1 -1
- package/dist/cmd/make.d.ts.map +1 -1
- package/dist/cmd/make.js +26 -10
- package/dist/cmd/make.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -8
- package/dist/index.js.map +1 -1
- package/dist/internal/color.d.ts +37 -0
- package/dist/internal/color.d.ts.map +1 -0
- package/dist/internal/color.js +57 -0
- package/dist/internal/color.js.map +1 -0
- package/dist/internal/command-helpers.d.ts.map +1 -1
- package/dist/internal/command-helpers.js +5 -1
- package/dist/internal/command-helpers.js.map +1 -1
- package/dist/internal/context.d.ts +5 -0
- package/dist/internal/context.d.ts.map +1 -1
- package/dist/internal/context.js +5 -0
- package/dist/internal/context.js.map +1 -1
- package/dist/internal/doctor.d.ts +1 -0
- package/dist/internal/doctor.d.ts.map +1 -1
- package/dist/internal/doctor.js +17 -5
- package/dist/internal/doctor.js.map +1 -1
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +13 -4
- package/dist/internal/errors.js.map +1 -1
- package/dist/internal/global-options.d.ts.map +1 -1
- package/dist/internal/global-options.js +7 -3
- package/dist/internal/global-options.js.map +1 -1
- package/dist/internal/logger.d.ts.map +1 -1
- package/dist/internal/logger.js +2 -0
- package/dist/internal/logger.js.map +1 -1
- package/dist/internal/oauth-page.d.ts +4 -0
- package/dist/internal/oauth-page.d.ts.map +1 -0
- package/dist/internal/oauth-page.js +67 -0
- package/dist/internal/oauth-page.js.map +1 -0
- package/dist/internal/oauth.d.ts.map +1 -1
- package/dist/internal/oauth.js +10 -35
- package/dist/internal/oauth.js.map +1 -1
- package/dist/internal/output.d.ts +30 -4
- package/dist/internal/output.d.ts.map +1 -1
- package/dist/internal/output.js +96 -13
- package/dist/internal/output.js.map +1 -1
- package/dist/internal/progress.d.ts +62 -0
- package/dist/internal/progress.d.ts.map +1 -0
- package/dist/internal/progress.js +198 -0
- package/dist/internal/progress.js.map +1 -0
- package/dist/internal/runtime.d.ts +16 -1
- package/dist/internal/runtime.d.ts.map +1 -1
- package/dist/internal/runtime.js +22 -7
- package/dist/internal/runtime.js.map +1 -1
- package/dist/internal/task-command.d.ts +0 -1
- package/dist/internal/task-command.d.ts.map +1 -1
- package/dist/internal/task-command.js +40 -10
- package/dist/internal/task-command.js.map +1 -1
- package/dist/internal/update-notifier.d.ts +10 -2
- package/dist/internal/update-notifier.d.ts.map +1 -1
- package/dist/internal/update-notifier.js +13 -6
- package/dist/internal/update-notifier.js.map +1 -1
- package/dist/internal/version.d.ts +10 -0
- package/dist/internal/version.d.ts.map +1 -1
- package/dist/internal/version.js +17 -6
- package/dist/internal/version.js.map +1 -1
- package/dist/internal/views.d.ts +57 -0
- package/dist/internal/views.d.ts.map +1 -0
- package/dist/internal/views.js +570 -0
- package/dist/internal/views.js.map +1 -0
- package/dist/root.d.ts.map +1 -1
- package/dist/root.js +4 -1
- package/dist/root.js.map +1 -1
- package/package.json +3 -3
- package/skills/meshy-cli/SKILL.md +11 -3
package/README.md
CHANGED
|
@@ -1,600 +1,104 @@
|
|
|
1
1
|
# meshy-cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`api` passthrough for endpoints the CLI doesn't model yet and a `skills/`
|
|
9
|
-
directory of agent-facing documentation.
|
|
10
|
-
|
|
11
|
-
The flag surface is deliberately curated rather than a 1:1 mirror of the API: deprecated parameters (`symmetry_mode`, `hd_texture`, `is_a_t_pose`) are not exposed, geometry knobs live on `remesh` and sizing on `resize` instead of every generation command, and defaults are pinned to game-ready values (PBR maps on, 4k textures — same credit cost as the bare defaults). Everything the API accepts remains reachable through `--data`.
|
|
3
|
+
The command line for the [Meshy AI API](https://docs.meshy.ai/): text-to-3D,
|
|
4
|
+
image-to-3D, text-to-motion, remesh, convert, resize, UV unwrap, rigging,
|
|
5
|
+
animation, retexture, 2D images, multi-color print, Creative Lab products, plus
|
|
6
|
+
the local helpers a 3D-printing or agent workflow needs. Built for people and
|
|
7
|
+
AI agents: a terminal gets a readable view, a pipe or an agent gets JSON.
|
|
12
8
|
|
|
13
9
|
## Install
|
|
14
10
|
|
|
15
|
-
Requires Node
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npm i -g meshy-cli # installs `meshy-cli` and `meshy`
|
|
19
|
-
meshy --help
|
|
20
|
-
meshy doctor # local diagnosis: versions, credential sources, base URLs (no network)
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
The same build is also published under the scoped alias
|
|
24
|
-
[`@meshy-ai/cli`](https://www.npmjs.com/package/@meshy-ai/cli)
|
|
25
|
-
(`npm i -g @meshy-ai/cli`) — identical contents, pick whichever name you
|
|
26
|
-
remember; don't install both.
|
|
27
|
-
|
|
28
|
-
### Development
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
# straight from git (`prepare` builds dist for you)
|
|
32
|
-
npm i -g git+https://github.com/meshy-dev/meshy-cli.git
|
|
33
|
-
|
|
34
|
-
# or clone for local development
|
|
35
|
-
pnpm install
|
|
36
|
-
pnpm build
|
|
37
|
-
node dist/index.js --help
|
|
38
|
-
pnpm link --global # exposes `meshy` / `meshy-cli` on $PATH
|
|
39
|
-
pnpm typecheck && pnpm test # `pnpm test` rebuilds dist first (subprocess tests run it)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Auth
|
|
43
|
-
|
|
44
|
-
Log in once and the credential is stored for you:
|
|
11
|
+
Requires Node 22.12+. No Python, no other runtime.
|
|
45
12
|
|
|
46
13
|
```bash
|
|
47
|
-
|
|
48
|
-
meshy
|
|
49
|
-
meshy auth status # what's in effect, and does it work
|
|
14
|
+
npm i -g meshy-cli # installs `meshy` and `meshy-cli`
|
|
15
|
+
meshy doctor # checks the environment, no network
|
|
50
16
|
```
|
|
51
17
|
|
|
52
|
-
The
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
In headless or agent contexts where a browser is not available, use
|
|
58
|
-
`--with-key` or set `MESHY_API_KEY` instead. Set `MESHY_CLI_NO_BROWSER=1` to
|
|
59
|
-
suppress the browser-open attempt (the URL is still printed to stderr).
|
|
18
|
+
The same build is published as [`@meshy-ai/cli`](https://www.npmjs.com/package/@meshy-ai/cli).
|
|
19
|
+
**Install one, not both**: they share the `meshy` binary and npm refuses the
|
|
20
|
+
second with `EEXIST` (`npm uninstall -g @meshy-ai/cli && npm i -g meshy-cli` to
|
|
21
|
+
switch). If `meshy --version` reports 0.1.x on Node 22, reinstall: 0.2.0–0.3.1
|
|
22
|
+
declared `node >=24` by mistake, and npm silently picked 0.1.3 instead.
|
|
60
23
|
|
|
61
|
-
|
|
24
|
+
## Log in
|
|
62
25
|
|
|
63
26
|
```bash
|
|
64
|
-
|
|
65
|
-
meshy
|
|
66
|
-
meshy
|
|
27
|
+
meshy auth login # browser sign-in, stored for you
|
|
28
|
+
meshy auth login --with-key msy_your_key_here # or paste an API key
|
|
29
|
+
meshy auth status
|
|
67
30
|
```
|
|
68
31
|
|
|
69
|
-
Get a key at
|
|
70
|
-
|
|
71
|
-
**Resolution order:** `--api-key` › `MESHY_API_KEY` › `--api-key-file` › the active stored profile.
|
|
72
|
-
The environment variable stays ahead of the stored credential on purpose, so a
|
|
73
|
-
CI runner is never overridden by whatever a developer once logged into on that
|
|
74
|
-
machine. With none of the four, commands exit `3` and print the command that
|
|
75
|
-
fixes it. An empty or placeholder `--api-key` / `MESHY_API_KEY` counts as unset.
|
|
76
|
-
|
|
77
|
-
**`--api-key-file`** reads exactly one variable, `MESHY_API_KEY`, from a
|
|
78
|
-
dotenv-style file (`export` prefix, quotes and `#` comments accepted; nothing is
|
|
79
|
-
expanded or executed, other keys are ignored). A file you name but that is
|
|
80
|
-
missing, malformed or key-less is an error — never a silent fall-through to
|
|
81
|
-
another account. There is no automatic `.env` discovery. The flag is not called
|
|
82
|
-
`--env-file` because Node.js itself intercepts that name anywhere in argv and
|
|
83
|
-
loads the whole file into the environment before the CLI starts.
|
|
84
|
-
|
|
85
|
-
**Where it lives:** `~/.config/meshy/credentials.json`, mode `0600`, on every
|
|
86
|
-
platform (`MESHY_CONFIG_DIR` or `MESHY_CREDENTIALS_PATH` move it). Writes go
|
|
87
|
-
through a cross-process lock and a temp-file rename, because several agents
|
|
88
|
-
driving this CLI at once is the normal case. A non-production `--base-url-v1`
|
|
89
|
-
reads and writes `credentials.dev.json` instead, so staging cannot clobber a
|
|
90
|
-
production login. Stored profiles are only ever sent to the v1/v2 origins they
|
|
91
|
-
were resolved for (and to a Creative Lab base on the same origin).
|
|
92
|
-
|
|
93
|
-
**OAuth token refresh:** when the stored OAuth access token is within 60 seconds
|
|
94
|
-
of expiry (or already expired), the CLI silently refreshes it using the stored
|
|
95
|
-
refresh token before running the command. A refresh failure with an unexpired
|
|
96
|
-
token is swallowed (the existing token is used); a failure with an expired token
|
|
97
|
-
exits `3` with a hint to run `meshy auth login`.
|
|
32
|
+
In CI, set `MESHY_API_KEY` instead; it wins over a stored login. Get a key at
|
|
33
|
+
<https://www.meshy.ai/settings/api>.
|
|
98
34
|
|
|
99
|
-
|
|
100
|
-
`auth logout [--all]`.
|
|
35
|
+
## Quick start
|
|
101
36
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
`make` chains the documented flows so a caller who wants a model does not have
|
|
105
|
-
to pick an endpoint and carry task ids between steps:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
meshy make "a red sports car" -o car.glb # text-to-3d preview → refine
|
|
109
|
-
meshy make ./cat.png -o out/cat/ # image-to-3d, textured
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
The input decides the chain: a prompt runs the two-stage text flow, an image
|
|
113
|
-
runs the single textured `image-to-3d` task. There is no third judgement — no
|
|
114
|
-
route picked by inspecting the input, no image step inserted ahead of a prompt,
|
|
115
|
-
no pause between stages. Those are opinions, and a CLI that acts on its own
|
|
116
|
-
opinions spends someone else's credits. Compose anything else from the resource
|
|
117
|
-
commands below.
|
|
37
|
+
One command, one model. `make` chains the documented flow — a prompt runs
|
|
38
|
+
text-to-3D preview then refine; an image runs one textured image-to-3D task:
|
|
118
39
|
|
|
119
40
|
```bash
|
|
120
|
-
meshy make "a
|
|
121
|
-
meshy make
|
|
122
|
-
meshy make "a red sports car" --
|
|
123
|
-
meshy make "a red sports car" --stop-after-first # wait for step 1, then return the resume command
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
All guards run before the first task is created. If a later step fails, the
|
|
127
|
-
error carries the finished step's task id and the command that resumes from it —
|
|
128
|
-
running that beats starting over, which would pay for the finished step twice.
|
|
129
|
-
`--async` and `--stop-after-first` are mutually exclusive.
|
|
130
|
-
|
|
131
|
-
## At a glance
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
# account
|
|
135
|
-
meshy-cli balance
|
|
136
|
-
|
|
137
|
-
# text → 3D (sync by default: blocks until the task finishes)
|
|
138
|
-
meshy-cli text-to-3d create --mode preview --prompt "a red sports car"
|
|
139
|
-
meshy-cli text-to-3d create --mode refine --preview-task-id <id>
|
|
140
|
-
|
|
141
|
-
# image → 3D
|
|
142
|
-
meshy-cli image-to-3d create --image-url https://example.com/cat.png
|
|
143
|
-
|
|
144
|
-
# text → standalone motion clip (Prime/FBX by default; Swift produces BVH)
|
|
145
|
-
meshy-cli text-to-motion create --prompt "a character waving" --duration 3
|
|
146
|
-
|
|
147
|
-
# smart topology: component-aware low-poly with a native polycount
|
|
148
|
-
meshy-cli image-to-3d create --image-url cat.png --model-type smart-topology --target-polycount 10000
|
|
149
|
-
|
|
150
|
-
# fire-and-forget (--async): exactly one POST, returns the task_id, query later
|
|
151
|
-
TASK=$(meshy-cli text-to-image create --prompt "mountain landscape" --async --output-schema v1 | jq -r .result.submission.task_id)
|
|
152
|
-
meshy-cli text-to-image get "$TASK" --output-schema v1
|
|
153
|
-
meshy-cli text-to-image wait "$TASK" --output-schema v1 --save-json ./task.json
|
|
154
|
-
meshy-cli text-to-image stream "$TASK" --format ndjson --output-schema v1 # Server-Sent Events
|
|
155
|
-
|
|
156
|
-
# UV unwrap and Creative Lab (photo → printable product, two stages)
|
|
157
|
-
meshy uv-unwrap create --input-task-id <id> --async
|
|
158
|
-
meshy creative-lab figure prototype create --image-url ./photo.png --name demo --async
|
|
159
|
-
meshy creative-lab figure build create --input-task-id <prototype-id> --async
|
|
160
|
-
meshy creative-lab lamp build create --input-task-id <id> --model-format zip --options '{"diameter_mm":180}'
|
|
161
|
-
|
|
162
|
-
# public animation catalog (no key) and Enterprise showcases (billed per request)
|
|
163
|
-
meshy animation-catalog list --category DailyActions --search wave
|
|
164
|
-
meshy showcases list --search car --page-size 3 --model-format glb
|
|
165
|
-
|
|
166
|
-
# local helpers (no key, no network)
|
|
167
|
-
meshy download --task-json ./task.json --asset result.basic_animations.walking_glb_url --output walking.glb
|
|
168
|
-
meshy project init --root ./meshy_output --name demo
|
|
169
|
-
meshy inspect faces --task-json ./task.json --max-faces 300000
|
|
170
|
-
meshy mesh prepare-print ./model.obj --height-mm 75
|
|
171
|
-
meshy slicer detect
|
|
172
|
-
meshy doctor
|
|
173
|
-
|
|
174
|
-
# raw passthrough for any endpoint
|
|
175
|
-
meshy-cli api GET /balance
|
|
176
|
-
meshy-cli api POST /text-to-3d --data '{"mode":"preview","prompt":"a cactus"}'
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## Stable machine output: `--output-schema v1`
|
|
180
|
-
|
|
181
|
-
Existing commands keep their 0.2.0 output (`legacy`) unless told otherwise; the
|
|
182
|
-
commands added in this release always speak `v1`. Pass `--output-schema v1` to
|
|
183
|
-
get one envelope with six fixed keys on stdout, in `json` (default), `pretty`
|
|
184
|
-
or `ndjson`:
|
|
185
|
-
|
|
186
|
-
```json
|
|
187
|
-
{
|
|
188
|
-
"schema_version": "meshy.cli/v1",
|
|
189
|
-
"command": "image-to-3d.get",
|
|
190
|
-
"ok": true,
|
|
191
|
-
"result": {
|
|
192
|
-
"task": { "task_id": "…", "resource": "image-to-3d", "status": "IN_PROGRESS", "progress": 52,
|
|
193
|
-
"face_count": null, "consumed_credits": null, "model_urls": {}, "task_error": null, "…": "…" },
|
|
194
|
-
"submission": { "state": "accepted", "operation_id": null },
|
|
195
|
-
"downloads": { "state": "not_requested", "files": [], "metadata_path": null },
|
|
196
|
-
"saved_json": null
|
|
197
|
-
},
|
|
198
|
-
"error": null,
|
|
199
|
-
"warnings": []
|
|
200
|
-
}
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
`ok` says whether the CLI operation completed; `result.task.status` is the
|
|
204
|
-
server's task state. A `get` of a FAILED task is `ok:true` (the query worked);
|
|
205
|
-
a `wait` that ends on FAILED is `ok:false` with the whole task kept in `result`.
|
|
206
|
-
Fields the server did not send are `null` — a missing `face_count` is never `0`.
|
|
207
|
-
`--include-raw` adds the untouched response under `result.task.raw`;
|
|
208
|
-
`--save-json <file>` writes the raw API JSON (never the envelope) and refuses to
|
|
209
|
-
overwrite. Progress and update notices go to stderr, so stdout is always exactly
|
|
210
|
-
one JSON document (`ndjson` streams emit one line per event plus a final
|
|
211
|
-
`outcome` line). Errors are envelopes too:
|
|
212
|
-
|
|
213
|
-
```json
|
|
214
|
-
{ "schema_version": "meshy.cli/v1", "command": "text-to-3d.create", "ok": false,
|
|
215
|
-
"result": { "submission": { "state": "unknown", "operation_id": "…" }, "task": null },
|
|
216
|
-
"error": { "code": "submission_unknown", "message": "…", "http_status": null, "retryable": false,
|
|
217
|
-
"recovery": { "action": "reconcile", "automatic": false, "command": "meshy text-to-3d list …" } },
|
|
218
|
-
"warnings": [] }
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Create, wait, stream and money
|
|
222
|
-
|
|
223
|
-
- `create` sends **exactly one POST**, journaled locally before it leaves
|
|
224
|
-
(`~/.config/meshy/operations/<operation-id>.json`, no key material). A lost
|
|
225
|
-
response, a 5xx or a malformed success is `submission_unknown` (exit 10): the
|
|
226
|
-
server may have created the task, so the CLI never retries and never suggests
|
|
227
|
-
re-running the create. Reconcile with `list`, then decide.
|
|
228
|
-
- `--operation-id <id>` replays the recorded outcome of an identical earlier
|
|
229
|
-
request instead of submitting again; a different request under the same id is
|
|
230
|
-
refused (`operation_conflict`, exit 2, naming what differs). "Identical" means
|
|
231
|
-
the same resource, API origin, credential — a one-way digest of the API key,
|
|
232
|
-
or the OAuth account (its user id, else the login id `meshy auth login` mints
|
|
233
|
-
for the profile) — and payload, with every inline image or model hashed by
|
|
234
|
-
content. An OAuth profile saved before login ids existed carries no verifiable
|
|
235
|
-
identity: it can start operations but is refused a replay (exit 2,
|
|
236
|
-
`credential_unverified`) until you log in again. This is a local record, not a
|
|
237
|
-
server-side idempotency key.
|
|
238
|
-
- Local targets that would fail after the POST are checked before it: an
|
|
239
|
-
existing `--save-json` file, an `-o` path outside `--workspace`, a missing
|
|
240
|
-
`--project` all exit 11 with "nothing was submitted" and cost no request.
|
|
241
|
-
- Once the server has accepted a task, every later failure — saving JSON,
|
|
242
|
-
polling (a 503), downloading, recording, Ctrl-C — still reports
|
|
243
|
-
`result.task_id`, `result.submission` and `result.next` (the `get`/`wait`/
|
|
244
|
-
`stream` commands that pick the task up). A bookkeeping problem never reads
|
|
245
|
-
as "no task was created".
|
|
246
|
-
- `--async` returns after the POST (no polling). `get` is a query: any status
|
|
247
|
-
exits 0. `wait --timeout N` polls with a monotonic deadline (`0` = one query)
|
|
248
|
-
that also bounds every in-flight GET: a response arriving after the deadline
|
|
249
|
-
is a timeout (exit 8, last status kept, `result.task` null when none arrived
|
|
250
|
-
in time), never a late success, and no request starts once the budget is
|
|
251
|
-
spent. `stream` follows Server-Sent Events with `--timeout` (total) and
|
|
252
|
-
`--idle-timeout` (silence, keep-alives reset it); `-o` downloads the assets
|
|
253
|
-
in every output format, and in `ndjson` the final `outcome` line carries the
|
|
254
|
-
download manifest.
|
|
255
|
-
- `-o` on `get`/`wait`/`stream`/`make` downloads every artifact of a SUCCEEDED
|
|
256
|
-
task; `result.downloads.files` is a per-file manifest (key, path, bytes,
|
|
257
|
-
sha256, status). When the second asset fails, the state is `partial`, the files
|
|
258
|
-
already written stay listed and on disk, and the error keeps the asset host's
|
|
259
|
-
class and HTTP status (a 503 is `network`, exit 7, not a local I/O error). The
|
|
260
|
-
same holds for a failure *after* the transfers — relinking, digesting or
|
|
261
|
-
publishing the `meta.json` sidecar: `downloads.failed_step` names the step, the
|
|
262
|
-
manifest carries the digests actually on disk. The sidecar itself is published
|
|
263
|
-
like an asset (exclusive, no symlink, inside the root), so a file that appears
|
|
264
|
-
at its path during the download is never overwritten. The legacy schema
|
|
265
|
-
reports the same failures with additive `task_id`/`operation_id` fields and the
|
|
266
|
-
resume command as `hint`, so the accepted task is never lost from a default
|
|
267
|
-
`create -o` error.
|
|
268
|
-
- Ctrl-C stops waiting, streaming or downloading (exit 130) and sends no DELETE;
|
|
269
|
-
the envelope carries the task id, the command that resumes and the files that
|
|
270
|
-
had already landed. An interrupted transfer leaves no temp file behind.
|
|
271
|
-
|
|
272
|
-
## Resources
|
|
273
|
-
|
|
274
|
-
One command per endpoint. They are all registered and all supported, but they
|
|
275
|
-
are indexed by `meshy resources` rather than listed in `meshy --help` — that
|
|
276
|
-
help text is read on every invocation (an agent pays for the whole surface each
|
|
277
|
-
time), so it should not grow with the API. `meshy <resource> --help` documents
|
|
278
|
-
each one in full; `meshy resources --output-schema v1` also lists the query and
|
|
279
|
-
local commands with their kind.
|
|
280
|
-
|
|
281
|
-
| Command | Meshy endpoint | Docs |
|
|
282
|
-
|---|---|---|
|
|
283
|
-
| `balance` | `GET /balance` | [docs](https://docs.meshy.ai/en/api/balance) |
|
|
284
|
-
| `text-to-3d` | `/text-to-3d` (v2) | [docs](https://docs.meshy.ai/en/api/text-to-3d) |
|
|
285
|
-
| `image-to-3d` | `/image-to-3d` | [docs](https://docs.meshy.ai/en/api/image-to-3d) |
|
|
286
|
-
| `multi-image-to-3d` | `/multi-image-to-3d` | [docs](https://docs.meshy.ai/en/api/multi-image-to-3d) |
|
|
287
|
-
| `remesh` | `/remesh` | [docs](https://docs.meshy.ai/en/api/remesh) |
|
|
288
|
-
| `convert` | `/convert` | [docs](https://docs.meshy.ai/en/api/convert) |
|
|
289
|
-
| `resize` | `/resize` | [docs](https://docs.meshy.ai/en/api/resize) |
|
|
290
|
-
| `uv-unwrap` | `/uv-unwrap` | [docs](https://docs.meshy.ai/en/api/uv-unwrap) |
|
|
291
|
-
| `rigging` | `/rigging` | [docs](https://docs.meshy.ai/en/api/rigging) |
|
|
292
|
-
| `animate` | `/animations` | [docs](https://docs.meshy.ai/en/api/animations) |
|
|
293
|
-
| `text-to-motion` | `/text-to-motion` | [docs](https://docs.meshy.ai/en/api/text-to-motion) |
|
|
294
|
-
| `retexture` | `/retexture` | [docs](https://docs.meshy.ai/en/api/retexture) |
|
|
295
|
-
| `text-to-image` | `/text-to-image` | [docs](https://docs.meshy.ai/en/api/text-to-image) |
|
|
296
|
-
| `image-to-image` | `/image-to-image` | [docs](https://docs.meshy.ai/en/api/image-to-image) |
|
|
297
|
-
| `multi-color-print` | `/print/multi-color` | [docs](https://docs.meshy.ai/en/api/multi-color-print) |
|
|
298
|
-
| `analyze-printability` | `/print/analyze` | [docs](https://docs.meshy.ai/en/api/analyze-printability) |
|
|
299
|
-
| `repair-printability` | `/print/repair` | [docs](https://docs.meshy.ai/en/api/repair-printability) |
|
|
300
|
-
| `creative-lab <product> prototype\|build` | `/openapi/creative-lab/<product>/v1/<stage>` | [figure](https://docs.meshy.ai/en/api/creative-lab-figure) · [lamp](https://docs.meshy.ai/en/api/creative-lab-lamp) · [keychain](https://docs.meshy.ai/en/api/creative-lab-keychain) · [fridge-magnet](https://docs.meshy.ai/en/api/creative-lab-fridge-magnet) |
|
|
301
|
-
| `animation-catalog list` | `GET /web/public/animations/resources` (no key) | [docs](https://docs.meshy.ai/en/api/animations) |
|
|
302
|
-
| `showcases list` | `GET /showcases` (Enterprise; every request is billed) | [docs](https://docs.meshy.ai/en/api/enterprise-api) |
|
|
303
|
-
|
|
304
|
-
Per-resource actions (all single-HTTP-call except `wait`/`stream`):
|
|
305
|
-
|
|
306
|
-
```
|
|
307
|
-
meshy-cli <resource> create [flags] [--data <json>] [--async] [--timeout <s>] [--operation-id <id>]
|
|
308
|
-
meshy-cli <resource> get <task-id> [--save-json <file>] [--include-raw] [--project <dir>]
|
|
309
|
-
meshy-cli <resource> list [--page <n>] [--page-size <n>] [--sort-by <field>]
|
|
310
|
-
meshy-cli <resource> wait <task-id> [--timeout <s>]
|
|
311
|
-
meshy-cli <resource> stream <task-id> [--timeout <s>] [--idle-timeout <s>]
|
|
312
|
-
meshy-cli <resource> delete <task-id>
|
|
41
|
+
meshy make "a lovely baby husky"
|
|
42
|
+
meshy make ./cat.png -o out/cat/ # -o downloads the result
|
|
43
|
+
meshy make "a red sports car" --dry-run # steps and credit estimate, no spend
|
|
313
44
|
```
|
|
314
45
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
meshy-cli delete <task-id>
|
|
319
|
-
# Meshy's DELETE is unified across resources, but GET is not, so
|
|
320
|
-
# `get`/`wait`/`stream` live only on their resource.
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
`create` is **synchronous by default** — it polls until the task reaches a
|
|
324
|
-
terminal status (`SUCCEEDED` / `FAILED` / `CANCELED`) or `--timeout` hits.
|
|
325
|
-
Pass `--async` to return the `task_id` immediately; then call
|
|
326
|
-
`<resource> get <id>`, `wait <id>` or `stream <id>` when you need the result.
|
|
327
|
-
|
|
328
|
-
### Creative Lab
|
|
329
|
-
|
|
330
|
-
Four products (`figure`, `lamp`, `keychain`, `fridge-magnet`), each with a
|
|
331
|
-
`prototype` stage (photo → styled concept image; the lamp prototype also yields
|
|
332
|
-
a lampshade GLB) and a `build` stage that consumes a SUCCEEDED prototype created
|
|
333
|
-
through this API with the same key. Build options are validated per product
|
|
334
|
-
before anything is sent: lamp `--options` (diameter, thickness, light-source
|
|
335
|
-
preset, rotations …) with `--model-format stl|zip`; keychain and fridge-magnet
|
|
336
|
-
relief options with `--model-format glb|obj|zip` — their `obj` output is a ZIP
|
|
337
|
-
bundle and is saved as `.zip`; figure has no options. Prototypes made in the
|
|
338
|
-
web app are rejected by the server (404).
|
|
46
|
+
```text
|
|
47
|
+
✓ [1/2] text-to-3d preview (geometry) 01a0c94c-… 1m 27s
|
|
48
|
+
✓ [2/2] text-to-3d refine (textures) 01a0c94d-… 5m 36s
|
|
339
49
|
|
|
340
|
-
|
|
50
|
+
✓ SUCCEEDED text-to-3d-refine
|
|
51
|
+
Task 01a0c94d-eaba-710e-b5b7-da5b2f620c95
|
|
52
|
+
Took 7m 03s
|
|
53
|
+
Credits ~30 (estimate for the whole chain)
|
|
54
|
+
Assets glb, fbx · textures: base_color, metallic, normal, roughness · thumbnail
|
|
341
55
|
|
|
342
|
-
|
|
343
|
-
the task produced, writes a sidecar metadata file, and (legacy schema) prints a
|
|
344
|
-
status report instead of JSON. Single-file outputs get a per-file
|
|
345
|
-
`<stem>_meta.json`; directory-mode outputs share a single `meta.json`. Under
|
|
346
|
-
`--output-schema v1` the same download is reported in `result.downloads`, and a
|
|
347
|
-
task that is not yet SUCCEEDED yields `downloads.state: "not_ready"` with exit 0.
|
|
348
|
-
|
|
349
|
-
```bash
|
|
350
|
-
meshy-cli text-to-image create --ai-model nano-banana-2-lite --prompt "a leaf" -o assets/leaf.jpeg
|
|
351
|
-
meshy-cli text-to-image create --ai-model gpt-image-2-5-sunburst --aspect-ratio 3:2 --prompt "a leaf" -o assets/leaf-wide.png
|
|
352
|
-
meshy-cli image-to-3d wait <id> -o out/robot/
|
|
56
|
+
tip: download it now: meshy download --resource text-to-3d --task-id 01a0c94d-… --all --output-dir ./a-lovely-baby-husky
|
|
353
57
|
```
|
|
354
58
|
|
|
355
|
-
|
|
59
|
+
Every Meshy endpoint is also a command of its own, with the same verbs:
|
|
356
60
|
|
|
357
61
|
```bash
|
|
358
|
-
meshy
|
|
359
|
-
meshy
|
|
360
|
-
meshy
|
|
361
|
-
meshy
|
|
362
|
-
meshy download --resource
|
|
363
|
-
meshy
|
|
62
|
+
meshy text-to-3d create --mode preview --prompt "a red sports car"
|
|
63
|
+
meshy image-to-3d create --image-url ./cat.png --async # returns the task id at once
|
|
64
|
+
meshy image-to-3d wait <task-id> -o out/cat/
|
|
65
|
+
meshy text-to-3d list
|
|
66
|
+
meshy download --resource text-to-3d --task-id <task-id> --list
|
|
67
|
+
meshy balance
|
|
68
|
+
meshy resources # every command
|
|
364
69
|
```
|
|
365
70
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
command lists the candidates and exits 2 instead of guessing. Selecting an OBJ
|
|
370
|
-
pulls its MTL and textures (`--geometry-only` to skip); once the set has landed
|
|
371
|
-
the OBJ's `mtllib` and the MTL's `map_*` references are rewritten to the names
|
|
372
|
-
actually saved (`model.mtl`, `texture_0_base_color.png`, …) so the model loads
|
|
373
|
-
from that directory. Textures are matched by the name the server served them
|
|
374
|
-
under (then by channel), one candidate only: with several material groups a
|
|
375
|
-
reference that could mean two files is left as written and reported as
|
|
376
|
-
ambiguous, and a reference that merely equals one of the CLI's generated names
|
|
377
|
-
(`texture_0_base_color.png`) while the server called that image something else
|
|
378
|
-
is ambiguous too — identity follows the source, never the file name on disk.
|
|
379
|
-
Channel fallbacks (a channel word in the reference, the MTL key's channel, the
|
|
380
|
-
only texture there is) are heuristics and compete on the texture they actually
|
|
381
|
-
reach: when two different references would both fall back to the same image, or
|
|
382
|
-
one reference would go to different images under different keys, they all stay
|
|
383
|
-
as written and are reported as ambiguous — the CLI never merges material groups
|
|
384
|
-
without evidence that they name the same file. Every link is listed under `result.downloads.material_links`
|
|
385
|
-
(`status: complete | incomplete`, the `newmtl` group of each map), rewritten
|
|
386
|
-
files carry `relinked: true` with their final sha256, and a reference that
|
|
387
|
-
matches no or several downloaded files stays as written and is warned
|
|
388
|
-
(`material_reference_unresolved` / `material_reference_ambiguous`). Files are published
|
|
389
|
-
exclusively (never overwritten without `--overwrite`), checked against the
|
|
390
|
-
content type and magic bytes, kept inside the output directory (or `--workspace`),
|
|
391
|
-
and listed with size and sha256 in `result.downloads.files`. With `--project <dir>`
|
|
392
|
-
the files that landed inside the project are recorded in its `metadata.json`;
|
|
393
|
-
when that record fails after the transfer (metadata.json replaced by a symlink,
|
|
394
|
-
damaged, or locked) the command exits 11 with the complete `result` — manifest,
|
|
395
|
-
`saved_json`, `project.action: "failed"` — and `error.recovery.command` is the
|
|
396
|
-
one `meshy project record …` invocation that redoes the record — carrying the
|
|
397
|
-
original `--workspace`, so a recovery never writes further than the command that
|
|
398
|
-
failed; the assets stay where they landed. Problems visible before the transfer (no metadata.json, a
|
|
399
|
-
symlink or invalid JSON in its place, a blank `--stage`) are refused with no
|
|
400
|
-
request made. Asset hosts never
|
|
401
|
-
receive the API credential; an expired signed URL is refreshed once when the
|
|
402
|
-
task came from the API and reported as unrefreshable when it came from a file.
|
|
403
|
-
|
|
404
|
-
## Projects (`meshy_output/`)
|
|
405
|
-
|
|
406
|
-
The Skills' project layout, without Python:
|
|
407
|
-
|
|
408
|
-
```bash
|
|
409
|
-
meshy project init --root ./meshy_output --name "demo" --task-id <id>
|
|
410
|
-
meshy text-to-3d wait <id> --project ./meshy_output/<folder> # saves task_<id>.json, records the stage
|
|
411
|
-
meshy project record --project ./meshy_output/<folder> --task-id <id> --resource text-to-3d --stage preview --file preview.glb
|
|
412
|
-
meshy project show --project ./meshy_output/<folder>
|
|
413
|
-
meshy project list --root ./meshy_output
|
|
414
|
-
meshy project rebuild-index --root ./meshy_output
|
|
415
|
-
```
|
|
71
|
+
`create / get / list / wait / stream / delete` work the same way on every
|
|
72
|
+
resource; `meshy <resource> --help` documents each one, and
|
|
73
|
+
`meshy api GET /balance` reaches any endpoint the CLI does not model yet.
|
|
416
74
|
|
|
417
|
-
|
|
418
|
-
write with a backup) is the source of truth; `history.json` is a rebuildable
|
|
419
|
-
index. A repeat `(task_id, stage)` merges instead of duplicating.
|
|
75
|
+
## For scripts and agents
|
|
420
76
|
|
|
421
|
-
|
|
77
|
+
stdout is the result and nothing else; progress and messages go to stderr.
|
|
78
|
+
Piped, redirected or run by an agent, the output is JSON automatically. Ask for
|
|
79
|
+
the stable envelope explicitly and the shape never depends on how you are run:
|
|
422
80
|
|
|
423
81
|
```bash
|
|
424
|
-
meshy
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
## Image and 3D-model inputs
|
|
445
|
-
|
|
446
|
-
Flags that take a media source (`--image-url`, `--image-urls`,
|
|
447
|
-
`--reference-image-urls`, `--texture-image-url`, `--image-style-url`,
|
|
448
|
-
`--multiview-image-urls`, `--model-url`) — and the same fields inside `--data` —
|
|
449
|
-
accept:
|
|
450
|
-
|
|
451
|
-
- **http(s) URLs** — preflighted with an unauthenticated HEAD so unreachable sources fail fast.
|
|
452
|
-
- **Local file paths** — absolute or relative to cwd. MIME-sniffed via magic
|
|
453
|
-
bytes (with extension fallback), size-capped, and inlined as `data:` URIs on the wire.
|
|
454
|
-
- **`data:` URIs** — validated (base64, MIME kind, size) and passed through.
|
|
455
|
-
|
|
456
|
-
Missing files and 4xx/5xx preflights exit with code `2` and a flag-prefixed
|
|
457
|
-
message before any task is created. GLB-only fields (`uv-unwrap`, `rigging`
|
|
458
|
-
`--model-url`) reject other formats locally.
|
|
459
|
-
|
|
460
|
-
## Global flags
|
|
461
|
-
|
|
462
|
-
| Flag | Purpose |
|
|
463
|
-
|------|---------|
|
|
464
|
-
| `--api-key <key>` | Override `MESHY_API_KEY` |
|
|
465
|
-
| `--api-key-file <path>` | Read `MESHY_API_KEY` from an explicit dotenv-style file (only that key) |
|
|
466
|
-
| `--base-url-v1 <url>` / `--base-url-v2 <url>` | Override endpoints (staging/proxy) |
|
|
467
|
-
| `--base-url-creative-lab <url>` | Override the Creative Lab base (default: `<v1 origin>/openapi/creative-lab`) |
|
|
468
|
-
| `--output-schema legacy\|v1` | Stdout data model (existing commands default to `legacy`; new commands are `v1`) |
|
|
469
|
-
| `--format json\|pretty\|ndjson` | Stdout rendering (default `json`) |
|
|
470
|
-
| `-o, --output <path>` | Download artifacts to a file/directory (task commands); output file for `mesh prepare-print` |
|
|
471
|
-
| `--workspace <dir>` | Confine every written file to this directory: `download`, `-o` on task verbs and `make` (report-only tasks included), `--save-json`, `--project`/project folders and the history index (skipped with `index_dirty` when its root would fall outside), `mesh prepare-print` outputs and their copied materials — checked on real paths before anything, even a directory, is created. The boundary is frozen when the command starts (real path and directory identity): a workspace or project replaced by a symlink while a request is in flight is refused, never followed |
|
|
472
|
-
| `--no-update-check` | Skip the background npm version check in this process |
|
|
473
|
-
| `-v, --verbose` | Debug logging to stderr |
|
|
474
|
-
| `--log-level <level>` | `debug \| info \| warn \| error \| silent` |
|
|
475
|
-
|
|
476
|
-
## Exit codes
|
|
477
|
-
|
|
478
|
-
| Code | Meaning |
|
|
479
|
-
|------|---------|
|
|
480
|
-
| 0 | success (including `get` of any task status, empty lists, local checks that pass) |
|
|
481
|
-
| 1 | task ended FAILED/CANCELED while waiting, or an unclassified error |
|
|
482
|
-
| 2 | usage (flag parse error, conflicting or missing arguments) |
|
|
483
|
-
| 3 | auth (`401`, no usable credential) |
|
|
484
|
-
| 4 | validation (`400`, `422`, locally rejected payload) |
|
|
485
|
-
| 5 | not found (`404`; the cause is not guessed) |
|
|
486
|
-
| 6 | rate limit (`429`) |
|
|
487
|
-
| 7 | network (read failures, stream disconnects) |
|
|
488
|
-
| 8 | timed out waiting for or streaming a task (the task keeps running) |
|
|
489
|
-
| 9 | credit exhausted (`402`) |
|
|
490
|
-
| 10 | submission unknown — a create was sent but its outcome could not be confirmed |
|
|
491
|
-
| 11 | local I/O — refused overwrite, path outside the authorised root, journal/project write failure |
|
|
492
|
-
| 12 | check failed (`inspect faces` over the limit) |
|
|
493
|
-
| 13 | check unknown (`inspect faces` without a usable face count) |
|
|
494
|
-
| 130 | interrupted (Ctrl-C); nothing was deleted server-side |
|
|
495
|
-
|
|
496
|
-
## Environment variables
|
|
497
|
-
|
|
498
|
-
| Variable | Default |
|
|
499
|
-
|---|---|
|
|
500
|
-
| `MESHY_API_KEY` | — (required unless a profile is stored or `--api-key-file` is given) |
|
|
501
|
-
| `MESHY_BASE_URL_V1` | `https://api.meshy.ai/openapi/v1` |
|
|
502
|
-
| `MESHY_BASE_URL_V2` | `https://api.meshy.ai/openapi/v2` |
|
|
503
|
-
| `MESHY_BASE_URL_CREATIVE_LAB` | derived from the v1 origin (`/openapi/creative-lab`) |
|
|
504
|
-
| `MESHY_OAUTH_AUTHORIZE_URL` | `https://www.meshy.ai/oauth/authorize` — override for staging/testing |
|
|
505
|
-
| `MESHY_CLI_NO_BROWSER` | unset — set to `1` to suppress browser open (URL still printed to stderr) |
|
|
506
|
-
| `MESHY_CONFIG_DIR` | `~/.config/meshy` (credentials, operation journal, update cache) |
|
|
507
|
-
| `MESHY_CONNECT_TIMEOUT_MS` | `10000` (read for compatibility; fetch has no separate connect timeout) |
|
|
508
|
-
| `MESHY_READ_TIMEOUT_MS` | `120000` — covers headers *and* body |
|
|
509
|
-
| `MESHY_POLL_INTERVAL_MS` | `3000` |
|
|
510
|
-
| `MESHY_LOG_LEVEL` | `warn` |
|
|
511
|
-
| `MESHY_CLI_NO_UPDATE_NOTIFIER` | unset — any non-empty value disables update checks; CI envs (`CI`, `GITHUB_ACTIONS`, `BUILD_NUMBER`, `RUN_ID`) auto-skip |
|
|
512
|
-
|
|
513
|
-
## Update notifications
|
|
514
|
-
|
|
515
|
-
meshy-cli checks the npm registry for a newer version at most once per 24 hours. The result is cached at `<MESHY_CONFIG_DIR>/update-state.json`. The refresh runs in a detached background process so it can never slow down or fail a command, and it never runs for local commands (`resources`, `project`, `inspect`, `mesh`, `slicer`, `doctor`, `download`, `animation-catalog`), for `make --dry-run`, or with `--no-update-check`.
|
|
516
|
-
|
|
517
|
-
When a newer version is available:
|
|
518
|
-
|
|
519
|
-
- **Legacy JSON object outputs** carry a top-level `_notice.update = { current, latest, message, command }` so agents can relay it to the user.
|
|
520
|
-
- **v1 envelopes are never decorated** — the six keys are the contract; humans get the hint on stderr.
|
|
521
|
-
- **ndjson arrays** (legacy) carry `_notice.update` on the **first line only**.
|
|
522
|
-
- **Humans on an interactive terminal** get a single line on stderr after the command output.
|
|
523
|
-
- **stdout is never polluted** — the notice never appears on stdout.
|
|
524
|
-
|
|
525
|
-
## Agent skills
|
|
526
|
-
|
|
527
|
-
The `skills/` directory contains markdown-based skills for AI coding agents
|
|
528
|
-
(Claude Code, etc.):
|
|
529
|
-
|
|
530
|
-
- [`skills/meshy-cli`](skills/meshy-cli/SKILL.md) — a single skill covering
|
|
531
|
-
setup, `make`, the shared verb contract, the v1 envelope, the API constraints
|
|
532
|
-
that produce failed tasks when ignored, the local helpers, and the exit-code table.
|
|
533
|
-
|
|
534
|
-
It is deliberately short. A skill is loaded into an agent's context on every
|
|
535
|
-
invocation, so length is a running cost; anything an agent can look up on
|
|
536
|
-
demand (`meshy resources`, `meshy <resource> --help`,
|
|
537
|
-
<https://docs.meshy.ai/en/api/>) is linked rather than copied.
|
|
538
|
-
|
|
539
|
-
## Skill-parity documentation
|
|
540
|
-
|
|
541
|
-
`docs/skill-parity/` records how this release covers the execution capabilities
|
|
542
|
-
of the Meshy Skills without Python: the frozen baseline, the endpoint contracts,
|
|
543
|
-
the capability matrix, design decisions, migration notes with every intentional
|
|
544
|
-
difference, and the verification record.
|
|
545
|
-
|
|
546
|
-
## Project layout
|
|
547
|
-
|
|
548
|
-
```
|
|
549
|
-
meshy-cli/
|
|
550
|
-
├── src/
|
|
551
|
-
│ ├── index.ts # CLI entry: update-check policy, SIGINT, unified error exit
|
|
552
|
-
│ ├── root.ts # root command + global flag wiring
|
|
553
|
-
│ ├── cmd/ # make, auth, balance, resources, api, one file per endpoint,
|
|
554
|
-
│ │ # uv-unwrap, creative-lab, animation-catalog, showcases,
|
|
555
|
-
│ │ # download, project, inspect, mesh, slicer, doctor
|
|
556
|
-
│ ├── client/
|
|
557
|
-
│ │ ├── resource-registry.ts # every resource: path, family, verbs, billing, media fields
|
|
558
|
-
│ │ ├── transport.ts # per-family HTTP transport (auth scope, deadlines, redirects)
|
|
559
|
-
│ │ ├── endpoints/ # TaskEndpoint + balance / catalog / showcases
|
|
560
|
-
│ │ └── types.ts # Zod task schemas
|
|
561
|
-
│ └── internal/
|
|
562
|
-
│ ├── result.ts / errors.ts # v1 envelope, error codes, exit codes
|
|
563
|
-
│ ├── task-command.ts # create/get/list/wait/stream/delete factory
|
|
564
|
-
│ ├── operation-store.ts # submission journal (single POST, unknown outcomes)
|
|
565
|
-
│ ├── stream.ts / poll.ts # SSE parser + cancellable polling
|
|
566
|
-
│ ├── artifacts.ts / download.ts # asset keys, safe downloads, legacy -o
|
|
567
|
-
│ ├── project-store.ts # meshy_output metadata + history
|
|
568
|
-
│ ├── inspect.ts / obj-transform.ts / slicers.ts / doctor.ts
|
|
569
|
-
│ ├── config.ts / runtime.ts / env-file.ts / credentials.ts / oauth.ts
|
|
570
|
-
│ └── atomic-file.ts / paths.ts / lock.ts
|
|
571
|
-
├── tests/ # node:test unit, contract and black-box tests
|
|
572
|
-
├── skills/ # agent-facing skill (published)
|
|
573
|
-
├── docs/skill-parity/ # baseline, contracts, matrix, decisions, verification
|
|
574
|
-
├── package.json
|
|
575
|
-
└── README.md
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
## Design notes
|
|
579
|
-
|
|
580
|
-
- **Two layers, one of them opinion-free.** `make` chains endpoints; the
|
|
581
|
-
resource commands expose them one at a time. `make` picks its chain from the
|
|
582
|
-
input type alone and stops there.
|
|
583
|
-
- **Plan first, then spend.** `make` computes the whole chain before creating
|
|
584
|
-
anything, so `--dry-run` and a real run share one code path and one estimate.
|
|
585
|
-
- **One POST, journaled.** Every billable create is recorded before it is sent;
|
|
586
|
-
a lost answer is reported as unknown, never re-sent.
|
|
587
|
-
- **One registry.** `src/client/resource-registry.ts` is the only place a path,
|
|
588
|
-
API family, verb set or media field is declared; commands, the `resources`
|
|
589
|
-
index and the transport all read from it.
|
|
590
|
-
- **Credentials have a scope.** The API credential goes to the API origins it
|
|
591
|
-
was resolved for and nowhere else — not to asset hosts, not to the public
|
|
592
|
-
catalog, not across redirects.
|
|
593
|
-
- **`--data` escape hatch.** Every `create` accepts a raw JSON object (or
|
|
594
|
-
`@file.json`) that merges with structured flags (flags win, explicit `false`
|
|
595
|
-
and `0` survive).
|
|
596
|
-
- **Stdout is reserved for command output.** Logs, progress and errors' prose go
|
|
597
|
-
to stderr so pipes (`| jq`, `-o file`) stay clean.
|
|
82
|
+
meshy text-to-3d create --mode preview --prompt "a cactus" --async --output-schema v1 --format json \
|
|
83
|
+
| jq -r .result.submission.task_id
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Exit codes are stable (`3` auth, `8` timed out, `10` submission unknown, …), and
|
|
87
|
+
a create is sent exactly once, never retried behind your back. The envelope,
|
|
88
|
+
the create/wait/stream semantics and the full exit-code table are in
|
|
89
|
+
[docs/scripting.md](https://github.com/meshy-dev/meshy-cli/blob/main/docs/scripting.md).
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
- [Using meshy-cli](https://github.com/meshy-dev/meshy-cli/blob/main/docs/usage.md)
|
|
94
|
+
— auth in depth, `make`, every resource, downloads, projects, printing
|
|
95
|
+
helpers, media inputs, what the terminal shows, global flags, environment
|
|
96
|
+
variables
|
|
97
|
+
- [Scripts and agents](https://github.com/meshy-dev/meshy-cli/blob/main/docs/scripting.md)
|
|
98
|
+
— the v1 envelope, create / wait / stream guarantees, exit codes, the agent skill
|
|
99
|
+
- [Developing](https://github.com/meshy-dev/meshy-cli/blob/main/docs/development.md)
|
|
100
|
+
— building from source, project layout, design notes
|
|
101
|
+
- [Meshy API reference](https://docs.meshy.ai/en/api/) — parameters and credit costs
|
|
598
102
|
|
|
599
103
|
## License
|
|
600
104
|
|