luxin-cli 0.0.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.md ADDED
@@ -0,0 +1,1985 @@
1
+ # Luxin CLI Contract
2
+
3
+ Status: preview hosted-product contract.
4
+
5
+ The `luxin` thin CLI/client gives agents a stable way to call the hosted Luxin service, parse JSON responses, receive artifacts, and leave feedback.
6
+
7
+ Public contract URLs:
8
+
9
+ - `https://luxin.sh`
10
+ - `https://luxin.sh/skill.md`
11
+ - `https://luxin.sh/llms.txt`
12
+ - `https://luxin.sh/cli.md`
13
+ - `https://api.luxin.sh`
14
+
15
+ ## Global Rules
16
+
17
+ - Every command that agents use must support `--json`.
18
+ - JSON is the default public CLI output. `--json` is accepted for
19
+ compatibility and explicitness, but fresh agents do not need to add it to
20
+ every command.
21
+ - JSON output must use the standard envelope from
22
+ `https://luxin.sh/llms.txt`.
23
+ - Commands must have deterministic exit codes.
24
+ - Commands must emit service telemetry unless running in a documented no-telemetry test mode.
25
+ - Commands must not print secrets after initial creation.
26
+ - File-writing commands must avoid overwriting inputs unless `--overwrite` is explicit.
27
+ - Expensive commands must expose quota, claim, cost, and budget guard failures clearly.
28
+ - Public feedback commands submit to hosted product memory by default.
29
+
30
+ ## Exit Codes
31
+
32
+ | Code | Meaning |
33
+ | ---- | -------------------------------------- |
34
+ | 0 | Success |
35
+ | 1 | Generic failure |
36
+ | 2 | Invalid arguments |
37
+ | 3 | Auth required or invalid token |
38
+ | 4 | Capability denied |
39
+ | 5 | Quota exceeded |
40
+ | 6 | Content policy denied |
41
+ | 7 | Provider failure |
42
+ | 8 | Timeout |
43
+ | 9 | Filesystem or artifact storage failure |
44
+
45
+ ## Commands
46
+
47
+ ### `luxin doctor`
48
+
49
+ Checks thin CLI/client health, hosted service reachability, auth state, local output permissions, and telemetry status.
50
+
51
+ ```bash
52
+ luxin doctor --json
53
+ ```
54
+
55
+ `doctor` also reports `data.in_flight`, the local live-spend recovery
56
+ breadcrumbs under the public CLI config directory. Outstanding entries include
57
+ the original operation, idempotency key, age/TTL state, sweep eligibility, and a
58
+ copy-runnable `recover_command`. Re-run the recovery command first when the
59
+ original create/edit result still matters. Treat those idempotency keys and
60
+ recovery commands as agent-internal operational data during normal progress
61
+ updates; surface them to a human only when recovery needs a decision, handoff,
62
+ or requested diagnostic detail.
63
+
64
+ Use `luxin doctor --sweep-in-flight --json` to remove only
65
+ sweep-eligible stale breadcrumbs after the long grace window. Plain `doctor`
66
+ never deletes recovery breadcrumbs.
67
+
68
+ ### `luxin trust`
69
+
70
+ Returns a no-auth, no-spend evidence packet for tool selection and package
71
+ provenance checks.
72
+
73
+ ```bash
74
+ luxin trust --json
75
+ ```
76
+
77
+ The packet uses `schema: "image-skill.trust-packet.v0"` and reports the public
78
+ CLI version, npm metadata status, public repo mapping when inferable, hosted
79
+ contract document hashes, hosted `/healthz`, `/v1/models` availability, safe
80
+ copyable commands, proof URL placeholders, and redaction guarantees.
81
+
82
+ Use `trust` when deciding whether Luxin is current and honest enough to
83
+ select. It is not a required setup step before the first image; the canonical
84
+ fresh-agent creative entrypoint remains `luxin create --guide`.
85
+ Agents may also use modality-first aliases when that is the natural wording:
86
+ `luxin image create --guide`, `luxin video create --guide`,
87
+ `luxin audio create --guide`, and `luxin 3d create --guide` all
88
+ route into the same `create --guide` flow, with video/audio/3D intent hints
89
+ added only when the agent did not already provide `--intent`.
90
+
91
+ If package metadata, hosted docs, API health, or model availability cannot be
92
+ verified, the command still returns a packet with explicit `unreachable`,
93
+ `not_available_yet`, `inspect_only`, or `stale_or_mismatched` states rather
94
+ than omitting the field.
95
+
96
+ ### `luxin signup --agent`
97
+
98
+ Bootstraps restricted agent access. Signup is anonymous by default: no contact
99
+ inbox is required to get a restricted token.
100
+
101
+ ```bash
102
+ luxin signup --agent \
103
+ --agent-name creative-agent \
104
+ --runtime codex \
105
+ --discovery-source cli-md \
106
+ --json
107
+ ```
108
+
109
+ Hosted signup saves the restricted `isk_r_` token to the public CLI config by
110
+ default with `0600` permissions, so later hosted commands can authenticate from
111
+ config without repeating signup or carrying a raw token through prompts. Set
112
+ `LUXIN_CONFIG_PATH` first when the default config home may be read-only.
113
+ Successful default signup reports `data.auth_handoff.status` as
114
+ `saved_config_ready`, keeps `data.token` null, and should not require any
115
+ token-copy step.
116
+ The raw token is returned only when `--show-token` is set, and only once. Use
117
+ `--show-token --no-save` when the agent runtime has a separate secret store and
118
+ does not want local config. Do not paste tokens into prompts, logs, issue text,
119
+ or feedback.
120
+
121
+ `--agent-contact` is an email-shaped durable contact inbox and it is optional
122
+ at signup: provide it when a durable inbox already exists, or attach one later
123
+ with `luxin claim request --contact INBOX --json` when funding or
124
+ durability makes it worth having. Use an agent-owned inbox when available;
125
+ otherwise use an operator, team, or sponsor inbox that can receive future
126
+ claim, billing, or abuse notices. Never invent an inbox or borrow an unrelated
127
+ human email just to fill the flag — omit it instead.
128
+ `example.invalid` addresses are only appropriate inside documented harness or
129
+ proof runs. `--human-email` remains accepted as a compatibility alias for
130
+ `--agent-contact`.
131
+
132
+ Anonymous signups mint a fresh agent identity on every call, so re-running
133
+ signup without a contact creates a new agent instead of returning the existing
134
+ one; rely on the saved config to reuse the identity you already have.
135
+
136
+ `--discovery-source SLUG` (or the `IMAGE_SKILL_DISCOVERY_SOURCE` environment
137
+ variable; the flag wins) optionally records where you discovered Luxin —
138
+ a short channel slug such as `clawhub`, `skills-sh`, or `npm` (lowercase
139
+ letters/digits plus `.`/`_`/`-`, max 64 chars). Keep `cli-md` when this
140
+ command reference brought you here. It is self-reported, first-touch (a later
141
+ re-signup never relabels it), and never required: omit it when you do not know
142
+ the channel rather than guessing.
143
+
144
+ ### `luxin claim request`
145
+
146
+ Attaches an email-shaped durable contact inbox to the authenticated agent —
147
+ the on-demand identity upgrade after an anonymous signup. Use it when funding
148
+ or durability makes a reachable contact worth having (billing, abuse, and
149
+ recovery notices).
150
+
151
+ ```bash
152
+ luxin claim request \
153
+ --contact agent-inbox@example.com \
154
+ --json
155
+ ```
156
+
157
+ Re-running with the same contact is idempotent (`data.state` is `unchanged`);
158
+ a different contact replaces the previous one (`data.state` is `attached`).
159
+ Attaching a contact is not inbox-ownership verification: `data.claim_state`
160
+ stays `unclaimed` and `data.claim_request_state` reports `requested`. The
161
+ response echoes only a redacted form of the contact.
162
+
163
+ If the runtime has a separate secret store, it may provide the token to commands
164
+ as `IMAGE_SKILL_TOKEN`. Keep that value outside prompts, logs, issue text, and
165
+ feedback. Saved config, `IMAGE_SKILL_TOKEN`, and `--token-stdin` are all
166
+ accepted by hosted commands; config is the default fresh-agent path.
167
+
168
+ If the agent runtime can hand secrets to a command over stdin, avoid exporting
169
+ the token and use `--token-stdin` instead:
170
+
171
+ ```bash
172
+ printf '%s\n' "$IMAGE_SKILL_TOKEN" | luxin usage quota --token-stdin --json
173
+ ```
174
+
175
+ `--api-base-url` is an advanced preview/test override; production public agents
176
+ should omit it.
177
+
178
+ ### First Run Guide Loop
179
+
180
+ Use the no-spend guide first. It is the only required first command for a fresh
181
+ agent. It checks health, executable model availability, auth/quota when a token
182
+ already exists, and payment rails, then returns one primary
183
+ `data.next_command` plus machine-readable `data.next_command_copy_runnable`,
184
+ `data.next_command_missing_inputs`, `data.next_command_effect`,
185
+ `data.guide_warning`, `data.auth_ready`, `data.no_spend_evaluation`, and
186
+ `data.guide_recovery`. Guide mode does not create a signup, provider job,
187
+ dry-run job, payment object, credit debit, or asset.
188
+
189
+ ```bash
190
+ IMAGE_SKILL_DISCOVERY_SOURCE=cli-md luxin create --guide --prompt "a compact field camera on a stainless workbench"
191
+ ```
192
+
193
+ Read `data.stage` and `data.guide_warning`, run `data.next_command` only when
194
+ `data.next_command_copy_runnable` is `true` and
195
+ `data.guide_warning.next_command_safety` is safe for the current spend policy.
196
+ When `data.next_command_copy_runnable` is `false`, fill
197
+ `data.next_command_missing_inputs` first. Rerun the guide only after auth or
198
+ payment state changes. Do not run
199
+ `doctor`, `models list`, `signup`, `whoami`, `usage quota`, `create --dry-run`,
200
+ or payment commands as a setup checklist before the guide asks for them.
201
+ For no-doc recovery loops, prefer `data.guide_recovery`: it names the current
202
+ precondition (`precondition_code` / `precondition_message`), the safest
203
+ no-spend command and field to run (`no_spend_command_field` /
204
+ `no_spend_command`), the command to run after the precondition changes, and the
205
+ live command field that would spend if rerun (`live_create_command_field` or
206
+ `live_payment_command_field`). When `data.guide_recovery.double_spend_guard.required`
207
+ is `true`, do not rerun that live field after a partial or unknown failure
208
+ until `error.recovery`, `jobs`, `activity`, or payment status proves the next
209
+ step.
210
+
211
+ - `prompt_required`: fill `data.next_command_missing_inputs` with the real
212
+ prompt, then rerun `data.next_command`.
213
+ - `auth_required`: fill `data.next_command_missing_inputs` when present, run
214
+ `data.next_command`, then rerun guide once. Hosted signup saves auth to
215
+ config by default. If the runtime intentionally used
216
+ `--no-save --show-token`, store the returned token and use
217
+ `data.auth_handoff.rerun_guide.with_env` or
218
+ `data.auth_handoff.rerun_guide.with_stdin`. In this stage,
219
+ `data.auth_ready.ready` is `false`, and
220
+ `data.guide_warning.next_command_safety` is
221
+ `hosted_signup_no_spend_setup`.
222
+ - `quota_required`: fill `data.next_command_missing_inputs` when present, then
223
+ run `data.self_fund_next_command` to start the top-up.
224
+ It aliases `data.next_command` and is the first payment command, usually an
225
+ x402 or Stripe quote. First inspect
226
+ `data.self_fund_handoff.urgency`, `urgency_score`, and `urgency_reasons`; run
227
+ `data.self_fund_handoff.first_safe_command` for no-spend payment-method
228
+ inspection when you need rail state before opening a quote. If the guide
229
+ authenticated from env or stdin, prefer
230
+ `data.self_fund_handoff.auth.next_command.with_env` or
231
+ `data.self_fund_handoff.auth.next_command.with_stdin` so auth follows the
232
+ payment command. Then follow `data.self_fund_handoff.payment_commands.buy`
233
+ and `status`, and rerun `data.self_fund_handoff.after_next` once credits are
234
+ granted. If `data.self_fund_handoff.wallet_settlement` is non-null, pay the
235
+ exact amount in the returned `payable_instructions` field from a delegated
236
+ wallet before polling status; the handoff names the response fields and the
237
+ credential boundary. `data.guide_warning.next_command_safety` is
238
+ `live_money_payment_action`, and
239
+ `data.guide_warning.payment_top_up_path` summarizes the same path as
240
+ `data.checks.payments.preferred_method_summary.top_up_path`. Read that path
241
+ before the quote: `browserless_agent_self_fund` means a wallet-equipped agent
242
+ can complete the preferred live-money rail without a browser;
243
+ `human_payment_handoff` means the agent can create the payment attempt but a
244
+ human/browser step must complete before credits are granted.
245
+ - any stage: inspect `data.checks.quota.top_up`; when `recommended` is `true`,
246
+ it includes the recommendation reason, preferred browserless x402 method, and
247
+ `quote_command` plus copy-runnable quote/buy/status command templates from
248
+ `usage quota`. On quota/payment recovery errors, the same browserless
249
+ handoff is exposed at `error.recovery.top_up.quote_command`, and
250
+ `error.recovery.suggested_command` points at that direct quote when delegated
251
+ live-money quoting is allowed. Use `error.recovery.top_up.first_command` for
252
+ no-spend payment-method inspection when delegated spend authority is absent or
253
+ unclear.
254
+ - `ready_to_create`: `data.next_command` is a live media create. Its
255
+ `data.self_fund_preparation` is the pre-wall top-up affordance; when
256
+ `available` is true, it mirrors top-up `urgency`, `urgency_score`, and
257
+ `urgency_reasons`; when `recommended` is true, `quote_command` creates an
258
+ authenticated live-money quote/payment object without paying, settling a
259
+ wallet transfer, debiting credits, calling a provider, or writing media.
260
+ When that recommended quote is copy-runnable, `data.self_fund_next_command`
261
+ aliases it and `data.self_fund_next_command_label` uses a `pre_wall_...`
262
+ label such as `pre_wall_browserless_agent_payable_quote`, so agents can open
263
+ the top-up quote path before consuming their remaining free allowance. Only
264
+ follow later buy/status/wallet-settlement commands when delegated spend is
265
+ allowed. `data.next_command_effect.label` is
266
+ `live_media_create_credit_debit`, with
267
+ `provider_call`, `hosted_create`, `credit_debit`, and `media_write` all true.
268
+ `data.guide_warning.next_command_safety` is
269
+ `live_media_create_credit_debit`, `data.guide_warning.no_spend_safe` is
270
+ `false`, `data.guide_warning.spend_required` is `true`, and
271
+ `data.guide_warning.recommended_command_field` is
272
+ `recommended_no_spend_command`.
273
+ `data.auth_ready.ready` is `true`,
274
+ `data.auth_ready.next_command_requires_auth` is `true`, and
275
+ `data.auth_ready.next_command_auth_ready` is `true`; the returned
276
+ `data.next_command` can reuse the current saved config, env token, or stdin
277
+ token context without exposing a raw token.
278
+ `data.no_spend_evaluation.stop_here` is `true`,
279
+ `data.no_spend_evaluation.next_command_is_live_create` is `true`, and
280
+ `data.no_spend_evaluation.recommended_command_field` is
281
+ `recommended_no_spend_command`. Run `data.next_command` for the first bounded
282
+ create only when media spend is allowed. If you are in a no-spend evaluation
283
+ or only need proof that the path is ready, stop before `data.next_command` and
284
+ run `data.recommended_no_spend_command` instead; it aliases
285
+ `data.no_spend_next_command` and is the dry-run plan command. Its
286
+ `data.no_spend_next_command_effect.label` is
287
+ `dry_run_planned_job_no_provider_call_no_credit_debit_no_media_write`, with
288
+ `no_spend`, `hosted_create_dry_run`, `planned_job`, and `plan_receipt` true,
289
+ `activity_event: "job.planned"`, and provider call, credit debit, and media
290
+ write false. It may create a recoverable planned job/activity receipt, but no
291
+ provider execution, debit, downloadable asset, or media write. If the guide authenticated from
292
+ env or stdin, prefer
293
+ `data.auth_handoff.next_command.with_env` or
294
+ `data.auth_handoff.next_command.with_stdin` so auth follows the create.
295
+
296
+ Manual escape hatches are not prerequisites. Use them only when
297
+ `data.next_command` / `data.escape_hatches` asks, or when the task genuinely
298
+ needs deeper capability, quota, payment, or planning detail:
299
+
300
+ ```bash
301
+ luxin trust
302
+ luxin doctor
303
+ luxin models list
304
+ luxin models show openai.gpt-image-2
305
+ luxin whoami
306
+ luxin usage quota
307
+ luxin create --dry-run --prompt "a compact field camera on a stainless workbench"
308
+ ```
309
+
310
+ Use `--show-token --no-save` for hosted signup only when the runtime can
311
+ immediately store the raw token once outside local config. For later commands,
312
+ saved config is the default; `IMAGE_SKILL_TOKEN` and `--token-stdin` remain
313
+ available for runtimes with a separate secret store.
314
+ `create --guide` also returns `data.auth_handoff` with copy-safe env/stdin
315
+ templates when auth is required or when the returned create command needs the
316
+ same auth context.
317
+
318
+ ### Local Config And Install
319
+
320
+ Prefer package execution in fresh agent sandboxes:
321
+
322
+ ```bash
323
+ npm_config_update_notifier=false npx -y luxin-cli@latest create --guide --prompt "a compact field camera on a stainless workbench" --json
324
+ ```
325
+
326
+ Global install is optional, not the primary path. If `npm install -g luxin-cli`
327
+ or `npx luxin-cli@latest ...` hits prefix/cache `EACCES`, retry with writable
328
+ package-manager paths instead of cloning private source:
329
+
330
+ ```bash
331
+ export npm_config_cache="${npm_config_cache:-$PWD/.npm-cache}"
332
+ export npm_config_prefix="${npm_config_prefix:-$PWD/.npm-global}"
333
+ export PATH="$npm_config_prefix/bin:$PATH"
334
+ npm_config_update_notifier=false npx -y luxin-cli@latest create --guide --prompt "a compact field camera on a stainless workbench" --json
335
+ ```
336
+
337
+ For `npx skills add ... -g -a codex` installs, the writable target is Codex
338
+ agent home rather than the npm prefix. If the Codex/global skill target is
339
+ read-only or cannot create its default directory, keep the tracked slug install
340
+ and point agent skill state at a writable workspace home. The skills.sh Codex
341
+ adapter writes to `$HOME/.agents`; `CODEX_HOME` keeps Codex profile state on the
342
+ same writable path:
343
+
344
+ ```bash
345
+ export HOME="$PWD/.agent-home"
346
+ export CODEX_HOME="$HOME/.codex"
347
+ mkdir -p "$HOME" "$CODEX_HOME"
348
+ npx skills add danielgwilson/luxin --full-depth --skill luxin -g -a codex -y
349
+ ```
350
+
351
+ Hosted signup saves auth state to the public CLI config by default. If the
352
+ runtime needs a writable compatibility config path, set
353
+ `LUXIN_CONFIG_PATH` before `signup`:
354
+
355
+ ```bash
356
+ export LUXIN_CONFIG_PATH="$PWD/.luxin/config.json"
357
+ # legacy name IMAGE_SKILL_CONFIG_PATH remains honored
358
+ npm_config_update_notifier=false npx -y luxin-cli@latest signup --agent \
359
+ --agent-name creative-agent \
360
+ --runtime codex \
361
+ --json
362
+ ```
363
+
364
+ Config write failures return `PUBLIC_CLI_CONFIG_WRITE_FAILED` with a structured
365
+ `error.recovery.suggested_command`. Agents should follow that recovery field,
366
+ then rerun `create --guide` for the requested creative flow.
367
+ When `create --guide` reaches `auth_required`, it probes the configured auth
368
+ path first. If local config cannot be written, `data.next_command` prefixes the
369
+ normal saved-config signup with
370
+ `LUXIN_CONFIG_PATH="$PWD/.luxin/config.json"`, so the first recovery
371
+ step still saves auth locally without exposing the one-time token.
372
+ `--show-token --no-save` and `data.auth_handoff.rerun_guide.with_stdin` remain
373
+ structured fallback paths for runtimes that intentionally use a separate secret
374
+ store.
375
+
376
+ ### `luxin whoami`
377
+
378
+ Shows current actor, organization, claim state, token class, and grants.
379
+ The JSON includes `session_origin` so a fresh agent can tell whether it is
380
+ unauthenticated, loaded a saved config, created the token in this process, or
381
+ is using hosted-session auth. `token_created_at` is the active token creation
382
+ timestamp when Luxin can prove it, otherwise `null`.
383
+
384
+ ```bash
385
+ luxin whoami --json
386
+ ```
387
+
388
+ Minimum success data:
389
+
390
+ ```json
391
+ {
392
+ "authenticated": true,
393
+ "session_origin": "loaded_from_config",
394
+ "token_status": "active",
395
+ "token_created_at": "2026-05-08T12:00:00.000Z"
396
+ }
397
+ ```
398
+
399
+ ### `luxin usage quota`
400
+
401
+ Canonical pre-spend check. Shows remaining credits, job limits, model limits,
402
+ and reset windows before create/edit.
403
+
404
+ The starter preview has 50 lifetime credits and a 50-job UTC-day compatibility
405
+ cap. Funded identities have no daily job cap: their available prepaid credits
406
+ and atomic credit reservations are the spend boundary. For funded identities,
407
+ the optional `daily_jobs` object is omitted from the quota response.
408
+
409
+ ```bash
410
+ luxin usage quota --json
411
+ ```
412
+
413
+ `luxin quota --json` remains a compatibility alias.
414
+
415
+ Hosted API equivalent:
416
+
417
+ ```bash
418
+ curl -sS https://api.luxin.sh/v1/quota \
419
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN"
420
+ ```
421
+
422
+ ### `luxin credits methods`
423
+
424
+ Machine-readable payment rail discovery. Use this before quoting or buying so
425
+ agents can tell which rails are available, whether live money can move, whether
426
+ browser/human action is required, and which command to try next.
427
+
428
+ ```bash
429
+ luxin credits methods --json
430
+ ```
431
+
432
+ Minimum success data shape:
433
+
434
+ ```json
435
+ {
436
+ "contract_version": "image-skill.payment-methods.v1",
437
+ "credit_unit_cents": 1,
438
+ "currency": "USD",
439
+ "quote_endpoint": "/v1/credit-quotes",
440
+ "packs_endpoint": "/v1/credit-packs",
441
+ "status_endpoint": "/v1/credit-purchases/status",
442
+ "next_actions": {
443
+ "recommended_quote": {
444
+ "purpose": "quote_credit_top_up",
445
+ "recommendation_reason": "browserless_agent_self_fund",
446
+ "method_id": "stripe_x402.exact.usdc",
447
+ "pack_id": "starter-500",
448
+ "command": "luxin credits quote --pack starter-500 --payment-method stripe_x402.exact.usdc --json",
449
+ "quote_command_copy_runnable": true,
450
+ "buy_command": "luxin credits buy --provider stripe_x402 --quote-id QUOTE_ID --idempotency-key KEY --json",
451
+ "status_command": "luxin credits status --payment-attempt-id PAYMENT_ATTEMPT_ID --json",
452
+ "requires_auth": true,
453
+ "live_money": true,
454
+ "requires_browser": false,
455
+ "agent_settleable": true,
456
+ "command_effect": {
457
+ "label": "live_money_quote_no_charge",
458
+ "no_spend": true,
459
+ "payment_object": true,
460
+ "credit_debit": false,
461
+ "media_write": false
462
+ }
463
+ }
464
+ },
465
+ "methods": [
466
+ {
467
+ "method_id": "stripe_checkout",
468
+ "status": "available",
469
+ "available": true,
470
+ "quoteable": true,
471
+ "purchasable": true,
472
+ "live_money": true,
473
+ "buyer_modes": ["hybrid", "human_only"],
474
+ "requires_browser": true,
475
+ "agent_initiated": true,
476
+ "agent_settleable": false,
477
+ "settlement_blocker": "requires human browser checkout completion",
478
+ "default_pack_id": "starter-500",
479
+ "purchase_endpoint": "/v1/credit-purchases/stripe-checkout-sessions"
480
+ },
481
+ {
482
+ "method_id": "stripe_x402.exact.usdc",
483
+ "status": "available",
484
+ "available": true,
485
+ "quoteable": true,
486
+ "purchasable": true,
487
+ "live_money": true,
488
+ "buyer_modes": ["agent_only", "hybrid"],
489
+ "requires_browser": false,
490
+ "agent_initiated": true,
491
+ "agent_settleable": true,
492
+ "settlement_blocker": null,
493
+ "default_pack_id": "starter-500",
494
+ "purchase_endpoint": "/v1/credit-purchases/stripe-x402-deposits"
495
+ }
496
+ ]
497
+ }
498
+ ```
499
+
500
+ Public payment discovery is intentionally action-first. Limited-rollout rails
501
+ may be returned with `available:false`, `quoteable:false`, `purchasable:false`,
502
+ and a non-null `unavailable_reason` so headless agents can understand the path
503
+ without trying it. Use a method only when it is returned with `available:true`,
504
+ `quoteable:true`, and `purchasable:true`. When
505
+ `next_actions.recommended_quote` is present, prefer its `command` as the next
506
+ authenticated quote step; it creates a live-money payment object but does not
507
+ move money, grant credits, debit credits, call a provider, or write media.
508
+
509
+ Hosted API equivalent:
510
+
511
+ ```bash
512
+ curl -sS https://api.luxin.sh/v1/payment-methods
513
+ ```
514
+
515
+ ### `luxin credits packs list`
516
+
517
+ Lists the recommended Luxin credit packs. Packs are the default
518
+ live-money buying UX because agents get obvious starter choices and avoid tiny
519
+ fee traps. Use the payment method catalog to choose the rail:
520
+ `stripe_checkout` when a human sponsor can complete Checkout, or
521
+ `stripe_x402.exact.usdc` when a wallet-equipped agent can settle a browserless
522
+ live crypto deposit attempt from returned pay-to instructions.
523
+ Exact custom quotes are still supported when an agent already knows the
524
+ required credit budget.
525
+
526
+ ```bash
527
+ luxin credits packs list --json
528
+ ```
529
+
530
+ Minimum success data:
531
+
532
+ ```json
533
+ {
534
+ "credit_unit_cents": 1,
535
+ "credit_unit_usd": 0.01,
536
+ "currency": "USD",
537
+ "default_pack_id": "starter-500",
538
+ "packs": [
539
+ {
540
+ "pack_id": "starter-500",
541
+ "name": "Starter",
542
+ "display_name": "Starter (500 credits)",
543
+ "credits": 500,
544
+ "amount_cents": 500,
545
+ "amount_usd": "5.00",
546
+ "price_usd": "5.00",
547
+ "currency": "USD"
548
+ }
549
+ ],
550
+ "custom_quotes": {
551
+ "supported": true,
552
+ "min_credits": 1,
553
+ "max_credits": 5000
554
+ }
555
+ }
556
+ ```
557
+
558
+ Hosted API equivalent:
559
+
560
+ ```bash
561
+ curl -sS https://api.luxin.sh/v1/credit-packs
562
+ ```
563
+
564
+ ### `luxin credits quote`
565
+
566
+ Requests a bounded credit quote from the hosted service. Public top-ups use the
567
+ payment method returned by `credits methods --json`: `stripe_checkout` for the
568
+ human Checkout path, or `stripe_x402.exact.usdc` for a browserless
569
+ action-required deposit attempt. A quote never grants credits.
570
+ One Luxin credit is a stable user-facing value unit worth `$0.01`.
571
+ Creative operations can consume more than one credit based on the selected
572
+ model's provider cost and Luxin's margin policy; inspect
573
+ `models show MODEL_ID --json` and operation `cost.credit_pricing` for the exact
574
+ debit before spending.
575
+
576
+ ```bash
577
+ luxin credits quote --credits 10 --payment-method stripe_x402.exact.usdc --json
578
+ ```
579
+
580
+ Always pass the payment method from `credits methods --json`; the public CLI
581
+ does not infer one. For retry-stable automation, provide an explicit non-secret
582
+ idempotency key:
583
+
584
+ ```bash
585
+ luxin credits quote \
586
+ --credits 10 \
587
+ --payment-method stripe_x402.exact.usdc \
588
+ --idempotency-key quote-run-001 \
589
+ --json
590
+ ```
591
+
592
+ Idempotency keys are scoped to the current hosted agent identity and exact
593
+ quote request. Reusing a key with different credits, pack, or payment method
594
+ returns a structured `error.recovery.suggested_command` with a fresh
595
+ idempotency key for the attempted quote terms.
596
+
597
+ For Stripe Checkout terms, prefer a named pack:
598
+
599
+ ```bash
600
+ luxin credits quote \
601
+ --pack starter-500 \
602
+ --payment-method stripe_checkout \
603
+ --idempotency-key stripe-pack-quote-run-001 \
604
+ --json
605
+ ```
606
+
607
+ For the browserless agent x402 rail, quote the exact method id returned by
608
+ `credits methods --json`:
609
+
610
+ ```bash
611
+ luxin credits quote \
612
+ --pack starter-500 \
613
+ --payment-method stripe_x402.exact.usdc \
614
+ --idempotency-key agent-x402-quote-run-001 \
615
+ --json
616
+ ```
617
+
618
+ For exact custom terms, keep the same rail choice. Use
619
+ `stripe_x402.exact.usdc` for an agent-settleable browserless rail, or use
620
+ `stripe_checkout` only for a human Checkout fallback:
621
+
622
+ ```bash
623
+ luxin credits quote \
624
+ --credits 137 \
625
+ --payment-method stripe_checkout \
626
+ --idempotency-key exact-quote-run-001 \
627
+ --json
628
+ ```
629
+
630
+ Minimum success data:
631
+
632
+ ```json
633
+ {
634
+ "quote_id": "quote_...",
635
+ "state": "created",
636
+ "credits": 10,
637
+ "price_amount_cents": 10,
638
+ "currency": "USD",
639
+ "expires_at": "2026-05-08T20:00:00.000Z",
640
+ "accepted_payment_method": "stripe_checkout",
641
+ "idempotency_key": "quote-run-001",
642
+ "pack_id": null,
643
+ "pack": null,
644
+ "live_money": true,
645
+ "next_actions": {
646
+ "recommended_buy": {
647
+ "purpose": "complete_credit_top_up",
648
+ "recommendation_reason": "human_checkout_handoff",
649
+ "quote_id": "quote_...",
650
+ "method_id": "stripe_checkout",
651
+ "provider": "stripe",
652
+ "command": "luxin credits buy --provider stripe --quote-id quote_... --idempotency-key purchase:quote_... --json",
653
+ "buy_command_copy_runnable": true,
654
+ "purchase_idempotency_key": "purchase:quote_...",
655
+ "status_command": "luxin credits status --quote-id quote_... --json",
656
+ "status_command_copy_runnable": true,
657
+ "status_command_after_payment": "luxin credits status --payment-attempt-id PAYMENT_ATTEMPT_ID --json",
658
+ "status_command_after_payment_copy_runnable": false,
659
+ "requires_auth": true,
660
+ "live_money": true,
661
+ "requires_browser": true,
662
+ "agent_settleable": false,
663
+ "human_handoff_required": true,
664
+ "command_effect": {
665
+ "label": "live_money_payment_attempt_requires_completion",
666
+ "no_spend": false,
667
+ "payment_attempt": true,
668
+ "credit_debit": false,
669
+ "media_write": false,
670
+ "wallet_settlement": false
671
+ }
672
+ }
673
+ }
674
+ }
675
+ ```
676
+
677
+ For x402 quotes, `accepted_payment_method` is
678
+ `"stripe_x402.exact.usdc"`. The quote does not grant credits or include pay-to
679
+ instructions; `data.next_actions.recommended_buy.command` carries the returned
680
+ `quote_id` and a stable non-secret purchase idempotency key for the
681
+ action-required deposit attempt. Run it only when delegated spend is allowed.
682
+ Use `data.next_actions.recommended_buy.status_command` to inspect the quote or
683
+ payment state by `quote_id`; after buy returns a `payment_attempt_id`, prefer
684
+ `status_command_after_payment`.
685
+
686
+ When `credits status --quote-id quote_... --json` sees an open
687
+ `stripe_x402.exact.usdc` or `stripe_checkout` quote, it repeats the exact
688
+ `data.next_actions.recommended_buy` command with the real `quote_id` and
689
+ `purchase:quote_...` idempotency key so agents do not need to reconstruct the
690
+ buy step from placeholders.
691
+
692
+ Hosted API equivalent:
693
+
694
+ ```bash
695
+ curl -sS https://api.luxin.sh/v1/credit-quotes \
696
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN" \
697
+ -H "content-type: application/json" \
698
+ -d '{"pack_id":"starter-500","payment_method":"stripe_x402.exact.usdc","idempotency_key":"agent-x402-quote-run-001"}'
699
+ ```
700
+
701
+ ### `luxin credits buy`
702
+
703
+ Creates a payment action for a previously returned quote. Choose the provider
704
+ that matches the quote's `accepted_payment_method`.
705
+
706
+ For a `stripe_x402.exact.usdc` quote, `--provider stripe_x402` creates a
707
+ browserless action-required USDC deposit attempt. When the response includes
708
+ `stripe_x402.payable_instructions`, a wallet-equipped agent may pay the exact
709
+ USDC amount to `deposit_address` on Base without using a browser. The response
710
+ is live money when `live_money:true`. Credits are granted only after verified
711
+ settlement and webhook fulfillment succeeds. Deposit challenge creation itself
712
+ must not mutate credit balances. Stay within the delegated cap and never pass
713
+ wallet private keys, seed phrases, x402 payment headers, deposit client
714
+ secrets, card data, Stripe secrets, or provider receipts to Luxin.
715
+ When `create --guide` enters `quota_required` for this rail, it returns
716
+ `data.self_fund_handoff.wallet_settlement` with the buy/status response fields
717
+ to inspect, plus `data.self_fund_handoff.first_safe_command` for no-spend rail
718
+ inspection before quote/buy: `data.stripe_x402.payable_instructions` after
719
+ `credits buy`, or
720
+ `data.payment_attempt.stripe_x402.payable_instructions` after `credits status`.
721
+
722
+ ```bash
723
+ luxin credits buy \
724
+ --provider stripe_x402 \
725
+ --quote-id quote_... \
726
+ --idempotency-key agent-x402-buy-run-001 \
727
+ --json
728
+ ```
729
+
730
+ Minimum x402 action-required data:
731
+
732
+ ```json
733
+ {
734
+ "state": "action_required",
735
+ "quote_id": "quote_...",
736
+ "payment_attempt_id": "payatt_...",
737
+ "provider": "stripe",
738
+ "accepted_payment_method": "stripe_x402.exact.usdc",
739
+ "credits": 500,
740
+ "amount_cents": 500,
741
+ "currency": "USD",
742
+ "live_money": true,
743
+ "stripe_x402": {
744
+ "method_id": "stripe_x402.exact.usdc",
745
+ "scheme": "exact",
746
+ "network": "base",
747
+ "token_currency": "usdc",
748
+ "deposit_address_present": true,
749
+ "payable_instructions": {
750
+ "kind": "stripe_crypto_deposit",
751
+ "network": "base",
752
+ "token_currency": "usdc",
753
+ "token_decimals": 6,
754
+ "token_amount": "5.00",
755
+ "token_amount_atomic": "5000000",
756
+ "amount_cents": 500,
757
+ "amount_usd": "5.00",
758
+ "deposit_address": "0x...",
759
+ "token_contract_address": "0x...",
760
+ "supported_token_currencies": ["usdc"],
761
+ "expires_at": "2026-05-08T20:00:00.000Z",
762
+ "exact_amount_required": true
763
+ },
764
+ "redacted": {
765
+ "payment_intent_id": "[redacted-stripe-payment-intent]",
766
+ "deposit_address": "[redacted-stripe-crypto-deposit-address]",
767
+ "client_secret": "[redacted-stripe-client-secret]"
768
+ }
769
+ },
770
+ "next_actions": {
771
+ "recommended_settlement": {
772
+ "purpose": "settle_stripe_x402_credit_top_up",
773
+ "quote_id": "quote_...",
774
+ "payment_attempt_id": "payatt_...",
775
+ "method_id": "stripe_x402.exact.usdc",
776
+ "payable_instructions_path": "data.stripe_x402.payable_instructions",
777
+ "status_command": "luxin credits status --payment-attempt-id payatt_... --json",
778
+ "quota_command": "luxin usage quota --json",
779
+ "command_effect": {
780
+ "wallet_settlement": true,
781
+ "credit_debit": false,
782
+ "media_write": false
783
+ }
784
+ }
785
+ },
786
+ "next": {
787
+ "agent_action": "pay_stripe_crypto_deposit",
788
+ "suggested_commands": [
789
+ "luxin credits status --payment-attempt-id payatt_... --json"
790
+ ]
791
+ }
792
+ }
793
+ ```
794
+
795
+ For a `stripe_checkout` quote, `--provider stripe` creates a hosted Stripe
796
+ Checkout Session and returns an `action_required` response with
797
+ `checkout_handoff_url`.
798
+
799
+ Agents should present or open `checkout_handoff_url` for humans. It is a short
800
+ Luxin URL that redirects to Stripe Checkout and is safe to copy from
801
+ mobile terminals, SSH clients, and wrapped chat output. `checkout_compact_url`
802
+ is also copy-safe and equals the Luxin handoff when the hosted API can
803
+ provide one. `checkout_url` is the raw Stripe compatibility fallback only; do
804
+ not present it unless no handoff URL is available. Do not trim Stripe Checkout
805
+ URLs: the long `#...` fragment is required by Stripe Checkout in the browser.
806
+ Present any fallback Stripe URL in a fenced code block so terminal wrapping does
807
+ not corrupt it. Stripe-hosted Checkout may also show a promotion-code field for
808
+ operator-provided codes; agents should let the human enter those codes on
809
+ Stripe, never collect promo codes, card details, or wallet credentials in the
810
+ Luxin CLI.
811
+
812
+ ```bash
813
+ luxin credits buy \
814
+ --provider stripe \
815
+ --quote-id quote_... \
816
+ --idempotency-key stripe-buy-run-001 \
817
+ --json
818
+ ```
819
+
820
+ Minimum success data:
821
+
822
+ ```json
823
+ {
824
+ "state": "action_required",
825
+ "quote_id": "quote_...",
826
+ "payment_attempt_id": "payatt_...",
827
+ "provider": "stripe",
828
+ "accepted_payment_method": "stripe_checkout",
829
+ "checkout_session_id": "cs_...",
830
+ "checkout_handoff_url": "https://api.luxin.sh/pay/payatt_...",
831
+ "checkout_compact_url": "https://api.luxin.sh/pay/payatt_...",
832
+ "checkout_url": "https://checkout.stripe.com/c/pay/cs_...#fid...",
833
+ "credits": 500,
834
+ "amount_cents": 500,
835
+ "currency": "USD",
836
+ "live_money": true,
837
+ "next": {
838
+ "human_action": "open_checkout_url",
839
+ "checkout_handoff_url": "https://api.luxin.sh/pay/payatt_...",
840
+ "checkout_compact_url": "https://api.luxin.sh/pay/payatt_...",
841
+ "fallback_checkout_url": "https://checkout.stripe.com/c/pay/cs_...#fid...",
842
+ "after_payment": "open checkout_handoff_url or checkout_compact_url; use the full checkout_url only if no Luxin handoff URL is available, and preserve its Stripe # fragment. Then poll luxin credits status --payment-attempt-id PAYMENT_ATTEMPT_ID --json or luxin usage quota --json; credits are granted only after verified webhook fulfillment"
843
+ }
844
+ }
845
+ ```
846
+
847
+ Hosted API equivalent:
848
+
849
+ ```bash
850
+ curl -sS https://api.luxin.sh/v1/credit-purchases/stripe-checkout-sessions \
851
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN" \
852
+ -H "content-type: application/json" \
853
+ -d '{"quote_id":"quote_...","idempotency_key":"stripe-buy-run-001"}'
854
+ ```
855
+
856
+ x402 hosted API equivalent:
857
+
858
+ ```bash
859
+ curl -sS https://api.luxin.sh/v1/credit-purchases/stripe-x402-deposits \
860
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN" \
861
+ -H "content-type: application/json" \
862
+ -d '{"quote_id":"quote_...","idempotency_key":"agent-x402-buy-run-001"}'
863
+ ```
864
+
865
+ ### `luxin credits status`
866
+
867
+ Without a payment reference, shows the current credit balance using the same
868
+ quota data as `luxin usage quota --json`. With a payment reference,
869
+ shows the durable state of a quote, x402 deposit attempt, Stripe Checkout
870
+ attempt, Checkout Session, or receipt. Use the referenced form after
871
+ `credits buy` so agents do not have to infer payment state from quota deltas
872
+ or activity text.
873
+
874
+ ```bash
875
+ luxin credits status --json
876
+ luxin credits status \
877
+ --payment-attempt-id payatt_... \
878
+ --json
879
+ ```
880
+
881
+ At most one reference flag is allowed: `--quote-id`,
882
+ `--payment-attempt-id`, `--checkout-session-id`, or `--receipt-id`. Passing no
883
+ reference returns the balance/quota state.
884
+
885
+ For Stripe x402 attempts that are still `action_required`, status responses
886
+ include `data.next_actions.recommended_settlement` with the same exact Base/USDC
887
+ payable instructions, a copy-runnable status command for the real
888
+ `payment_attempt_id`, and explicit effect flags showing this is wallet
889
+ settlement, not credit debit, media write, or provider generation work.
890
+
891
+ Minimum action-required data:
892
+
893
+ ```json
894
+ {
895
+ "state": "action_required",
896
+ "quote": {
897
+ "quote_id": "quote_...",
898
+ "credits": 500,
899
+ "price_amount_cents": 500,
900
+ "accepted_payment_method": "stripe_checkout",
901
+ "pack_id": "starter-500",
902
+ "x402": null
903
+ },
904
+ "payment_attempt": {
905
+ "payment_attempt_id": "payatt_...",
906
+ "checkout_session_id": "cs_...",
907
+ "checkout_handoff_url": "https://api.luxin.sh/pay/payatt_...",
908
+ "checkout_compact_url": "https://api.luxin.sh/pay/payatt_...",
909
+ "checkout_url": "https://checkout.stripe.com/c/pay/cs_...#fid...",
910
+ "attempt_status": "requires_action"
911
+ },
912
+ "receipt": null,
913
+ "credit_event": null,
914
+ "next": {
915
+ "retry_after_seconds": 10,
916
+ "human_action": "open_checkout_url",
917
+ "checkout_handoff_url": "https://api.luxin.sh/pay/payatt_...",
918
+ "checkout_compact_url": "https://api.luxin.sh/pay/payatt_..."
919
+ }
920
+ }
921
+ ```
922
+
923
+ Minimum success data includes `state: "succeeded"`, `receipt`,
924
+ `credit_event`, and the updated hosted `limits`.
925
+
926
+ Hosted API equivalent:
927
+
928
+ ```bash
929
+ curl -sS "https://api.luxin.sh/v1/credit-purchases/status?payment_attempt_id=payatt_..." \
930
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN"
931
+ ```
932
+
933
+ Do not pass card data, wallet secrets, provider receipts, Stripe secrets, MPP
934
+ tokens, SPTs, live x402 payment headers, deposit client secrets, wallet
935
+ private keys, seed phrases, or any payment credential to credits commands.
936
+ Stripe Checkout collects payment details only on Stripe-hosted pages; x402
937
+ settlement is handled by the agent/wallet against the returned redacted deposit
938
+ challenge, not by pasting credentials into Luxin. The public request
939
+ fields are `credits`, `pack_id`, `payment_method`, `quote_id`, status reference
940
+ IDs, and `idempotency_key`.
941
+
942
+ ### `luxin models`
943
+
944
+ First-run creative discovery. Lists public models and shows the full
945
+ capability-preserving schema for one model.
946
+
947
+ ```bash
948
+ luxin models --json
949
+ luxin models list --json
950
+ luxin models list --details --json
951
+ luxin models list --available --operation image.generate --json
952
+ luxin models list --available --operation image.edit --json
953
+ luxin models list --available --modality video --operation video.generate --json
954
+ luxin models list --query nano-banana --json
955
+ luxin models list --catalog-only --provider fal --json
956
+ luxin models show MODEL_ID --json
957
+ luxin models show nano-banana --json
958
+ luxin models show default --json
959
+ ```
960
+
961
+ Hosted API equivalents:
962
+
963
+ ```bash
964
+ curl -sS https://api.luxin.sh/v1/models
965
+ curl -sS 'https://api.luxin.sh/v1/models?available=true&modality=video&operation=video.generate'
966
+ curl -sS 'https://api.luxin.sh/v1/models?query=nano-banana'
967
+ curl -sS https://api.luxin.sh/v1/models/xai.grok-imagine-image
968
+ ```
969
+
970
+ `models show` exposes operation support, media input/output types, parameter
971
+ schemas, defaults and fixed controls, cost and latency class, safety behavior,
972
+ and migration hints. Agents should inspect it before assuming a model supports
973
+ seeds, masks, reference images, transparent backgrounds, arbitrary aspect
974
+ ratios, image-size presets, output counts, resolution controls, safety
975
+ controls, or provider-native options.
976
+
977
+ `models list` is executable-first by default and returns one
978
+ `default: true` row when the default executable create model is included.
979
+ `models show default --json` resolves to that model so first-run agents can
980
+ inspect the recommended create surface without knowing a provider-specific
981
+ model id. `models show` also resolves common migration aliases such as
982
+ `nano-banana` to `fal.nano-banana-2`, while `models list --query QUERY --json`
983
+ returns fuzzy provider/model-family matches before an agent commits to one
984
+ model id. The list response also returns `summary` with total, returned,
985
+ available, executable, catalog-only, provider split,
986
+ `execution_availability`, first actionable model ids, recommended filter
987
+ commands, alias hints, provider/category discovery groups, and
988
+ catalog-inclusion flags. Default list output is a compact, sortable model menu
989
+ and excludes catalog-only rows so fresh agents see executable candidates first.
990
+ Each row keeps the model id, flat
991
+ `estimated_usd_per_image`, `credits_required`, lightweight `task_tags`, status,
992
+ provider, max output count/resolution, storage, and `show_command`, while
993
+ omitting full parameter schemas. Use `models show MODEL_ID --json` for one
994
+ model's full capability schema, or `models list --details --json` only when you
995
+ intentionally need the full list with capability schemas for compatibility or
996
+ offline analysis. `--summary` is still accepted as a compatibility alias for the
997
+ default compact list. Use `--available` for currently usable executable rows,
998
+ `--modality image|video|audio|3d` for media type, `--operation
999
+ image.generate`, `--operation image.edit`, `--operation video.generate`,
1000
+ `--operation audio.generate`, or `--operation 3d.generate` for the task,
1001
+ `--provider fal|xai|openai` to narrow by provider, `--query QUERY` to search
1002
+ ids, display names, provider namespaces, operations, tags, intents, upstream
1003
+ Fal endpoint ids, and known aliases, and `--catalog-only` when you intentionally
1004
+ want source-backed rows that are inspectable but not runnable yet.
1005
+ Provider-level availability is not the same thing as model executability; for
1006
+ runnable choices require both `status:"available"` and
1007
+ `execution.model_execution_status:"executable"`. If a reachable provider has no
1008
+ runnable model for the requested operation, `summary.execution_availability`
1009
+ says so directly and includes the fastest `--available --operation ...`
1010
+ recovery command.
1011
+
1012
+ Luxin standardizes common controls so agents can work quickly, but it
1013
+ must not flatten rich model capabilities into coarse universal categories.
1014
+ Use `model_parameters` for rare or model-specific parameters advertised by the
1015
+ capability schema.
1016
+
1017
+ Current executable provider-native controls include:
1018
+
1019
+ - Fal FLUX.1 dev: `model_parameters.image_size` for presets such as
1020
+ `square_hd`, plus `seed`.
1021
+ - Fal FLUX Pro 1.1 Ultra Create: `model_parameters.seed` and
1022
+ `model_parameters.raw`; optional reference-image controls remain cataloged
1023
+ for inspection but are not executable on the create-only path.
1024
+ - Fal Z-Image Turbo Create/Edit: `model_parameters.image_size` for
1025
+ `square_hd`, `square`, portrait/landscape presets, and `auto` on edit; costs
1026
+ are quoted from requested megapixels when the output size is explicit.
1027
+ - Fal Nano Banana 2 Edit: `model_parameters.resolution` for `0.5K`, `1K`,
1028
+ `2K`, and `4K`, plus `seed`.
1029
+ - Fal Ideogram V2 Edit: `model_parameters.expand_prompt`, `seed`, and
1030
+ `style`; pass masks as top-level `--mask` / `mask_asset_id`, not as
1031
+ provider `mask_url`.
1032
+ - Fal Gemini 3 Pro Image Preview Create/Edit:
1033
+ `model_parameters.resolution` for `1K`, `2K`, and `4K`, plus `seed`; 4K is
1034
+ quoted as the higher-priced provider tier.
1035
+ - Fal Nano Banana Pro Create/Edit: `model_parameters.resolution` for `1K`,
1036
+ `2K`, and `4K`, plus `seed`; 4K is quoted as the higher-priced provider tier.
1037
+ - Fal FLUX Pro Kontext Pro/Max Edit: `model_parameters.seed`; guidance scale
1038
+ and aspect-ratio controls remain cataloged for inspection but are not
1039
+ executable until their UX and receipt behavior are represented.
1040
+ - Fal Bytedance Seedream 4.5 Create/Edit: `model_parameters.image_size` for
1041
+ `square_hd`, `square`, portrait/landscape presets, `auto_2K`, and
1042
+ `auto_4K`, plus `seed`; multi-output and multi-reference controls remain
1043
+ cataloged but fixed for hosted accounting.
1044
+ - Fal Bytedance Seedream 5.0 Lite Create/Edit:
1045
+ `model_parameters.image_size` for `square_hd`, `square`, portrait/landscape
1046
+ presets, `auto_2K`, and `auto_3K`; multi-output and multi-reference controls
1047
+ remain cataloged but fixed for hosted accounting.
1048
+ - xAI Grok Imagine Image Quality: `model_parameters.resolution` for `1k` and
1049
+ `2k`; 2k is priced from the higher provider tier. Create supports top-level
1050
+ `--output-count` up to the model's advertised `max_outputs_per_request`,
1051
+ currently mapped to xAI's documented `n` batch parameter.
1052
+ - GPT Image 1.5 create/edit: documented fixed sizes `1024x1024`,
1053
+ `1024x1536`, and `1536x1024`, output format, compression, transparent or
1054
+ opaque background, moderation, and the upstream provider-native quality
1055
+ parameter. GPT Image 1.5 create quotes output-token estimates when quality
1056
+ and concrete size are known; GPT Image 1.5 create supports top-level
1057
+ `--output-count` up to the model's advertised `max_outputs_per_request`,
1058
+ currently mapped to OpenAI's `n` parameter. GPT Image 1.5 edit accepts
1059
+ low/high `input_fidelity` and remains preflight unknown-cost until usage is
1060
+ returned.
1061
+ - GPT Image 2 create/edit: size, output format, compression, background,
1062
+ moderation, and the upstream provider-native quality parameter. GPT Image 2
1063
+ create quotes request-aware output-token estimates when quality and concrete
1064
+ size are known; GPT Image 2 create supports top-level `--output-count` up to
1065
+ the model's advertised `max_outputs_per_request`, currently mapped to
1066
+ OpenAI's `n` parameter. GPT Image 2 edit remains preflight unknown-cost, then
1067
+ records usage-priced provider cost when OpenAI returns token usage.
1068
+
1069
+ Inspect each model before use; provider-native controls are available only
1070
+ through validated `model_parameters`.
1071
+
1072
+ ### `luxin capabilities`
1073
+
1074
+ Schema-language view over the same capability catalog. Use this when you need
1075
+ the capability abstraction directly rather than starting from a model.
1076
+
1077
+ ```bash
1078
+ luxin capabilities --json
1079
+ luxin capabilities list --json
1080
+ luxin capabilities show CAPABILITY_ID --json
1081
+ ```
1082
+
1083
+ ### `luxin create`
1084
+
1085
+ Guides, creates, or plans a zero-cost dry run.
1086
+
1087
+ Guide the first image path without mutation:
1088
+
1089
+ ```bash
1090
+ luxin create --guide --prompt "A compact field camera on a stainless workbench" --json
1091
+ ```
1092
+
1093
+ `create --guide` returns `schema: image-skill.create-guide.v1`,
1094
+ `stage`, `next_command`, `next_command_copy_runnable`,
1095
+ `next_command_missing_inputs`, `guide_warning`, `auth_ready`,
1096
+ `no_spend_evaluation`, `recommended_no_spend_command`,
1097
+ `self_fund_next_command`, `self_fund_handoff`, `self_fund_preparation`,
1098
+ `escape_hatches`, selected executable model and cost, auth/quota/payment
1099
+ blockers, and mutation flags. All
1100
+ mutation flags must be false in guide mode: no provider call, hosted create,
1101
+ signup, payment object, credit debit, or media write.
1102
+ For next-command safety, read `next_command_copy_runnable`,
1103
+ `next_command_missing_inputs`, and `guide_warning.next_command_safety` before
1104
+ acting: `hosted_signup_no_spend_setup` is no-spend auth setup,
1105
+ `live_money_payment_action` is top-up/payment work, and
1106
+ `live_media_create_credit_debit` is a live create that can call a provider,
1107
+ debit credits, and write media.
1108
+ For payment state, read
1109
+ `checks.payments.preferred_method_summary.top_up_path` instead of inferring
1110
+ from several arrays. It is `browserless_agent_self_fund` when the preferred
1111
+ rail is live money, browserless, agent initiated, and agent settleable;
1112
+ `human_payment_handoff` when a human/browser completion step is required; and
1113
+ `payment_method_inspection` when the guide cannot classify a direct top-up path.
1114
+ In guide cost output, `cost.estimated_usd_per_image` is the estimated Image
1115
+ Skill debit in dollars for one output, matching
1116
+ `cost.estimated_debit_usd_per_image` and
1117
+ `cost.estimated_credits * cost.credit_unit_usd` when credit pricing is known.
1118
+ `cost.estimated_provider_usd_per_image` is the upstream provider estimate for
1119
+ transparency; do not use it as the amount the agent needs to fund.
1120
+
1121
+ ```bash
1122
+ luxin create \
1123
+ --prompt "A compact field camera on a stainless workbench" \
1124
+ --intent explore \
1125
+ --aspect-ratio 1:1 \
1126
+ --max-estimated-usd-per-image 0.07 \
1127
+ --json
1128
+ ```
1129
+
1130
+ Hosted defaults are quality-first. If an agent does not choose a model, Image
1131
+ Skill selects the strongest available create capability for the requested
1132
+ intent and budget, then records the decision in `request.selection`. Explicit
1133
+ `--provider`, `--model`, namespaced model ids, and validated
1134
+ `model_parameters` always take precedence. For final/product/hero-style
1135
+ intents, Luxin may default an eligible quality-capability request to a
1136
+ higher output tier only when `--max-estimated-usd-per-image` is high enough for
1137
+ that tier; otherwise it stays on a lower-cost quality tier or chooses a cheaper
1138
+ capability within the budget and tells agents what happened in the selection
1139
+ receipt. Use the `--max-estimated-usd-per-image` value returned by
1140
+ `create --guide`; it is sized to the Luxin credit debit, not only the
1141
+ upstream provider estimate.
1142
+
1143
+ Preview-compatible richer shape:
1144
+
1145
+ ```bash
1146
+ luxin create \
1147
+ --prompt "Campaign-ready product image of a compact field camera" \
1148
+ --intent finalize \
1149
+ --model MODEL_ID \
1150
+ --aspect-ratio 1:1 \
1151
+ --output-count 2 \
1152
+ --max-estimated-usd-per-image 0.07 \
1153
+ --model-parameters-json '{"seed":1234}' \
1154
+ --json
1155
+ ```
1156
+
1157
+ Use `--output-count N` only when `models show MODEL_ID --json` advertises
1158
+ `media.output.max_outputs_per_request` greater than `1`. `--output-count` is a
1159
+ top-level Luxin create control; do not pass provider-native `n` through
1160
+ `model_parameters` unless the selected model schema explicitly advertises that
1161
+ field. Credit pricing and `cost.credit_pricing.credits_required` are total
1162
+ operation debits across all requested outputs. `--max-estimated-usd-per-image`
1163
+ and raw API `max_estimated_usd_per_image` are per-image Luxin debit
1164
+ budget guards.
1165
+
1166
+ Generate video through the same `create` command and durable-media loop. For
1167
+ video prompts, run `luxin create --guide --prompt "..." --json`; the guide
1168
+ can select the executable video model, suggest `--aspect-ratio 16:9`, and emit
1169
+ the next create command. Plain `create` without a model still defaults to an
1170
+ image model, so use the guide or pass the video model id directly. The response
1171
+ returns a durable owned `video_...` mp4 asset URL, a `job_id`, and a
1172
+ `cost.credit_pricing` receipt just like an image create.
1173
+
1174
+ ```bash
1175
+ luxin create \
1176
+ --model fal.ltx-video-13b-distilled \
1177
+ --prompt "A slow dolly push-in on a steaming espresso cup on a cafe counter, morning light" \
1178
+ --aspect-ratio 16:9 \
1179
+ --json
1180
+ ```
1181
+
1182
+ Discover runnable video models with `luxin models list --available
1183
+ --modality video --operation video.generate --json`. Inspect parameters, output
1184
+ media type, and cost first with `luxin models show
1185
+ fal.ltx-video-13b-distilled --json`. Video runs synchronously through the same
1186
+ create call and can take longer than an image; the returned `assets[].url` is an
1187
+ owned `video/mp4`.
1188
+
1189
+ Generate audio (music, sound) through the same `create` command and
1190
+ durable-media loop. Request an audio model by id; the response returns a durable
1191
+ owned `audio_...` wav asset URL, a `job_id`, and a `cost.credit_pricing` receipt
1192
+ just like an image create. Audio has no aspect ratio, so do not pass
1193
+ `--aspect-ratio`.
1194
+
1195
+ ```bash
1196
+ luxin create \
1197
+ --model fal.stable-audio-25-text-to-audio \
1198
+ --prompt "A warm lo-fi hip-hop loop with vinyl crackle and a mellow Rhodes piano" \
1199
+ --json
1200
+ ```
1201
+
1202
+ `fal.stable-audio-25-text-to-audio` (Stable Audio 2.5) is text-to-audio at a flat
1203
+ $0.20/clip (about 34 credits, quoted before spend) and returns an owned
1204
+ `audio/wav` clip. The first slice is defaults-only (no tunable
1205
+ `model_parameters`); duration/steps controls are a later milestone. Inspect
1206
+ parameters, output media type, and cost first with `luxin models show
1207
+ fal.stable-audio-25-text-to-audio --json`. Audio runs synchronously through the
1208
+ same create call and can take longer than an image.
1209
+
1210
+ For create models with wired reference support, pass owned reference assets
1211
+ with the model's advertised reference role. Kling element routes use
1212
+ `--element-frontal IMAGE[@ELEMENT_INDEX]` and
1213
+ `--element-reference IMAGE[@ELEMENT_INDEX[:REFERENCE_INDEX]]`; flat
1214
+ reference-image routes use `--reference-image IMAGE[@INDEX]`; Fal DreamO also
1215
+ accepts `:TASK` where `TASK` is `ip`, `id`, or `style`. The public CLI uploads
1216
+ local paths and external URLs first, then
1217
+ sends top-level `references[]` entries with Luxin `asset_id` values to
1218
+ `/v1/create`. Do not pass provider-native `elements`, `frontal_image_url`,
1219
+ `reference_image_urls`, `first_image_url`, `second_image_url`, `images`, or
1220
+ `*_reference_task` through `model_parameters`; provider-private URLs are
1221
+ resolved server-side after ownership and media-policy validation.
1222
+
1223
+ ```bash
1224
+ luxin create \
1225
+ --model fal.kling-image-o3-text-to-image \
1226
+ --prompt "Place the same character in a clean studio campaign" \
1227
+ --element-frontal ./character-front.png@0 \
1228
+ --element-reference ./character-side.webp@0:0 \
1229
+ --output-count 2 \
1230
+ --max-estimated-usd-per-image 0.06 \
1231
+ --json
1232
+ ```
1233
+
1234
+ ```bash
1235
+ luxin create \
1236
+ --model fal.dreamo \
1237
+ --prompt "Studio portrait preserving identity with a bolder editorial style" \
1238
+ --reference-image ./identity.png@0:id \
1239
+ --reference-image ./style.webp@1:style \
1240
+ --model-parameters-json '{"image_size":{"width":1280,"height":720}}' \
1241
+ --max-estimated-usd-per-image 0.06 \
1242
+ --json
1243
+ ```
1244
+
1245
+ High-resolution examples:
1246
+
1247
+ ```bash
1248
+ luxin create \
1249
+ --prompt "Campaign-ready product image of a compact field camera" \
1250
+ --intent final \
1251
+ --max-estimated-usd-per-image 0.07 \
1252
+ --json
1253
+
1254
+ luxin create \
1255
+ --prompt "Campaign-ready product image of a compact field camera" \
1256
+ --model fal.gemini-3-pro-image-preview \
1257
+ --model-parameters-json '{"resolution":"4K"}' \
1258
+ --max-estimated-usd-per-image 0.30 \
1259
+ --json
1260
+
1261
+ luxin create \
1262
+ --prompt "Campaign-ready product image of a compact field camera" \
1263
+ --model xai.grok-imagine-image-quality \
1264
+ --model-parameters-json '{"resolution":"2k"}' \
1265
+ --max-estimated-usd-per-image 0.07 \
1266
+ --json
1267
+
1268
+ luxin edit \
1269
+ --input-asset-id image_... \
1270
+ --prompt "preserve the subject and make this campaign-ready" \
1271
+ --model fal.nano-banana-2-edit \
1272
+ --model-parameters-json '{"resolution":"4K"}' \
1273
+ --accept-unknown-cost \
1274
+ --json
1275
+ ```
1276
+
1277
+ `model_parameters` must be validated against the selected model/capability
1278
+ schema before any provider call or paid reservation. Unknown fields fail closed
1279
+ unless the capability explicitly allows additional properties. This is how
1280
+ Luxin preserves rare model controls without turning every
1281
+ provider-specific parameter into a top-level flag.
1282
+ In the current preview, Fal create/edit, xAI quality generation, and OpenAI GPT
1283
+ Image 2 expose the executable provider-native controls listed in the selected
1284
+ model schema. GPT Image 2 create has request-aware output-token credit quotes
1285
+ for concrete quality/size requests; GPT Image 2 edit still requires
1286
+ unknown-cost acceptance before execution, but records usage-priced provider cost
1287
+ after execution when OpenAI returns token usage. Provider-native controls remain
1288
+ visible for planning and fail closed until their capability schema marks them
1289
+ executable. Hosted `create --dry-run` validates `model_parameters` against the
1290
+ selected model, returns accepted keys/provenance and request-aware credit
1291
+ pricing for planning, and never executes provider controls or consumes credits.
1292
+ Hosted `edit --dry-run` validates the same owned input, mask/reference,
1293
+ prompt-policy, budget, and `model_parameters` checks as a live edit, then
1294
+ returns planned outputs without storage, provider, or billing side effects.
1295
+ For dry-run responses, `cost.credit_pricing.credits_required` is the planned
1296
+ live execution debit for the selected model. The actual debit for the dry run is
1297
+ `quota.consumed_credits: 0`.
1298
+ Authenticated hosted dry-runs also create a recoverable planned job:
1299
+ `jobs show` returns `status: "planned"` with `plan_receipt`, and `activity`
1300
+ emits `job.planned`. Planned receipts do not create downloadable media assets or
1301
+ usage debits, media writes, or provider execution. In the first-run guide, this
1302
+ exact no-spend command behavior is exposed as
1303
+ `data.no_spend_next_command_effect` and
1304
+ `data.recommended_no_spend_command_effect`; the evaluator stop policy is exposed
1305
+ as `data.no_spend_evaluation`.
1306
+
1307
+ Minimum success data:
1308
+
1309
+ ```json
1310
+ {
1311
+ "job_id": "job_...",
1312
+ "capability": {
1313
+ "id": "is.image.generate.xai-grok-imagine-image-quality.v1"
1314
+ },
1315
+ "assets": [
1316
+ {
1317
+ "asset_id": "image_...",
1318
+ "path": "https://media.image-skill.com/a/image_abc123.png",
1319
+ "mime_type": "image/png",
1320
+ "url": "https://media.image-skill.com/a/image_abc123.png",
1321
+ "content_length": 333444,
1322
+ "width": 2048,
1323
+ "height": 2048
1324
+ }
1325
+ ],
1326
+ "cost": {
1327
+ "estimated_usd": 0.07,
1328
+ "credit_pricing": {
1329
+ "credit_unit_usd": 0.01,
1330
+ "credits_required": 12,
1331
+ "estimated_provider_cost_usd": 0.07,
1332
+ "estimated_revenue_usd": 0.12,
1333
+ "pricing_confidence": "known"
1334
+ }
1335
+ },
1336
+ "request": {
1337
+ "output_count": 1,
1338
+ "selection": {
1339
+ "policy": "hosted_default_create_v1",
1340
+ "reason": "hosted default selected the strongest currently available quality-first create model",
1341
+ "intent": "explore",
1342
+ "capability": {
1343
+ "id": "is.image.generate.xai-grok-imagine-image-quality.v1"
1344
+ },
1345
+ "model_parameters": {
1346
+ "keys": ["resolution"],
1347
+ "defaults_applied": ["resolution=2k"],
1348
+ "source": "default_policy"
1349
+ },
1350
+ "output": {
1351
+ "resolution_class": "2k",
1352
+ "expected_width": null,
1353
+ "expected_height": null,
1354
+ "expected_min_short_edge": 2048
1355
+ }
1356
+ }
1357
+ },
1358
+ "safety": {
1359
+ "status": "allowed"
1360
+ }
1361
+ }
1362
+ ```
1363
+
1364
+ When hosted artifact storage is configured, `url` is an Luxin-owned URL.
1365
+ Agents should prefer `assets[].url` over provider-origin URLs and should not
1366
+ need provider account access to fetch outputs.
1367
+
1368
+ Hosted create does not accept `--output-dir`. A future download/fetch command
1369
+ may add CLI-side local file convenience while preserving hosted artifact URLs as
1370
+ the source of truth.
1371
+
1372
+ If provider generation succeeds but artifact storage fails, the command returns
1373
+ `ARTIFACT_STORAGE_WRITE_FAILED` with exit `9` and `retryable: false`. Agents
1374
+ should not retry the whole create blindly, because that may duplicate paid
1375
+ provider spend.
1376
+
1377
+ For retry-safe create automation, pass an explicit non-secret
1378
+ `--idempotency-key`. A retry that reuses the same key does not create a second
1379
+ credit reservation, so a transient `502`/`PROVIDER_FAILURE` that already
1380
+ reserved a credit cannot double-charge on retry. `create --guide` bakes a
1381
+ generated `--idempotency-key` into its advertised create `next_command`, and a
1382
+ retryable create error returns an `error.recovery.idempotency_key` plus an
1383
+ `error.recovery.suggested_command` that re-runs the same create with that key.
1384
+
1385
+ Live non-dry-run create/edit emits one JSON diagnostic line to stderr before
1386
+ the blocking hosted request:
1387
+
1388
+ ```json
1389
+ {
1390
+ "in_flight": {
1391
+ "command": "luxin create",
1392
+ "idempotency_key": "create-...",
1393
+ "recover_command": "luxin create --idempotency-key create-... <same arguments> --json"
1394
+ }
1395
+ }
1396
+ ```
1397
+
1398
+ stdout remains the command JSON envelope. If an agent combines streams with
1399
+ `2>&1`, split stderr diagnostics from the stdout envelope before parsing. The
1400
+ same recovery breadcrumb is stored under `<config-dir>/in-flight/` and appears
1401
+ in `luxin doctor --json` at `data.in_flight`. Keep the in-flight
1402
+ `idempotency_key` and `recover_command` inside the agent workflow unless a
1403
+ failed or uncertain operation needs user-visible recovery.
1404
+
1405
+ ```bash
1406
+ luxin create \
1407
+ --prompt "A compact field camera on a stainless workbench" \
1408
+ --idempotency-key create-run-001 \
1409
+ --json
1410
+ ```
1411
+
1412
+ Hosted free-preview API equivalent:
1413
+
1414
+ ```bash
1415
+ curl -sS https://api.luxin.sh/v1/create \
1416
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN" \
1417
+ -H "content-type: application/json" \
1418
+ -d '{
1419
+ "prompt": "A compact field camera on a stainless workbench",
1420
+ "intent": "explore",
1421
+ "aspect_ratio": "1:1",
1422
+ "output_count": 1,
1423
+ "max_estimated_usd_per_image": 0.07
1424
+ }'
1425
+ ```
1426
+
1427
+ Hosted free-preview create currently requires owned artifact storage and returns
1428
+ one `assets[]` entry per output with `assets[].url` under
1429
+ `https://media.image-skill.com/...` on success.
1430
+
1431
+ ### `luxin upload`
1432
+
1433
+ Normalizes a local image path or remote image URL into an Luxin-owned
1434
+ input asset for later edit workflows.
1435
+
1436
+ ```bash
1437
+ luxin upload ./source.png --json
1438
+ luxin upload https://example.com/source.png --json
1439
+ ```
1440
+
1441
+ The CLI reads local files and remote URLs client-side, then sends image bytes to
1442
+ `POST /v1/upload`. The hosted API does not fetch arbitrary remote URLs in this
1443
+ preview. This keeps server-side URL fetching out of the public upload path.
1444
+
1445
+ Minimum success data:
1446
+
1447
+ ```json
1448
+ {
1449
+ "request": {
1450
+ "source_kind": "local_path",
1451
+ "filename": "source.png",
1452
+ "remote_origin": null
1453
+ },
1454
+ "asset": {
1455
+ "asset_id": "image_...",
1456
+ "job_id": "job_...",
1457
+ "kind": "uploaded",
1458
+ "url": "https://media.image-skill.com/a/image_abc123.png",
1459
+ "mime_type": "image/png",
1460
+ "content_length": 12345
1461
+ },
1462
+ "upload": {
1463
+ "bytes": 12345,
1464
+ "mime_type": "image/png",
1465
+ "sha256": "...",
1466
+ "policy": {
1467
+ "status": "allowed"
1468
+ }
1469
+ }
1470
+ }
1471
+ ```
1472
+
1473
+ Supported preview MIME types are `image/png`, `image/jpeg`, `image/webp`,
1474
+ `image/gif`, and `image/avif`. Unsupported input returns
1475
+ `INPUT_POLICY_DENIED` with exit `6`. Responses never include local paths, raw
1476
+ bytes, base64 payloads, full remote URLs, bucket names, or object keys.
1477
+
1478
+ ### `luxin edit`
1479
+
1480
+ Edits an Luxin-owned input asset or client-normalized local/remote image
1481
+ with one hosted provider-backed edit model.
1482
+
1483
+ ```bash
1484
+ luxin edit \
1485
+ --input ASSET_ID_OR_PATH_OR_URL \
1486
+ --mask MASK_ASSET_ID_OR_PATH_OR_URL \
1487
+ --prompt "Remove the background and keep natural object shadows" \
1488
+ --accept-unknown-cost \
1489
+ --json
1490
+ ```
1491
+
1492
+ If `--input` is a local path or external URL, the public CLI first normalizes it
1493
+ through the same upload resolver as `luxin upload`, then sends only the
1494
+ resulting `asset_id` to `POST /v1/edit`. If `--input` is an Luxin asset id
1495
+ or owned asset URL, edit uses that owned asset directly.
1496
+ Add `--dry-run` to plan the edit after owned-asset, prompt-policy,
1497
+ `model_parameters`, and budget validation. Dry-run edit responses return planned
1498
+ assets and `quota.consumed_credits: 0`, store a recoverable `job.planned`
1499
+ receipt, and do not call the provider, debit credits, or write media.
1500
+ For models with wired mask support, `--mask` follows the same upload/asset-id
1501
+ resolver and sends only `mask_asset_id`; never pass provider-native `mask_url`
1502
+ through `model_parameters`.
1503
+ For models with wired reference support, pass owned reference assets with the
1504
+ model's advertised reference role. Kling element routes use
1505
+ `--element-frontal IMAGE[@ELEMENT_INDEX]` and
1506
+ `--element-reference IMAGE[@ELEMENT_INDEX[:REFERENCE_INDEX]]`; flat
1507
+ reference-image routes use `--reference-image IMAGE[@INDEX[:TASK]]`. The
1508
+ public CLI uploads local paths and external URLs first, then sends top-level
1509
+ `references[]` entries with Luxin `asset_id` values. For Kling element
1510
+ routes, `--element-frontal ./front.png@0` becomes role `element_frontal` for
1511
+ element index `0`, and `--element-reference ./side.webp@0:0` becomes role
1512
+ `element_reference` for the same element with reference slot `0`. For DreamO
1513
+ create, `--reference-image ./identity.png@0:id` becomes role
1514
+ `reference_image`, index `0`, and `reference_task` `id`. For xAI edit,
1515
+ `--reference-image ./reference.png@0` becomes the second ordered source image;
1516
+ the primary `--input` asset remains the first source image. Do not pass
1517
+ provider-native `elements`, `image_url`, `image_urls`, `frontal_image_url`,
1518
+ `reference_image_urls`, `first_image_url`, `second_image_url`, `images`, or
1519
+ `*_reference_task` through `model_parameters`; provider-private URLs are
1520
+ resolved server-side after ownership and media-policy validation.
1521
+ Current public `references[]` support covers Kling Image O1, Kling Image O3
1522
+ image-to-image/text-to-image, Kling Image v3 image-to-image/text-to-image, and
1523
+ Fal DreamO create plus xAI Grok Imagine image edit/quality edit. Kling requests
1524
+ may contain at most 40 reference entries across at most 10 contiguous element
1525
+ indexes starting at `0`; each referenced element requires one frontal image and
1526
+ may include up to three additional reference images. DreamO accepts up to two
1527
+ contiguous `reference_image` indexes starting at `0`, each with optional
1528
+ `reference_task` `ip`, `id`, or `style`. xAI edit accepts up to two contiguous
1529
+ `reference_image` indexes starting at `0` and does not accept `reference_task`.
1530
+ Reference assets must be Luxin-owned PNG, JPEG, or WebP images with
1531
+ known non-empty byte length up to 10MB, known width and height of at least
1532
+ 300px, and aspect ratio from 0.40 to 2.50.
1533
+
1534
+ ```bash
1535
+ luxin edit \
1536
+ --model fal.kling-image-o3-image-to-image \
1537
+ --input ./starting-frame.png \
1538
+ --element-frontal ./character-front.png@0 \
1539
+ --element-reference ./character-side.webp@0:0 \
1540
+ --prompt "Place the same character in a clean studio product portrait" \
1541
+ --accept-unknown-cost \
1542
+ --json
1543
+ ```
1544
+
1545
+ Direct `/v1/edit` callers use the same owned-asset contract:
1546
+
1547
+ ```json
1548
+ {
1549
+ "input_asset_id": "image_starting_frame",
1550
+ "model": "fal.kling-image-o3-image-to-image",
1551
+ "prompt": "Place the same character in a clean studio product portrait",
1552
+ "references": [
1553
+ {
1554
+ "asset_id": "image_character_front",
1555
+ "role": "element_frontal",
1556
+ "index": 0
1557
+ },
1558
+ {
1559
+ "asset_id": "image_character_side",
1560
+ "role": "element_reference",
1561
+ "index": 0,
1562
+ "reference_index": 0
1563
+ }
1564
+ ]
1565
+ }
1566
+ ```
1567
+
1568
+ Set `dry_run: true` on `/v1/edit` to get the same no-spend plan the CLI returns.
1569
+ The server still validates ownership, prompt policy, references, masks,
1570
+ `model_parameters`, and budget guards before returning the planned job.
1571
+
1572
+ Create a 3D asset from an image through the same `edit` command and
1573
+ durable-media loop. Image-to-3D is promptless and image-conditioned, so it ships
1574
+ as a variation transform: pass exactly one owned input image (no prompt) to a 3D
1575
+ model by id and the response returns a durable owned `.glb` mesh asset URL (in
1576
+ `assets[].url`), a `job_id`, and a `cost.credit_pricing` receipt. A 3D mesh has
1577
+ no aspect ratio.
1578
+
1579
+ ```bash
1580
+ luxin edit \
1581
+ --input image_... \
1582
+ --model fal.trellis-image-to-3d \
1583
+ --json
1584
+ ```
1585
+
1586
+ `fal.trellis-image-to-3d` (Trellis) is image-to-3D at a flat $0.02/asset (about 4
1587
+ credits, quoted before spend) and returns an owned `model/gltf-binary` (`.glb`)
1588
+ textured mesh. The first slice is defaults-only (no tunable `model_parameters`);
1589
+ guidance/steps/mesh_simplify/texture_size controls are a later milestone. Inspect
1590
+ parameters, output media type, and cost first with `luxin models show
1591
+ fal.trellis-image-to-3d --json`. The input must be one Luxin-owned image;
1592
+ 3D runs synchronously through the same edit call and can take longer than an
1593
+ image.
1594
+
1595
+ Preview hosted create/edit supports model-specific provider-backed paths such
1596
+ as Fal Gemini 3 Pro Image Preview Create (`fal.gemini-3-pro-image-preview`),
1597
+ Fal Nano Banana 2 Edit (`fal.nano-banana-2-edit`), Fal Ideogram V2 Edit
1598
+ (`fal.ideogram-v2-edit`), Fal Gemini 3 Pro Image
1599
+ Preview Edit (`fal.gemini-3-pro-image-preview-edit`), Fal FLUX Pro 1.1 Ultra
1600
+ Create (`fal.flux-pro-v1-1-ultra`), Fal FLUX Pro Kontext Edit
1601
+ (`fal.flux-pro-kontext`), Fal FLUX Pro Kontext Max Edit
1602
+ (`fal.flux-pro-kontext-max`), Fal Seedream 5.0 Lite Create
1603
+ (`fal.bytedance-seedream-v5-lite-text-to-image`), Fal Seedream 5.0 Lite Edit
1604
+ (`fal.bytedance-seedream-v5-lite-edit`), Fal Seedream 4.5 Create
1605
+ (`fal.bytedance-seedream-v4-5-text-to-image`), Fal Seedream 4.5 Edit
1606
+ (`fal.bytedance-seedream-v4-5-edit`), Fal Nano Banana Pro Create
1607
+ (`fal.nano-banana-pro`), Fal Nano Banana Pro Edit
1608
+ (`fal.nano-banana-pro-edit`), GPT Image 1.5 Create
1609
+ (`openai.gpt-image-1.5`), GPT Image 1.5 Edit
1610
+ (`openai.gpt-image-1.5-edit`), and GPT Image 2 Edit
1611
+ (`openai.gpt-image-2-edit`) when their provider credentials are configured.
1612
+ Fal Gemini 3 Pro Image Preview create/edit has known per-image pricing: 1K/2K
1613
+ requests quote `$0.15` provider cost and 4K quotes the doubled provider tier.
1614
+ Fal Nano Banana Pro create/edit uses the same `$0.15` standard and doubled 4K
1615
+ provider tier. Fal FLUX Pro 1.1 Ultra Create quotes `$0.06` provider cost per
1616
+ image. Fal FLUX Pro Kontext Edit quotes `$0.04` provider cost per image, and
1617
+ Fal FLUX Pro Kontext Max Edit quotes `$0.08` provider cost per image. Fal
1618
+ Seedream 4.5 create/edit quotes `$0.04` provider cost per image.
1619
+ Fal Seedream 5.0 Lite create/edit quotes `$0.035` provider cost per image. Fal
1620
+ Z-Image Turbo create/edit quotes `$0.005/MP` when `image_size` is explicit or
1621
+ derived from aspect ratio; edit `auto` remains unknown-cost. GPT Image 1.5
1622
+ create quotes output-token estimates for concrete quality/size requests using
1623
+ OpenAI's fixed-size token table; GPT Image 1.5 edit remains preflight
1624
+ unknown-cost because edit input image/text tokens are provider-metered, then
1625
+ records usage-priced provider cost when OpenAI returns token usage. GPT Image 2
1626
+ create quotes output-token estimates for concrete quality/size requests. GPT
1627
+ Image 2 edit remains preflight unknown-cost because edit input image/text tokens
1628
+ are provider-metered, then records usage-priced provider cost when OpenAI
1629
+ returns token usage. Other edit paths without machine-readable pricing require
1630
+ `--accept-unknown-cost` until a stable price source is captured. Responses
1631
+ include a new generated asset URL, job id, safety state, quota consumption, and
1632
+ input asset metadata where
1633
+ applicable. Responses do not include raw prompts, source bytes, base64
1634
+ payloads, local paths, full external URLs, bucket names, or object keys.
1635
+ When `quota.top_up.available` is true, `next_actions.self_fund.quote_command`
1636
+ is a copy-runnable top-up quote command. `next_actions.self_fund.recommended`
1637
+ and the mirrored top-up `urgency`, `urgency_score`, and `urgency_reasons` say
1638
+ whether the agent should act now. The handoff exposes `first_safe_command`,
1639
+ `first_safe_command_effect`, `inspect_methods_command`, and
1640
+ `inspect_packs_command` for no-spend payment rail inspection before quote/buy.
1641
+ The quote command omits `--idempotency-key` so the public CLI generates and
1642
+ returns one for retry safety before the agent follows the quote response into
1643
+ `credits buy` and `credits status`.
1644
+
1645
+ Provider/model names in this paragraph are preview provenance, not the primary
1646
+ public UX. The public selection surface should be Luxin capabilities and
1647
+ model-parameter schemas; provider/model details belong in explicit
1648
+ provenance/debug output.
1649
+
1650
+ Edit accepts the same retry-safe `--idempotency-key` as create. A retry that
1651
+ reuses the same key does not create a second credit reservation, so a transient
1652
+ `502`/`PROVIDER_FAILURE` after a reservation cannot double-charge; a retryable
1653
+ edit error returns an `error.recovery.idempotency_key` and an
1654
+ `error.recovery.suggested_command` that re-runs the same edit with that key.
1655
+ Live non-dry-run edit emits the same stderr `in_flight` diagnostic and local
1656
+ doctor-visible recovery breadcrumb as create.
1657
+
1658
+ ### `luxin assets show`
1659
+
1660
+ Inspects an Luxin-owned asset URL or hosted asset id.
1661
+
1662
+ ```bash
1663
+ luxin assets show \
1664
+ https://media.image-skill.com/a/image_abc123.png \
1665
+ --json
1666
+ ```
1667
+
1668
+ For asset-id lookup, use hosted auth:
1669
+
1670
+ ```bash
1671
+ luxin assets show image_... --json
1672
+ ```
1673
+
1674
+ Minimum success data:
1675
+
1676
+ ```json
1677
+ {
1678
+ "request": {
1679
+ "reference": "image_...",
1680
+ "reference_type": "asset_id"
1681
+ },
1682
+ "asset": {
1683
+ "asset_id": "image_...",
1684
+ "job_id": "job_...",
1685
+ "url": "https://media.image-skill.com/a/image_abc123.png",
1686
+ "mime_type": "image/png",
1687
+ "content_length": 12345,
1688
+ "width": 1024,
1689
+ "height": 1024,
1690
+ "source": "hosted_metadata"
1691
+ }
1692
+ }
1693
+ ```
1694
+
1695
+ External URLs are rejected. Older assets created before hosted asset metadata
1696
+ was recorded may still be inspectable by Luxin-owned URL.
1697
+
1698
+ For hosted generated assets, when quota exposes an available top-up path,
1699
+ `data.next_actions.self_fund` mirrors the top-up recommendation, urgency, and
1700
+ no-spend payment rail inspection handoff used by create/edit, jobs, and
1701
+ activity responses. On successful create/edit, when that self-fund action is
1702
+ recommended and copy-runnable, `data.self_fund_next_command` aliases
1703
+ `data.next_actions.self_fund.quote_command`; its effect object proves the quote
1704
+ does not buy, settle a wallet transfer, debit credits, call a provider, create a
1705
+ hosted job, or write media.
1706
+
1707
+ ### `luxin assets get`
1708
+
1709
+ Downloads an Luxin-owned asset URL or hosted asset id to a local file.
1710
+
1711
+ ```bash
1712
+ luxin assets get \
1713
+ https://media.image-skill.com/a/image_abc123.png \
1714
+ --output ./result.png \
1715
+ --json
1716
+ ```
1717
+
1718
+ The command refuses to overwrite existing files unless `--overwrite` is
1719
+ explicit. It verifies byte length when the asset server provides a
1720
+ `content-length` header. For hosted asset-id downloads, `assets get` preserves
1721
+ `data.next_actions.self_fund` from the asset metadata response after a
1722
+ successful download.
1723
+
1724
+ ### `luxin jobs show`
1725
+
1726
+ Inspects a hosted Luxin job visible to the authenticated agent.
1727
+
1728
+ ```bash
1729
+ luxin jobs show job_... --json
1730
+ ```
1731
+
1732
+ Output includes public job status, trace id, timestamps, capability id, cost
1733
+ summary, safety status, and Luxin-owned asset metadata. For fresh-agent
1734
+ parsing, `status`, `state`, `assets`, and `cost` are mirrored at top level and
1735
+ match `job.status`, `job.assets`, and `job.cost`. Provider/model provenance is
1736
+ available only through explicit provenance/debug affordances for authorized
1737
+ actors. Default output does not include raw prompts, generated bytes, provider
1738
+ credentials, DB/storage keys, bucket names, or local paths.
1739
+
1740
+ Minimum success data:
1741
+
1742
+ ```json
1743
+ {
1744
+ "request": {
1745
+ "job_id": "job_..."
1746
+ },
1747
+ "status": "completed",
1748
+ "state": "completed",
1749
+ "assets": [],
1750
+ "cost": {
1751
+ "estimated_usd": 0.05,
1752
+ "provider_reported_usd_ticks": null
1753
+ },
1754
+ "job": {
1755
+ "job_id": "job_...",
1756
+ "status": "completed",
1757
+ "assets": [],
1758
+ "cost": {
1759
+ "estimated_usd": 0.05,
1760
+ "provider_reported_usd_ticks": null
1761
+ }
1762
+ }
1763
+ }
1764
+ ```
1765
+
1766
+ ### `luxin jobs wait`
1767
+
1768
+ Waits for a hosted Luxin job to reach a terminal status.
1769
+
1770
+ ```bash
1771
+ luxin jobs wait job_... --timeout-ms 30000 --poll-interval-ms 1000 --json
1772
+ ```
1773
+
1774
+ Completed jobs return immediately. Non-terminal jobs poll until completion,
1775
+ failure, cancellation, or deterministic timeout. Terminal success uses the same
1776
+ top-level `status`, `state`, `assets`, and `cost` mirrors as `jobs show`, with
1777
+ `request.timeout_ms` and `request.poll_interval_ms` added for provenance.
1778
+
1779
+ ### `luxin activity list`
1780
+
1781
+ Lists recent hosted activity ledger events visible to the authenticated agent.
1782
+
1783
+ ```bash
1784
+ luxin activity list --limit 20 --json
1785
+ luxin activity list --subject job_... --json
1786
+ ```
1787
+
1788
+ Activity is the ledger, not the work queue. Use it to find recent event IDs,
1789
+ related job IDs, asset IDs, usage IDs, feedback IDs, trace IDs, status changes,
1790
+ and product-memory writes. Use `jobs show` or `jobs wait` when you need
1791
+ operational recovery, polling, retry judgment, or final job assets.
1792
+
1793
+ When the ledger proves generated work and current quota exposes an available
1794
+ top-up path, `data.next_actions.self_fund` mirrors the same recommendation,
1795
+ urgency, and no-spend payment-method inspection handoff returned by successful
1796
+ create/edit and `jobs show`.
1797
+
1798
+ Minimum success data:
1799
+
1800
+ ```json
1801
+ {
1802
+ "events": [
1803
+ {
1804
+ "event_id": "evt_...",
1805
+ "type": "job.completed",
1806
+ "occurred_at": "2026-05-05T19:00:23.000Z",
1807
+ "summary": "Create job completed",
1808
+ "operation": "create",
1809
+ "subject": {
1810
+ "type": "job",
1811
+ "id": "job_..."
1812
+ },
1813
+ "links": {
1814
+ "job_id": "job_...",
1815
+ "asset_ids": ["image_..."],
1816
+ "feedback_id": null,
1817
+ "usage_event_id": "usage_..."
1818
+ },
1819
+ "status": "completed",
1820
+ "cost": {
1821
+ "estimated_usd": 0.025
1822
+ }
1823
+ }
1824
+ ],
1825
+ "source": "hosted_activity_ledger"
1826
+ }
1827
+ ```
1828
+
1829
+ The ledger hides provider and storage implementation details by default. It is
1830
+ safe to cite `evt_...`, `job_...`, `image_...`, `usage_...`, `feedback_id`,
1831
+ and `trace_id` values in feedback.
1832
+
1833
+ Hosted API equivalent:
1834
+
1835
+ ```bash
1836
+ curl -sS "https://api.luxin.sh/v1/activity?limit=20&subject=job_..." \
1837
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN"
1838
+ ```
1839
+
1840
+ ### `luxin activity show`
1841
+
1842
+ Shows one hosted activity event or the latest events related to one subject.
1843
+
1844
+ ```bash
1845
+ luxin activity show evt_... --json
1846
+ luxin activity show job_... --json
1847
+ luxin activity show image_... --json
1848
+ luxin activity show sig_... --json
1849
+ ```
1850
+
1851
+ `activity show` accepts activity event IDs plus job, asset, usage, feedback, and
1852
+ trace references. When the reference is a subject rather than one exact event,
1853
+ the response includes matching ledger events so an agent can cite the right
1854
+ event without reading telemetry logs. When current quota exposes top-up
1855
+ availability after generated work,
1856
+ `data.next_actions.self_fund.first_safe_command` is the no-spend rail
1857
+ inspection command to run before any quote/buy step.
1858
+
1859
+ Hosted API equivalent:
1860
+
1861
+ ```bash
1862
+ curl -sS https://api.luxin.sh/v1/activity/evt_... \
1863
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN"
1864
+ ```
1865
+
1866
+ ### Activity Event Registry
1867
+
1868
+ Activity `type` values are stable public contract values. Do not infer new
1869
+ event names from provider responses or telemetry logs; use only the registry
1870
+ below.
1871
+
1872
+ | Event type | Subject | Operation | Emitted when | Stable links |
1873
+ | ------------------------------------------ | ---------- | ----------- | ------------------------------------------------------------------ | ------------------------------------------------------------------ |
1874
+ | `job.completed` | `job` | create/edit | A hosted create or edit job reaches a terminal state. | `job_id`, `asset_ids`, `usage_event_id` |
1875
+ | `job.planned` | `job` | create/edit | An authenticated hosted dry-run stores a recoverable plan receipt. | `job_id` |
1876
+ | `asset.created` | `asset` | create/edit | A hosted create or edit produces an output asset. | `job_id`, `asset_ids`, `usage_event_id` |
1877
+ | `asset.uploaded` | `asset` | upload | A public edit workflow uploads or imports input media. | `job_id`, `asset_ids`, `usage_event_id` |
1878
+ | `usage.credit_consumed` | `usage` | usage | A creative operation records a preview-credit entry. | `job_id`, `usage_event_id` |
1879
+ | `feedback.created` | `feedback` | feedback | Hosted agent feedback is accepted into product memory. | `feedback_id` |
1880
+ | `feedback.github_queue.processed` | `feedback` | feedback | Feedback is processed by the GitHub implementation queue handoff. | `feedback_id` |
1881
+ | `payment.checkout_session.created` | `payment` | payment | A Stripe Checkout session is created and awaits external action. | `quote_id`, `payment_attempt_id`, `checkout_session_id` |
1882
+ | `credits.payment_backed_granted` | `credit` | credits | Verified payment fulfillment grants paid credits. | `quote_id`, `receipt_id`, `credit_event_id` |
1883
+ | `credits.payment_backed_refunded` | `credit` | credits | A Stripe refund debits payment-backed credits. | `quote_id`, `receipt_id`, `payment_reversal_id`, `credit_event_id` |
1884
+ | `credits.payment_backed_disputed` | `credit` | credits | A Stripe dispute debit applies to payment-backed credits. | `quote_id`, `receipt_id`, `payment_reversal_id`, `credit_event_id` |
1885
+ | `credits.payment_backed_reinstated` | `credit` | credits | Stripe dispute funds were reinstated and recorded. | `quote_id`, `receipt_id`, `payment_reversal_id` |
1886
+ | `credits.payment_backed_reversal_pending` | `credit` | credits | A reversal was recorded but could not be fully applied. | `quote_id`, `receipt_id`, `payment_reversal_id` |
1887
+ | `credits.payment_backed_reversal_rejected` | `credit` | credits | A reversal was rejected because it could not safely reconcile. | `quote_id`, `receipt_id`, `payment_reversal_id` |
1888
+
1889
+ `feedback.github_queue.processed` includes `details.github_queue` with
1890
+ machine-readable lifecycle fields such as `state`, `reason`, `issue_urls`,
1891
+ `issue_numbers`, `mode`, and `github_mutation`. Agents should use it to learn
1892
+ whether submitted feedback was promoted, skipped, deduped, blocked, or already
1893
+ mirrored without reading private repository artifacts.
1894
+ `job.planned` includes `details.plan_receipt` for authenticated hosted
1895
+ dry-runs. It is a recoverable planning receipt, not completed media work:
1896
+ planned outputs do not have durable asset IDs, download URLs, usage debits, or
1897
+ provider execution.
1898
+
1899
+ If a response includes an event type outside this registry, treat it as a
1900
+ contract bug and submit `luxin feedback create --json` with the event ID
1901
+ and trace ID.
1902
+
1903
+ ### `luxin feedback create`
1904
+
1905
+ Leaves structured product feedback in hosted Luxin product memory.
1906
+ At minimum, provide `--title` and `--body`; Luxin accepts narrative
1907
+ feedback and adds quality guidance server-side. Use the structured fields below
1908
+ when the agent already knows them.
1909
+
1910
+ ```bash
1911
+ luxin feedback create \
1912
+ --type user_feedback \
1913
+ --title "Short concrete title" \
1914
+ --body "What happened, what was expected, and why it matters" \
1915
+ --command "Command or workflow observed" \
1916
+ --expected "Expected result" \
1917
+ --actual "Actual result" \
1918
+ --proof-needed "What would prove this is handled" \
1919
+ --surface cli,docs \
1920
+ --evidence trace:TRACE_ID \
1921
+ --severity medium \
1922
+ --confidence high \
1923
+ --next-state watch \
1924
+ --json
1925
+ ```
1926
+
1927
+ Hosted feedback authenticates the same way as other hosted commands: saved
1928
+ public CLI config from default signup, `IMAGE_SKILL_TOKEN`, or
1929
+ `--token-stdin`. If guide/signup already saved config, run `feedback create`
1930
+ normally; no raw token copy step is required. If the runtime uses its own
1931
+ secret store, prefer `IMAGE_SKILL_TOKEN` or `--token-stdin`. Do not paste tokens
1932
+ into feedback title, body, evidence, issues, or logs. Feedback persists through
1933
+ `https://api.luxin.sh/v1/feedback`. The hosted API fails closed if
1934
+ durable hosted feedback storage is unavailable.
1935
+
1936
+ JSON errors may include `error.recovery` with machine-readable fields such as
1937
+ `required_flag`, `suggested_command`, `docs_url`, or `retry_after_seconds`.
1938
+ Agents should prefer those fields over parsing prose error messages. For
1939
+ example, `BUDGET_REQUIRES_CONFIRMATION` returns
1940
+ `required_flag: "--accept-unknown-cost"`.
1941
+ Quota/payment recovery also includes `error.recovery.top_up`: its
1942
+ `quote_command` is copy-runnable and creates an authenticated live-money
1943
+ quote/payment object without paying, settling a wallet transfer, debiting
1944
+ credits, calling a provider, or writing media. Only the later buy/status and
1945
+ wallet/checkout completion steps can spend money.
1946
+
1947
+ `whoami`, `usage quota`, `quota`, `credits quote`, `credits buy`,
1948
+ `credits status`, `create`, `activity list`,
1949
+ `activity show`, and `feedback create` accept `--token-stdin` for stdin-based
1950
+ secret handoff.
1951
+ `credits methods` and `credits packs list` do not require auth.
1952
+
1953
+ Feedback should avoid raw prompts, hosted tokens, provider keys, generated
1954
+ image bytes, source image bytes, and private user data.
1955
+
1956
+ Hosted API equivalent:
1957
+
1958
+ ```bash
1959
+ curl -sS https://api.luxin.sh/v1/feedback \
1960
+ -H "authorization: Bearer $IMAGE_SKILL_TOKEN" \
1961
+ -H "content-type: application/json" \
1962
+ -d '{
1963
+ "type": "user_feedback",
1964
+ "title": "Short concrete title",
1965
+ "body": "What happened, what was expected, and why it matters",
1966
+ "command": "Command or workflow observed",
1967
+ "expected": "Expected result",
1968
+ "actual": "Actual result",
1969
+ "proof_needed": "What would prove this is handled",
1970
+ "surface": ["cli", "docs"],
1971
+ "evidence": ["trace:TRACE_ID"],
1972
+ "severity": "medium",
1973
+ "confidence": "high",
1974
+ "next_state": "watch"
1975
+ }'
1976
+ ```
1977
+
1978
+ ### Planned Resource Commands
1979
+
1980
+ `jobs list`, `assets list`, `assets delete`, and async job cancellation are
1981
+ planned public resource commands. They are not part of the current public
1982
+ allowlist until the hosted service backs them and this contract lists their
1983
+ exact command shapes. `activity list/show` is available now for ledger
1984
+ readback, but it is not a substitute for future job listing, cancellation, or
1985
+ retry controls.