luxin-cli 0.2.1 → 0.2.3

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/CHANGELOG.md CHANGED
@@ -6,6 +6,126 @@ provenance; this file is the human- and agent-readable release map.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.2.3 - 2026-08-04
10
+
11
+ - Release (self-fund/recovery): the wall now offers a human-funding handoff
12
+ instead of only a rail no external agent could walk (#2201). Both wall types
13
+ — credits depleted and daily job cap reached — route through
14
+ `QUOTA_EXCEEDED`, and the recovery envelope now carries
15
+ `error.recovery.human_handoff`: a copy-runnable `luxin claim code --json`,
16
+ typed `no_spend`, with the honest instruction to hand `data.dashboard_url`
17
+ (and nothing else — never the token, never the raw code) to your human, who
18
+ funds credits at the dashboard in about a minute. With no wallet evidence —
19
+ the external default — that handoff leads `error.recovery.suggested_command`
20
+ and `error.recovery.suggested_commands`; the agent-native x402 quote/buy rail
21
+ stays listed and `top_up.preferred_payment_method`
22
+ (`stripe_x402.exact.usdc`) is unchanged. New `error.recovery.delegated_spend`
23
+ (`state`, `per_tx_cap_usd`, `agent_day_remaining_usd`, `requires_wallet`)
24
+ lets an agent tell whether it can settle x402 itself before it stops at the
25
+ wall; it defaults to `state: "unknown"`, and when a caller proves delegated
26
+ spend is available the x402 quote leads instead. The credits-depleted wall
27
+ message — the majority wall — now names the price (a ~$5 top-up of 500
28
+ credits, pack `starter-500`), the concrete next step, and both paths, at the
29
+ quality the daily-cap message already had. The packaged CLI rewrites the
30
+ handoff command through your invocation prefix, so what the wall prints is
31
+ runnable as printed.
32
+ - Release (honest messaging): the `create --guide` / `edit --guide`
33
+ `quota_required` blocker is now trigger-aware (#2200). It used to always emit
34
+ the credits-shortfall line ("Selected first image requires N credits; current
35
+ remaining credits are M") even when the trigger was the daily job cap, so an
36
+ agent holding spare credits read a message that was simply wrong about why it
37
+ was blocked. The blocker now mirrors the stage's credit-first ordering:
38
+ credits only outrank the daily cap when they are genuinely short, and
39
+ otherwise the message names the real trigger — "You've reached today's job
40
+ allowance (X/day); a top-up raises your daily allowance so you can keep
41
+ creating now" — matching the hosted daily-cap copy.
42
+ - Release (no-spend mode): `create --guide` and `edit --guide` accept an opt-in
43
+ `--no-spend` output mode (#2194). A cold-agent no-spend study got a guide
44
+ response that repeatedly embedded live create, quote, buy, and payment
45
+ command templates, which buried the safe dry-run and raised the chance of
46
+ picking a prohibited action. With `--no-spend`,
47
+ `data.no_spend_output_mode.enabled` is `true` and the live funding templates
48
+ are omitted — `data.self_fund_next_command`,
49
+ `data.self_fund_next_command_label`, `data.self_fund_handoff`,
50
+ `data.self_fund_preparation`, and `data.checks.payments.suggested_commands`,
51
+ each named in `data.no_spend_output_mode.suppressed_fields`. The dry-run
52
+ command (`data.recommended_no_spend_command` / `data.no_spend_next_command`)
53
+ and the `provider_call` / `credit_debit` / `media_write` false proof in
54
+ `data.mutation` are retained. The funding path stays discoverable without
55
+ dominating via `data.no_spend_output_mode.self_fund_discovery`:
56
+ `rerun_with_funding_command` re-runs the same guide without `--no-spend`, and
57
+ `inspect_methods_command` is a read-only, no-spend payment-method
58
+ inspection. `--no-spend` is a guide output mode: outside `--guide` it is
59
+ rejected with the pointer to `create --dry-run` for a no-spend planned job.
60
+ `luxin create --help` and the packaged `cli.md` / `commands.json` carry the
61
+ flag.
62
+ - Release (trust/billing): a completed, charged job always surfaces an asset
63
+ (#2107). A live create/edit reserves credit before calling the provider and
64
+ settles on the provider's success envelope — but a provider that answered
65
+ SUCCESS with an empty or planned-only asset list used to settle the
66
+ reservation and commit a charged, asset-less job, so the agent was billed for
67
+ nothing and had no recoverable job or asset. The runner now requires at least
68
+ one real (non-planned) asset before settling: otherwise it releases the
69
+ reserved credit and returns a retryable `PROVIDER_COMPLETED_WITHOUT_ASSET`
70
+ failure instead of committing the charge. Nothing to change on your side —
71
+ the debit-without-media outcome is gone.
72
+ - Release (guide reliability): the `create --guide` executable-default read is
73
+ guarded against the shape the hosted registry actually returns (#2109).
74
+ `GET /v1/models` serves the compact model-summary rows, which carry
75
+ `model_execution_status` as a flat field rather than nested under
76
+ `execution`; a nested-only read failed every row's executable check and
77
+ dead-ended the guide at `no_executable_model` even though an executable
78
+ default existed and an explicit `create --dry-run --model fal.bagel` still
79
+ planned for zero credits. The flat-reading fix shipped earlier, but every
80
+ guide fixture used the nested shape, so a regression would have passed CI.
81
+ This release adds a faithful regression test serving the compact/flat shape
82
+ and asserting `ready_to_create` with the executable default selected.
83
+ - Resolved (0.2.2 known limitation): the `dashboard.claim` grant backfill
84
+ landed (#2184), so `luxin claim code` no longer answers `CAPABILITY_DENIED`
85
+ for agents whose tokens predate the hosted dashboard plane. That matters more
86
+ now that the wall itself recommends the command.
87
+ - Release (hosted parity): the Stripe reconciliation sweep is rail-aware and
88
+ transitions confirmed-unsettled pending attempts older than its abandonment
89
+ window to a terminal `expired` state with an audit trail (#2160). Settled
90
+ attempts are never abandoned and live-money retrieval failures still fail
91
+ loudly. No packaged CLI command changed for this; stale open quotes on your
92
+ account simply stop lingering as pending forever.
93
+ - No payment caps, wallet settlement, provider spend, dist-tag mutation, or
94
+ media generation behavior changed in this release bump beyond the
95
+ debited-no-asset release path above, which only ever refunds.
96
+
97
+ ## 0.2.2 - 2026-07-30
98
+
99
+ - Release (retention/self-fund): publish the human handoff from #2181. New verb
100
+ `luxin claim code` mints a single-use, 15-minute dashboard link for the
101
+ authenticated agent's human and hands back `data.dashboard_url` — give your
102
+ human that link and they can watch your work and fund your credits there,
103
+ signing in with nothing but the link (no email, no password, no provider
104
+ billing setup). The mint envelope teaches the handoff in-band rather than only
105
+ in docs: `data.human_handoff` carries
106
+ `share_field: "data.dashboard_url"` and `never_share: ["token", "code"]`
107
+ alongside a warning with the same sentence, so an agent that never reads
108
+ `cli.md` still learns to send the link and nothing else. The code rides in the
109
+ URL fragment (`#code=...`), which browsers never send to a server, so sharing
110
+ the link intact keeps the credential out of server logs and analytics.
111
+ - Release (activation): create and edit successes that produced real durable
112
+ media now carry `data.next_actions.share_with_human` — the same copy-runnable
113
+ `luxin claim code --json`, typed no-spend like the existing `inspect_job` /
114
+ `inspect_asset` / `iterate_edit` / `self_fund` actions — so the handoff is
115
+ offered at the moment finished work exists to show. Dry runs never carry it:
116
+ inviting a human to look at a plan is the wrong moment for the funding ask.
117
+ - Release (contract surfaces): `luxin claim` usage widens to
118
+ `luxin claim <request|code> --json`, `claim code` joins root help with its own
119
+ help entry, and the packaged contract picks up the matching sections —
120
+ `cli.md` `#luxin-claim-code`, a "Show your human" section in `SKILL.md`, and
121
+ step `7a. Human handoff` plus `luxin claim code --json` in `llms.txt`. No
122
+ payment caps, wallet settlement, provider spend, hosted deploys, production
123
+ writes, or media generation behavior changed in this release bump.
124
+ - Known limitation: `claim code` requires the `dashboard.claim` grant, which is
125
+ persisted per token at signup. Tokens minted before the hosted dashboard
126
+ plane shipped do not carry it and answer `CAPABILITY_DENIED` until an
127
+ additive grant backfill runs; agents that sign up now carry the grant.
128
+
9
129
  ## 0.2.1 - 2026-07-28
10
130
 
11
131
  - Release (activation/self-fund): publish the first `luxin-cli` payload since
package/SKILL.md CHANGED
@@ -228,6 +228,20 @@ receipts to Luxin.
228
228
 
229
229
  Do not silently downgrade to the cheapest model to avoid payment when the user asked for quality or is willing to pay. Quote the needed credits and use the rail above.
230
230
 
231
+ ## Show your human
232
+
233
+ When you have real work to show and need it funded, hand your human a dashboard link:
234
+
235
+ ```bash
236
+ luxin claim code --json
237
+ ```
238
+
239
+ Give them `data.dashboard_url` and nothing else. They get a read-only view of your jobs, assets, quota, and activity, plus the ability to open a credit checkout for you. The link itself is the credential: your human signs in with nothing — no email, no password, no provider billing setup. Never share your token, and never quote the raw `data.code` in prompts, logs, issues, or feedback: the code is the whole credential. It rides in the URL fragment (`#code=...`), which browsers never send to a server, so share the link intact rather than rebuilding it as a query string.
240
+
241
+ The code is single-use and expires (`data.ttl_seconds`, currently 15 minutes); the human session it opens lasts days. So one code is normally enough — reuse an unexpired `dashboard_url` instead of re-minting, and expect `DASHBOARD_CODE_RATE_LIMITED` past 30 codes per agent per hour. Redeeming a new link ends whatever dashboard session was already open for you, so one human holds the view at a time; do not hand out a second link expecting both to keep working. `claim code` needs the `dashboard.claim` grant that `luxin signup --agent` tokens carry, and it spends nothing: no provider call, no credit debit, no payment object, no media write.
242
+
243
+ Best moment: right after a create or edit produced real media, where the success envelope already carries `data.next_actions.share_with_human` with this command and `share_field: "data.dashboard_url"`. A human who can see finished work is a human who will fund the next run. Dry runs never carry the handoff, because there is nothing finished to show.
244
+
231
245
  ## Models and capability-preserving parameters
232
246
 
233
247
  `models show MODEL_ID` is the first detailed discovery surface for agents. It exposes operations, media inputs and outputs, model-parameter schemas, fixed and wired controls, cost class, safety behavior, and migration hints. Treat its output as the source of truth for what a model supports. Do not infer one model's parameter surface from another model.
@@ -293,7 +307,9 @@ luxin activity show EVENT_OR_JOB_OR_ASSET_OR_FEEDBACK
293
307
 
294
308
  After a successful hosted create/edit, prefer `data.next_actions` when present:
295
309
  `inspect_job` and `inspect_asset` are no-spend recovery commands,
296
- `iterate_edit` reuses the asset, and `self_fund` promotes a copy-runnable
310
+ `iterate_edit` reuses the asset, `share_with_human` is the no-spend
311
+ `luxin claim code --json` dashboard handoff (see "Show your human"), and
312
+ `self_fund` promotes a copy-runnable
297
313
  top-up quote command when `quota.top_up.available` is true. Its `recommended`
298
314
  flag and mirrored top-up `urgency`, `urgency_score`, and `urgency_reasons` say
299
315
  whether the agent should act now, while `first_safe_command` plus
package/bin/luxin.mjs CHANGED
@@ -15,7 +15,7 @@ import { Readable } from "node:stream";
15
15
  import { pipeline } from "node:stream/promises";
16
16
  import os from "node:os";
17
17
 
18
- const VERSION = "0.2.1";
18
+ const VERSION = "0.2.3";
19
19
  const PACKAGE_NAME = "luxin";
20
20
  const DEFAULT_API_BASE_URL = "https://api.luxin.sh";
21
21
  const DEFAULT_DOCS_BASE_URL = "https://luxin.sh";
@@ -338,6 +338,7 @@ function commandHelpByKey(key) {
338
338
  "trust",
339
339
  "signup --agent --agent-name NAME --runtime RUNTIME",
340
340
  "claim request --contact INBOX",
341
+ "claim code",
341
342
  "whoami",
342
343
  "usage quota",
343
344
  "quota",
@@ -400,9 +401,9 @@ function commandHelpByKey(key) {
400
401
  },
401
402
  claim: {
402
403
  command: "luxin claim help",
403
- usage: "luxin claim request --contact AGENT_OR_OPERATOR_INBOX --json",
404
+ usage: "luxin claim <request|code> --json",
404
405
  docs_url: "https://luxin.sh/cli.md#luxin-claim-request",
405
- subcommands: ["request"],
406
+ subcommands: ["request", "code"],
406
407
  },
407
408
  "claim request": {
408
409
  command: "luxin claim request help",
@@ -411,6 +412,14 @@ function commandHelpByKey(key) {
411
412
  required_flags: ["--contact"],
412
413
  optional_flags: ["--token-stdin"],
413
414
  },
415
+ "claim code": {
416
+ command: "luxin claim code help",
417
+ usage: "luxin claim code --json",
418
+ docs_url: "https://luxin.sh/cli.md#luxin-claim-code",
419
+ description:
420
+ "Mint a single-use, short-lived dashboard link and hand data.dashboard_url to your human: they can watch your work and fund your credits there. No inputs beyond auth; no spend.",
421
+ optional_flags: ["--token-stdin"],
422
+ },
414
423
  auth: {
415
424
  command: "luxin auth help",
416
425
  usage: "luxin auth <status|save|logout> --json",
@@ -543,6 +552,7 @@ function commandHelpByKey(key) {
543
552
  docs_url: "https://luxin.sh/cli.md#luxin-create",
544
553
  optional_flags: [
545
554
  "--guide",
555
+ "--no-spend",
546
556
  "--dry-run",
547
557
  "--model",
548
558
  "--aspect-ratio",
@@ -965,12 +975,15 @@ async function signup(argv) {
965
975
  // unclaimed; attaching a contact is not inbox-ownership verification.
966
976
  async function claim(argv) {
967
977
  const [subcommand, ...rest] = argv;
978
+ if (subcommand === "code") {
979
+ return await claimCode(rest);
980
+ }
968
981
  if (subcommand !== "request") {
969
982
  return failure(
970
983
  "luxin claim",
971
984
  2,
972
985
  "INVALID_ARGUMENTS",
973
- "claim requires the request subcommand",
986
+ "claim requires the request or code subcommand",
974
987
  false,
975
988
  {
976
989
  suggested_command: CLAIM_REQUEST_SUGGESTED_COMMAND,
@@ -1008,6 +1021,25 @@ async function claim(argv) {
1008
1021
  });
1009
1022
  }
1010
1023
 
1024
+ // Claim code (#2088 S1d): mints the single-use, short-TTL dashboard link the
1025
+ // agent hands to its HUMAN — they watch the work and fund the credits there.
1026
+ // The code rides in the URL fragment of data.dashboard_url, which never
1027
+ // reaches servers, logs, or analytics. Hand over the link and nothing else.
1028
+ async function claimCode(argv) {
1029
+ const args = parseArgs(argv);
1030
+ const token = await resolveToken(args);
1031
+ if (!token.ok) {
1032
+ return token.result;
1033
+ }
1034
+ return apiRequest({
1035
+ command: "luxin claim code",
1036
+ method: "POST",
1037
+ apiBaseUrl: apiBase(args),
1038
+ path: "/v1/dashboard-codes",
1039
+ token: token.token,
1040
+ });
1041
+ }
1042
+
1011
1043
  function rewriteSignupContactFailure(result) {
1012
1044
  const error = result.envelope.error;
1013
1045
  if (
@@ -1953,13 +1985,66 @@ async function createGuide(args, options = {}) {
1953
1985
  paymentSummary,
1954
1986
  selfFundPreparation,
1955
1987
  );
1988
+ // #2194: no-spend output mode. Omit the live self-fund and payment command
1989
+ // templates when the agent opts into a no-spend/dry-run study so the safe
1990
+ // dry-run is not buried under quote/buy/payment workflow commands. Retain the
1991
+ // dry-run command and the mutation proof, and keep the self-fund path
1992
+ // discoverable via self_fund_discovery instead of dominating the response.
1993
+ const noSpendOutputMode = flagBool(args, "no-spend");
1994
+ const paymentSummaryOutput = noSpendOutputMode
1995
+ ? { ...paymentSummary, suggested_commands: [] }
1996
+ : paymentSummary;
1997
+ const selfFundHandoffOutput = noSpendOutputMode ? null : selfFundHandoff;
1998
+ const selfFundPreparationOutput = noSpendOutputMode
1999
+ ? null
2000
+ : selfFundPreparation;
2001
+ const selfFundNextCommandOutput = noSpendOutputMode
2002
+ ? null
2003
+ : selfFundNextCommand;
2004
+ const selfFundNextCommandLabelOutput = noSpendOutputMode
2005
+ ? null
2006
+ : selfFundNextCommandLabel;
2007
+ const noSpendOutputModeData = noSpendOutputMode
2008
+ ? {
2009
+ enabled: true,
2010
+ suppressed_fields: [
2011
+ "self_fund_next_command",
2012
+ "self_fund_next_command_label",
2013
+ "self_fund_handoff",
2014
+ "self_fund_preparation",
2015
+ "checks.payments.suggested_commands",
2016
+ ],
2017
+ self_fund_discovery: {
2018
+ rerun_with_funding_command: renderGuideCommand(
2019
+ trimmedPrompt.length > 0 ? trimmedPrompt : "PROMPT",
2020
+ explicitApiBaseUrl(args),
2021
+ guideCommandPrefix,
2022
+ {
2023
+ operation: guideOperation,
2024
+ inputReference: options.inputReference,
2025
+ modelId: requestedModelId,
2026
+ providerId: requestedProviderId,
2027
+ intent: requestedIntentFlag,
2028
+ maxEstimatedUsdPerImage,
2029
+ modelParametersJson: requestedModelParametersJson,
2030
+ },
2031
+ ),
2032
+ inspect_methods_command: escapeHatches.payment_methods,
2033
+ note: "No-spend output mode omits live self-fund and payment command templates. Re-run this guide without --no-spend to surface them; data.escape_hatches.payment_methods stays available for read-only, no-spend payment-method inspection. provider_call, credit_debit, and media_write remain false (see data.mutation).",
2034
+ },
2035
+ }
2036
+ : {
2037
+ enabled: false,
2038
+ suppressed_fields: [],
2039
+ self_fund_discovery: null,
2040
+ };
1956
2041
  const guideRecovery = createGuideRecovery(stage, {
1957
2042
  blocker,
1958
2043
  nextCommand,
1959
2044
  noSpendNextCommand,
1960
2045
  afterNext,
1961
2046
  escapeHatches,
1962
- selfFundNextCommand,
2047
+ selfFundNextCommand: selfFundNextCommandOutput,
1963
2048
  });
1964
2049
  return createGuideSuccess(command, quota?.envelope.actor ?? null, {
1965
2050
  schema:
@@ -2009,7 +2094,7 @@ async function createGuide(args, options = {}) {
2009
2094
  ? null
2010
2095
  : (quota.envelope.error?.code ?? "quota_unavailable"),
2011
2096
  },
2012
- payments: paymentSummary,
2097
+ payments: paymentSummaryOutput,
2013
2098
  },
2014
2099
  selection:
2015
2100
  selected === null
@@ -2059,13 +2144,14 @@ async function createGuide(args, options = {}) {
2059
2144
  recommended_no_spend_command: noSpendNextCommand,
2060
2145
  recommended_no_spend_command_label: noSpendNextCommandLabel,
2061
2146
  recommended_no_spend_command_effect: noSpendNextCommandEffect,
2062
- self_fund_next_command: selfFundNextCommand,
2063
- self_fund_next_command_label: selfFundNextCommandLabel,
2064
- self_fund_handoff: selfFundHandoff,
2065
- self_fund_preparation: selfFundPreparation,
2147
+ self_fund_next_command: selfFundNextCommandOutput,
2148
+ self_fund_next_command_label: selfFundNextCommandLabelOutput,
2149
+ self_fund_handoff: selfFundHandoffOutput,
2150
+ self_fund_preparation: selfFundPreparationOutput,
2066
2151
  after_next: afterNext,
2067
2152
  auth_handoff: authHandoff,
2068
2153
  escape_hatches: escapeHatches,
2154
+ no_spend_output_mode: noSpendOutputModeData,
2069
2155
  mutation: {
2070
2156
  provider_call: false,
2071
2157
  hosted_create: false,
@@ -3358,7 +3444,24 @@ function createGuideBlocker(stage, input) {
3358
3444
  };
3359
3445
  }
3360
3446
  if (stage === "quota_required") {
3361
- const remaining = quotaRemainingCredits(input.quota?.envelope.data ?? null);
3447
+ const quotaData = input.quota?.envelope.data ?? null;
3448
+ const remaining = quotaRemainingCredits(quotaData);
3449
+ // Mirror createGuideStage's credit-first ordering: credits only outrank the
3450
+ // daily-job cap when they are genuinely short. Agents that hold spare
3451
+ // credits but hit the daily allowance (issues #2103, #2148) must be told the
3452
+ // honest trigger, not a credits-shortfall line that reads as wrong to them
3453
+ // (same confusion class as #1193).
3454
+ const creditsShort =
3455
+ input.estimatedCredits !== null &&
3456
+ remaining !== null &&
3457
+ remaining < input.estimatedCredits;
3458
+ const dailyJobs = quotaData?.daily_jobs;
3459
+ if (!creditsShort && dailyJobs !== undefined && dailyJobs.remaining <= 0) {
3460
+ return {
3461
+ code: "quota_required",
3462
+ message: `You've reached today's job allowance (${dailyJobs.cap}/day); a top-up raises your daily allowance so you can keep creating now.`,
3463
+ };
3464
+ }
3362
3465
  return {
3363
3466
  code: "quota_required",
3364
3467
  message: `Selected first image requires ${input.estimatedCredits ?? "unknown"} credits; current remaining credits are ${remaining ?? "unknown"}.`,
@@ -4408,6 +4511,12 @@ async function create(argv) {
4408
4511
  if (flagBool(args, "guide")) {
4409
4512
  return createGuide(args);
4410
4513
  }
4514
+ if (flagBool(args, "no-spend")) {
4515
+ return invalid(
4516
+ "luxin create",
4517
+ "create --no-spend is a guide output mode; combine it with --guide, or use create --dry-run for a no-spend planned job",
4518
+ );
4519
+ }
4411
4520
  const prompt = await promptValue(args);
4412
4521
  if (!prompt.ok) {
4413
4522
  return prompt.result;
@@ -4555,6 +4664,12 @@ async function edit(argv) {
4555
4664
  inputReference: input,
4556
4665
  });
4557
4666
  }
4667
+ if (flagBool(args, "no-spend")) {
4668
+ return invalid(
4669
+ "luxin edit",
4670
+ "edit --no-spend is a guide output mode; combine it with --guide, or use edit --dry-run for a no-spend planned job",
4671
+ );
4672
+ }
4558
4673
  if (input === undefined) {
4559
4674
  return invalid(
4560
4675
  "luxin edit",
@@ -6936,6 +7051,16 @@ function quotaRecoveryWithCopyRunnableCommands(recovery, commandPrefix) {
6936
7051
  ),
6937
7052
  }
6938
7053
  : {}),
7054
+ ...(recovery.human_handoff &&
7055
+ typeof recovery.human_handoff === "object" &&
7056
+ typeof recovery.human_handoff.command === "string"
7057
+ ? {
7058
+ human_handoff: {
7059
+ ...recovery.human_handoff,
7060
+ command: render(recovery.human_handoff.command),
7061
+ },
7062
+ }
7063
+ : {}),
6939
7064
  top_up: quotaTopUpWithCopyRunnableCommands(recovery.top_up, commandPrefix),
6940
7065
  };
6941
7066
  }
package/cli.md CHANGED
@@ -175,6 +175,68 @@ printf '%s\n' "$IMAGE_SKILL_TOKEN" | luxin usage quota --token-stdin --json
175
175
  `--api-base-url` is an advanced preview/test override; production public agents
176
176
  should omit it.
177
177
 
178
+ ### `luxin claim code`
179
+
180
+ Mints a single-use, short-lived dashboard link for the authenticated agent's
181
+ human. This is the human handoff: give `data.dashboard_url` to your human and
182
+ they can watch your work and fund your credits there. The link itself is the
183
+ credential: your human signs in with nothing — no email, no password, no
184
+ provider billing setup.
185
+
186
+ ```bash
187
+ luxin claim code --json
188
+ ```
189
+
190
+ ```json
191
+ {
192
+ "ok": true,
193
+ "command": "luxin claim code",
194
+ "data": {
195
+ "mode": "hosted_auth",
196
+ "agent_id": "agt_...",
197
+ "code": "dc_...",
198
+ "dashboard_url": "https://luxin.sh/dashboard#code=dc_...",
199
+ "expires_at": "2026-07-30T18:15:00.000Z",
200
+ "ttl_seconds": 900,
201
+ "single_use": true,
202
+ "human_handoff": {
203
+ "purpose": "hand_dashboard_link_to_human",
204
+ "audience": "human",
205
+ "share_field": "data.dashboard_url",
206
+ "message": "give dashboard_url to your human: they can watch your work and fund your credits there. Send the link only — never your token, and never the raw code.",
207
+ "never_share": ["token", "code"]
208
+ }
209
+ }
210
+ }
211
+ ```
212
+
213
+ Hand over `data.dashboard_url` and nothing else. Never hand over your token,
214
+ and never quote the raw `data.code` in prompts, logs, issue text, or feedback:
215
+ the code is the whole credential. The code travels in the URL fragment
216
+ (`#code=...`), which browsers never send to a server, so it stays out of server
217
+ logs and analytics — keep it that way by sharing the link intact rather than
218
+ rebuilding it as a query string.
219
+
220
+ The code is single-use and expires (`data.ttl_seconds`, currently 15 minutes).
221
+ The dashboard is read-only over your work — jobs, assets, quota, activity — plus
222
+ the ability to open a credit checkout for you. It cannot create, edit, upload,
223
+ or spend as you. Once your human has opened the link their session lasts days,
224
+ so one code is normally all that is needed; mint a fresh one when the link
225
+ expires unused. Redeeming a new link ends whatever dashboard session was
226
+ already open for you, so one human holds the view at a time — do not hand out
227
+ a second link expecting both to keep working. Minting is capped at 30 codes per
228
+ agent per hour and answers `DASHBOARD_CODE_RATE_LIMITED` past that — reuse an
229
+ unexpired `dashboard_url` instead of re-minting per message.
230
+
231
+ `claim code` requires the `dashboard.claim` grant, which restricted tokens
232
+ minted by `luxin signup --agent` carry. It never spends: no provider call, no
233
+ credit debit, no payment object, no media write.
234
+
235
+ Best moment to run it: right after a create or edit produced real media. That
236
+ success envelope carries `data.next_actions.share_with_human` with this exact
237
+ command, because a human who can see finished work is a human who will fund the
238
+ next run.
239
+
178
240
  ### First Run Guide Loop
179
241
 
180
242
  Use the no-spend guide first. It is the only required first command for a fresh
@@ -293,6 +355,26 @@ step.
293
355
  `data.auth_handoff.next_command.with_env` or
294
356
  `data.auth_handoff.next_command.with_stdin` so auth follows the create.
295
357
 
358
+ For a no-spend or dry-run study, add `--no-spend` to `create --guide` for a
359
+ compact output mode. `data.no_spend_output_mode.enabled` is then `true` and the
360
+ live self-fund and payment command templates are omitted:
361
+ `data.self_fund_next_command`, `data.self_fund_next_command_label`,
362
+ `data.self_fund_handoff`, `data.self_fund_preparation`, and
363
+ `data.checks.payments.suggested_commands` are suppressed (each is listed in
364
+ `data.no_spend_output_mode.suppressed_fields`), so the safe dry-run is not
365
+ buried under quote/buy/payment workflow commands. The response still centers on
366
+ the dry-run command (`data.recommended_no_spend_command`, aliased by
367
+ `data.no_spend_next_command`), and the provider-call, credit-debit, and
368
+ media-write false proof in `data.mutation` is retained. The self-fund path
369
+ stays discoverable without dominating via
370
+ `data.no_spend_output_mode.self_fund_discovery`: its
371
+ `rerun_with_funding_command` re-runs the guide without `--no-spend` to surface
372
+ the funding templates, and `inspect_methods_command` is a read-only, no-spend
373
+ payment-method inspection (the same command as
374
+ `data.escape_hatches.payment_methods`). `--no-spend` is a guide output mode; it
375
+ requires `--guide`, and for a no-spend planned job outside the guide use
376
+ `create --dry-run`.
377
+
296
378
  Manual escape hatches are not prerequisites. Use them only when
297
379
  `data.next_command` / `data.escape_hatches` asks, or when the task genuinely
298
380
  needs deeper capability, quota, payment, or planning detail:
@@ -1642,6 +1724,13 @@ The quote command omits `--idempotency-key` so the public CLI generates and
1642
1724
  returns one for retry safety before the agent follows the quote response into
1643
1725
  `credits buy` and `credits status`.
1644
1726
 
1727
+ When a create or edit produced a real durable asset, the same envelope carries
1728
+ `data.next_actions.share_with_human`: a no-spend, copy-runnable
1729
+ `luxin claim code --json` plus `share_field: "data.dashboard_url"`. Run it and
1730
+ hand your human the resulting `dashboard_url` — they can watch this work and
1731
+ fund your credits from it. Dry runs never carry it, because there is nothing
1732
+ finished to show.
1733
+
1645
1734
  Provider/model names in this paragraph are preview provenance, not the primary
1646
1735
  public UX. The public selection surface should be Luxin capabilities and
1647
1736
  model-parameter schemas; provider/model details belong in explicit
package/commands.json CHANGED
@@ -33,7 +33,7 @@
33
33
  "surface": "hosted_cli",
34
34
  "mutation": true,
35
35
  "spend": false,
36
- "subcommands": ["request"]
36
+ "subcommands": ["request", "code"]
37
37
  },
38
38
  {
39
39
  "id": "whoami",
@@ -166,6 +166,7 @@
166
166
  "trust",
167
167
  "signup --agent --agent-name NAME --runtime RUNTIME",
168
168
  "claim request --contact INBOX",
169
+ "claim code",
169
170
  "whoami",
170
171
  "usage quota",
171
172
  "quota",
@@ -238,9 +239,9 @@
238
239
  "key": "claim",
239
240
  "help": {
240
241
  "command": "luxin claim help",
241
- "usage": "luxin claim request --contact AGENT_OR_OPERATOR_INBOX --json",
242
+ "usage": "luxin claim <request|code> --json",
242
243
  "docs_url": "https://luxin.sh/cli.md#luxin-claim-request",
243
- "subcommands": ["request"]
244
+ "subcommands": ["request", "code"]
244
245
  }
245
246
  },
246
247
  {
@@ -253,6 +254,16 @@
253
254
  "optional_flags": ["--token-stdin"]
254
255
  }
255
256
  },
257
+ {
258
+ "key": "claim code",
259
+ "help": {
260
+ "command": "luxin claim code help",
261
+ "usage": "luxin claim code --json",
262
+ "docs_url": "https://luxin.sh/cli.md#luxin-claim-code",
263
+ "description": "Mint a single-use, short-lived dashboard link and hand data.dashboard_url to your human: they can watch your work and fund your credits there. No inputs beyond auth; no spend.",
264
+ "optional_flags": ["--token-stdin"]
265
+ }
266
+ },
256
267
  {
257
268
  "key": "whoami",
258
269
  "help": {
@@ -410,6 +421,7 @@
410
421
  "docs_url": "https://luxin.sh/cli.md#luxin-create",
411
422
  "optional_flags": [
412
423
  "--guide",
424
+ "--no-spend",
413
425
  "--dry-run",
414
426
  "--model",
415
427
  "--aspect-ratio",
package/llms.txt CHANGED
@@ -66,6 +66,7 @@ First-run guide loop:
66
66
  5a. When data.stage is quota_required, data.self_fund_handoff mirrors top-up urgency, urgency_score, and urgency_reasons, and exposes first_safe_command plus first_safe_command_effect. Run first_safe_command, usually luxin credits methods --json, for no-spend rail inspection before quote/buy when delegated spend authority is absent or unclear.
67
67
  6. If data.stage is ready_to_create, data.next_command is the first bounded live create. data.guide_warning.next_command_safety must be live_media_create_credit_debit, data.guide_warning.no_spend_safe must be false, data.guide_warning.spend_required must be true, and data.guide_warning.recommended_command_field must be recommended_no_spend_command. data.auth_ready.ready and data.auth_ready.next_command_auth_ready must be true; data.auth_ready.next_command_requires_auth must be true, and the command can reuse saved config, IMAGE_SKILL_TOKEN, or --token-stdin context without exposing a raw token. data.next_command_effect.label must be live_media_create_credit_debit and its provider_call, hosted_create, credit_debit, and media_write flags are true. data.no_spend_evaluation.stop_here must be true, data.no_spend_evaluation.next_command_is_live_create must be true, and data.no_spend_evaluation.recommended_command_field must be recommended_no_spend_command. Run data.next_command only when media spend is allowed. In no-spend evaluations, or when you only need to prove readiness without media/provider work, stop before data.next_command and run data.recommended_no_spend_command instead. data.recommended_no_spend_command must equal data.no_spend_next_command. data.no_spend_next_command_effect.label must be dry_run_planned_job_no_provider_call_no_credit_debit_no_media_write: no_spend, hosted_create_dry_run, planned_job, and plan_receipt are true; activity_event is job.planned; provider_call, credit_debit, and media_write are false. This dry-run may create a recoverable planned job/activity receipt but no provider execution, debit, downloadable asset, or media write. If the guide authenticated from env or stdin, prefer data.auth_handoff.next_command.with_env or data.auth_handoff.next_command.with_stdin so auth follows the live create. In guide cost output, cost.estimated_usd_per_image and cost.estimated_debit_usd_per_image are the Luxin debit dollars for one output; cost.estimated_provider_usd_per_image is only the upstream provider estimate. Use the guide's returned max_estimated_usd_per_image because it is sized to the credit debit the agent funds. Add --output-count N only after models show confirms the selected create model supports more than one output; credit_pricing.credits_required is the total debit across outputs, while max_estimated_usd_per_image remains a per-image Luxin debit guard.
68
68
  7. After create, prefer data.next_actions when present: inspect_job and inspect_asset are copy-runnable no-spend recovery commands, iterate_edit is the reusable-asset edit template, and self_fund is the promoted top-up quote handoff when quota.top_up.available is true. self_fund.recommended plus urgency, urgency_score, and urgency_reasons say whether to act now, and self_fund exposes first_safe_command plus first_safe_command_effect for no-spend rail inspection before quote/buy. When self_fund.recommended is true and the quote is copy-runnable, data.self_fund_next_command aliases data.next_actions.self_fund.quote_command and data.self_fund_next_command_effect proves the quote creates no provider call, hosted create, credit debit, media write, or wallet settlement. self_fund.quote_command is copy-runnable and omits --idempotency-key so the public CLI generates and returns one for retry safety; follow the quote response into buy/status. Otherwise use luxin jobs show JOB_ID to recover status, cost, safety, timestamps, and final assets; luxin assets get ASSET_URL_OR_ID --output ./result.png to fetch the generated asset without repeating provider work; and luxin activity list --subject JOB_ID to find ledger events, trace, usage, asset links, and any data.next_actions.self_fund handoff to cite or follow. Hosted asset-id assets show/get may also return data.next_actions.self_fund after generated work, so inspect that field before ending the session.
69
+ 7a. Human handoff. When a create or edit produced a real asset, data.next_actions.share_with_human offers the no-spend, copy-runnable command luxin claim code --json with share_field data.dashboard_url. Run it and give your human the returned data.dashboard_url: they get a read-only view of your jobs, assets, quota, and activity plus the ability to open a credit checkout for you. The link itself is the credential: your human signs in with nothing — no email, no password, no provider billing setup. Hand over data.dashboard_url only — never your token, and never the raw data.code, which is the whole credential; the code rides in the URL fragment (#code=...), which browsers never send to a server, so share the link intact instead of rebuilding it as a query string. The code is single-use and expires (data.ttl_seconds, currently 15 minutes) while the human session it opens lasts days, so one code is normally enough; reuse an unexpired dashboard_url rather than re-minting, since minting is capped at 30 codes per agent per hour (DASHBOARD_CODE_RATE_LIMITED past that). Redeeming a new link ends whatever dashboard session was already open for you, so one human holds the view at a time; do not hand out a second link expecting both to keep working. luxin claim code needs the dashboard.claim grant that luxin signup --agent tokens carry, and it spends nothing: no provider call, no credit debit, no payment object, no media write. Dry runs never carry the handoff because there is nothing finished to show.
69
70
  8. Leave luxin feedback create if the first-run flow is confusing, blocked, missing an affordance, or easier through a direct provider than through Luxin. Feedback auth uses saved config from default signup, IMAGE_SKILL_TOKEN, or --token-stdin; if signup or guide already saved config, run feedback create normally and do not copy a raw token. Never paste tokens into feedback title, body, evidence, issues, or logs. Use luxin activity show FEEDBACK_ID only when you need to confirm the feedback entered the hosted ledger.
70
71
 
71
72
  Manual escape hatches are not prerequisites. Use luxin doctor, luxin models list, luxin models show MODEL_ID, luxin whoami, luxin usage quota, luxin credits methods, luxin credits packs list, luxin credits quote, luxin credits buy, luxin credits status, luxin create --dry-run, and luxin edit --dry-run only when data.next_command or data.escape_hatches asks for them, or when the task genuinely needs deeper capability, quota, payment, or planning detail.
@@ -74,6 +75,7 @@ Core commands:
74
75
  - luxin doctor --json
75
76
  - luxin signup --agent --agent-name NAME --runtime RUNTIME --json
76
77
  - luxin claim request --contact AGENT_OR_OPERATOR_INBOX --json
78
+ - luxin claim code --json
77
79
  - luxin whoami --json
78
80
  - luxin usage quota --json
79
81
  - luxin quota --json (compatibility alias)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "luxin-cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Zero-setup durable creative-media CLI for agents (image + video + audio + 3D): guide-first creation, model and cost inspection, owned URLs, JSON recovery, payments, reusable assets, and feedback. Luxin is a creative-media runtime, unrelated to the luxon datetime library.",
5
5
  "type": "module",
6
6
  "private": false,
package/skill.md CHANGED
@@ -228,6 +228,20 @@ receipts to Luxin.
228
228
 
229
229
  Do not silently downgrade to the cheapest model to avoid payment when the user asked for quality or is willing to pay. Quote the needed credits and use the rail above.
230
230
 
231
+ ## Show your human
232
+
233
+ When you have real work to show and need it funded, hand your human a dashboard link:
234
+
235
+ ```bash
236
+ luxin claim code --json
237
+ ```
238
+
239
+ Give them `data.dashboard_url` and nothing else. They get a read-only view of your jobs, assets, quota, and activity, plus the ability to open a credit checkout for you. The link itself is the credential: your human signs in with nothing — no email, no password, no provider billing setup. Never share your token, and never quote the raw `data.code` in prompts, logs, issues, or feedback: the code is the whole credential. It rides in the URL fragment (`#code=...`), which browsers never send to a server, so share the link intact rather than rebuilding it as a query string.
240
+
241
+ The code is single-use and expires (`data.ttl_seconds`, currently 15 minutes); the human session it opens lasts days. So one code is normally enough — reuse an unexpired `dashboard_url` instead of re-minting, and expect `DASHBOARD_CODE_RATE_LIMITED` past 30 codes per agent per hour. Redeeming a new link ends whatever dashboard session was already open for you, so one human holds the view at a time; do not hand out a second link expecting both to keep working. `claim code` needs the `dashboard.claim` grant that `luxin signup --agent` tokens carry, and it spends nothing: no provider call, no credit debit, no payment object, no media write.
242
+
243
+ Best moment: right after a create or edit produced real media, where the success envelope already carries `data.next_actions.share_with_human` with this command and `share_field: "data.dashboard_url"`. A human who can see finished work is a human who will fund the next run. Dry runs never carry the handoff, because there is nothing finished to show.
244
+
231
245
  ## Models and capability-preserving parameters
232
246
 
233
247
  `models show MODEL_ID` is the first detailed discovery surface for agents. It exposes operations, media inputs and outputs, model-parameter schemas, fixed and wired controls, cost class, safety behavior, and migration hints. Treat its output as the source of truth for what a model supports. Do not infer one model's parameter surface from another model.
@@ -293,7 +307,9 @@ luxin activity show EVENT_OR_JOB_OR_ASSET_OR_FEEDBACK
293
307
 
294
308
  After a successful hosted create/edit, prefer `data.next_actions` when present:
295
309
  `inspect_job` and `inspect_asset` are no-spend recovery commands,
296
- `iterate_edit` reuses the asset, and `self_fund` promotes a copy-runnable
310
+ `iterate_edit` reuses the asset, `share_with_human` is the no-spend
311
+ `luxin claim code --json` dashboard handoff (see "Show your human"), and
312
+ `self_fund` promotes a copy-runnable
297
313
  top-up quote command when `quota.top_up.available` is true. Its `recommended`
298
314
  flag and mirrored top-up `urgency`, `urgency_score`, and `urgency_reasons` say
299
315
  whether the agent should act now, while `first_safe_command` plus
@@ -228,6 +228,20 @@ receipts to Luxin.
228
228
 
229
229
  Do not silently downgrade to the cheapest model to avoid payment when the user asked for quality or is willing to pay. Quote the needed credits and use the rail above.
230
230
 
231
+ ## Show your human
232
+
233
+ When you have real work to show and need it funded, hand your human a dashboard link:
234
+
235
+ ```bash
236
+ luxin claim code --json
237
+ ```
238
+
239
+ Give them `data.dashboard_url` and nothing else. They get a read-only view of your jobs, assets, quota, and activity, plus the ability to open a credit checkout for you. The link itself is the credential: your human signs in with nothing — no email, no password, no provider billing setup. Never share your token, and never quote the raw `data.code` in prompts, logs, issues, or feedback: the code is the whole credential. It rides in the URL fragment (`#code=...`), which browsers never send to a server, so share the link intact rather than rebuilding it as a query string.
240
+
241
+ The code is single-use and expires (`data.ttl_seconds`, currently 15 minutes); the human session it opens lasts days. So one code is normally enough — reuse an unexpired `dashboard_url` instead of re-minting, and expect `DASHBOARD_CODE_RATE_LIMITED` past 30 codes per agent per hour. Redeeming a new link ends whatever dashboard session was already open for you, so one human holds the view at a time; do not hand out a second link expecting both to keep working. `claim code` needs the `dashboard.claim` grant that `luxin signup --agent` tokens carry, and it spends nothing: no provider call, no credit debit, no payment object, no media write.
242
+
243
+ Best moment: right after a create or edit produced real media, where the success envelope already carries `data.next_actions.share_with_human` with this command and `share_field: "data.dashboard_url"`. A human who can see finished work is a human who will fund the next run. Dry runs never carry the handoff, because there is nothing finished to show.
244
+
231
245
  ## Models and capability-preserving parameters
232
246
 
233
247
  `models show MODEL_ID` is the first detailed discovery surface for agents. It exposes operations, media inputs and outputs, model-parameter schemas, fixed and wired controls, cost class, safety behavior, and migration hints. Treat its output as the source of truth for what a model supports. Do not infer one model's parameter surface from another model.
@@ -293,7 +307,9 @@ luxin activity show EVENT_OR_JOB_OR_ASSET_OR_FEEDBACK
293
307
 
294
308
  After a successful hosted create/edit, prefer `data.next_actions` when present:
295
309
  `inspect_job` and `inspect_asset` are no-spend recovery commands,
296
- `iterate_edit` reuses the asset, and `self_fund` promotes a copy-runnable
310
+ `iterate_edit` reuses the asset, `share_with_human` is the no-spend
311
+ `luxin claim code --json` dashboard handoff (see "Show your human"), and
312
+ `self_fund` promotes a copy-runnable
297
313
  top-up quote command when `quota.top_up.available` is true. Its `recommended`
298
314
  flag and mirrored top-up `urgency`, `urgency_score`, and `urgency_reasons` say
299
315
  whether the agent should act now, while `first_safe_command` plus
@@ -175,6 +175,68 @@ printf '%s\n' "$IMAGE_SKILL_TOKEN" | luxin usage quota --token-stdin --json
175
175
  `--api-base-url` is an advanced preview/test override; production public agents
176
176
  should omit it.
177
177
 
178
+ ### `luxin claim code`
179
+
180
+ Mints a single-use, short-lived dashboard link for the authenticated agent's
181
+ human. This is the human handoff: give `data.dashboard_url` to your human and
182
+ they can watch your work and fund your credits there. The link itself is the
183
+ credential: your human signs in with nothing — no email, no password, no
184
+ provider billing setup.
185
+
186
+ ```bash
187
+ luxin claim code --json
188
+ ```
189
+
190
+ ```json
191
+ {
192
+ "ok": true,
193
+ "command": "luxin claim code",
194
+ "data": {
195
+ "mode": "hosted_auth",
196
+ "agent_id": "agt_...",
197
+ "code": "dc_...",
198
+ "dashboard_url": "https://luxin.sh/dashboard#code=dc_...",
199
+ "expires_at": "2026-07-30T18:15:00.000Z",
200
+ "ttl_seconds": 900,
201
+ "single_use": true,
202
+ "human_handoff": {
203
+ "purpose": "hand_dashboard_link_to_human",
204
+ "audience": "human",
205
+ "share_field": "data.dashboard_url",
206
+ "message": "give dashboard_url to your human: they can watch your work and fund your credits there. Send the link only — never your token, and never the raw code.",
207
+ "never_share": ["token", "code"]
208
+ }
209
+ }
210
+ }
211
+ ```
212
+
213
+ Hand over `data.dashboard_url` and nothing else. Never hand over your token,
214
+ and never quote the raw `data.code` in prompts, logs, issue text, or feedback:
215
+ the code is the whole credential. The code travels in the URL fragment
216
+ (`#code=...`), which browsers never send to a server, so it stays out of server
217
+ logs and analytics — keep it that way by sharing the link intact rather than
218
+ rebuilding it as a query string.
219
+
220
+ The code is single-use and expires (`data.ttl_seconds`, currently 15 minutes).
221
+ The dashboard is read-only over your work — jobs, assets, quota, activity — plus
222
+ the ability to open a credit checkout for you. It cannot create, edit, upload,
223
+ or spend as you. Once your human has opened the link their session lasts days,
224
+ so one code is normally all that is needed; mint a fresh one when the link
225
+ expires unused. Redeeming a new link ends whatever dashboard session was
226
+ already open for you, so one human holds the view at a time — do not hand out
227
+ a second link expecting both to keep working. Minting is capped at 30 codes per
228
+ agent per hour and answers `DASHBOARD_CODE_RATE_LIMITED` past that — reuse an
229
+ unexpired `dashboard_url` instead of re-minting per message.
230
+
231
+ `claim code` requires the `dashboard.claim` grant, which restricted tokens
232
+ minted by `luxin signup --agent` carry. It never spends: no provider call, no
233
+ credit debit, no payment object, no media write.
234
+
235
+ Best moment to run it: right after a create or edit produced real media. That
236
+ success envelope carries `data.next_actions.share_with_human` with this exact
237
+ command, because a human who can see finished work is a human who will fund the
238
+ next run.
239
+
178
240
  ### First Run Guide Loop
179
241
 
180
242
  Use the no-spend guide first. It is the only required first command for a fresh
@@ -293,6 +355,26 @@ step.
293
355
  `data.auth_handoff.next_command.with_env` or
294
356
  `data.auth_handoff.next_command.with_stdin` so auth follows the create.
295
357
 
358
+ For a no-spend or dry-run study, add `--no-spend` to `create --guide` for a
359
+ compact output mode. `data.no_spend_output_mode.enabled` is then `true` and the
360
+ live self-fund and payment command templates are omitted:
361
+ `data.self_fund_next_command`, `data.self_fund_next_command_label`,
362
+ `data.self_fund_handoff`, `data.self_fund_preparation`, and
363
+ `data.checks.payments.suggested_commands` are suppressed (each is listed in
364
+ `data.no_spend_output_mode.suppressed_fields`), so the safe dry-run is not
365
+ buried under quote/buy/payment workflow commands. The response still centers on
366
+ the dry-run command (`data.recommended_no_spend_command`, aliased by
367
+ `data.no_spend_next_command`), and the provider-call, credit-debit, and
368
+ media-write false proof in `data.mutation` is retained. The self-fund path
369
+ stays discoverable without dominating via
370
+ `data.no_spend_output_mode.self_fund_discovery`: its
371
+ `rerun_with_funding_command` re-runs the guide without `--no-spend` to surface
372
+ the funding templates, and `inspect_methods_command` is a read-only, no-spend
373
+ payment-method inspection (the same command as
374
+ `data.escape_hatches.payment_methods`). `--no-spend` is a guide output mode; it
375
+ requires `--guide`, and for a no-spend planned job outside the guide use
376
+ `create --dry-run`.
377
+
296
378
  Manual escape hatches are not prerequisites. Use them only when
297
379
  `data.next_command` / `data.escape_hatches` asks, or when the task genuinely
298
380
  needs deeper capability, quota, payment, or planning detail:
@@ -1642,6 +1724,13 @@ The quote command omits `--idempotency-key` so the public CLI generates and
1642
1724
  returns one for retry safety before the agent follows the quote response into
1643
1725
  `credits buy` and `credits status`.
1644
1726
 
1727
+ When a create or edit produced a real durable asset, the same envelope carries
1728
+ `data.next_actions.share_with_human`: a no-spend, copy-runnable
1729
+ `luxin claim code --json` plus `share_field: "data.dashboard_url"`. Run it and
1730
+ hand your human the resulting `dashboard_url` — they can watch this work and
1731
+ fund your credits from it. Dry runs never carry it, because there is nothing
1732
+ finished to show.
1733
+
1645
1734
  Provider/model names in this paragraph are preview provenance, not the primary
1646
1735
  public UX. The public selection surface should be Luxin capabilities and
1647
1736
  model-parameter schemas; provider/model details belong in explicit
@@ -33,7 +33,7 @@
33
33
  "surface": "hosted_cli",
34
34
  "mutation": true,
35
35
  "spend": false,
36
- "subcommands": ["request"]
36
+ "subcommands": ["request", "code"]
37
37
  },
38
38
  {
39
39
  "id": "whoami",
@@ -166,6 +166,7 @@
166
166
  "trust",
167
167
  "signup --agent --agent-name NAME --runtime RUNTIME",
168
168
  "claim request --contact INBOX",
169
+ "claim code",
169
170
  "whoami",
170
171
  "usage quota",
171
172
  "quota",
@@ -238,9 +239,9 @@
238
239
  "key": "claim",
239
240
  "help": {
240
241
  "command": "luxin claim help",
241
- "usage": "luxin claim request --contact AGENT_OR_OPERATOR_INBOX --json",
242
+ "usage": "luxin claim <request|code> --json",
242
243
  "docs_url": "https://luxin.sh/cli.md#luxin-claim-request",
243
- "subcommands": ["request"]
244
+ "subcommands": ["request", "code"]
244
245
  }
245
246
  },
246
247
  {
@@ -253,6 +254,16 @@
253
254
  "optional_flags": ["--token-stdin"]
254
255
  }
255
256
  },
257
+ {
258
+ "key": "claim code",
259
+ "help": {
260
+ "command": "luxin claim code help",
261
+ "usage": "luxin claim code --json",
262
+ "docs_url": "https://luxin.sh/cli.md#luxin-claim-code",
263
+ "description": "Mint a single-use, short-lived dashboard link and hand data.dashboard_url to your human: they can watch your work and fund your credits there. No inputs beyond auth; no spend.",
264
+ "optional_flags": ["--token-stdin"]
265
+ }
266
+ },
256
267
  {
257
268
  "key": "whoami",
258
269
  "help": {
@@ -410,6 +421,7 @@
410
421
  "docs_url": "https://luxin.sh/cli.md#luxin-create",
411
422
  "optional_flags": [
412
423
  "--guide",
424
+ "--no-spend",
413
425
  "--dry-run",
414
426
  "--model",
415
427
  "--aspect-ratio",
@@ -66,6 +66,7 @@ First-run guide loop:
66
66
  5a. When data.stage is quota_required, data.self_fund_handoff mirrors top-up urgency, urgency_score, and urgency_reasons, and exposes first_safe_command plus first_safe_command_effect. Run first_safe_command, usually luxin credits methods --json, for no-spend rail inspection before quote/buy when delegated spend authority is absent or unclear.
67
67
  6. If data.stage is ready_to_create, data.next_command is the first bounded live create. data.guide_warning.next_command_safety must be live_media_create_credit_debit, data.guide_warning.no_spend_safe must be false, data.guide_warning.spend_required must be true, and data.guide_warning.recommended_command_field must be recommended_no_spend_command. data.auth_ready.ready and data.auth_ready.next_command_auth_ready must be true; data.auth_ready.next_command_requires_auth must be true, and the command can reuse saved config, IMAGE_SKILL_TOKEN, or --token-stdin context without exposing a raw token. data.next_command_effect.label must be live_media_create_credit_debit and its provider_call, hosted_create, credit_debit, and media_write flags are true. data.no_spend_evaluation.stop_here must be true, data.no_spend_evaluation.next_command_is_live_create must be true, and data.no_spend_evaluation.recommended_command_field must be recommended_no_spend_command. Run data.next_command only when media spend is allowed. In no-spend evaluations, or when you only need to prove readiness without media/provider work, stop before data.next_command and run data.recommended_no_spend_command instead. data.recommended_no_spend_command must equal data.no_spend_next_command. data.no_spend_next_command_effect.label must be dry_run_planned_job_no_provider_call_no_credit_debit_no_media_write: no_spend, hosted_create_dry_run, planned_job, and plan_receipt are true; activity_event is job.planned; provider_call, credit_debit, and media_write are false. This dry-run may create a recoverable planned job/activity receipt but no provider execution, debit, downloadable asset, or media write. If the guide authenticated from env or stdin, prefer data.auth_handoff.next_command.with_env or data.auth_handoff.next_command.with_stdin so auth follows the live create. In guide cost output, cost.estimated_usd_per_image and cost.estimated_debit_usd_per_image are the Luxin debit dollars for one output; cost.estimated_provider_usd_per_image is only the upstream provider estimate. Use the guide's returned max_estimated_usd_per_image because it is sized to the credit debit the agent funds. Add --output-count N only after models show confirms the selected create model supports more than one output; credit_pricing.credits_required is the total debit across outputs, while max_estimated_usd_per_image remains a per-image Luxin debit guard.
68
68
  7. After create, prefer data.next_actions when present: inspect_job and inspect_asset are copy-runnable no-spend recovery commands, iterate_edit is the reusable-asset edit template, and self_fund is the promoted top-up quote handoff when quota.top_up.available is true. self_fund.recommended plus urgency, urgency_score, and urgency_reasons say whether to act now, and self_fund exposes first_safe_command plus first_safe_command_effect for no-spend rail inspection before quote/buy. When self_fund.recommended is true and the quote is copy-runnable, data.self_fund_next_command aliases data.next_actions.self_fund.quote_command and data.self_fund_next_command_effect proves the quote creates no provider call, hosted create, credit debit, media write, or wallet settlement. self_fund.quote_command is copy-runnable and omits --idempotency-key so the public CLI generates and returns one for retry safety; follow the quote response into buy/status. Otherwise use luxin jobs show JOB_ID to recover status, cost, safety, timestamps, and final assets; luxin assets get ASSET_URL_OR_ID --output ./result.png to fetch the generated asset without repeating provider work; and luxin activity list --subject JOB_ID to find ledger events, trace, usage, asset links, and any data.next_actions.self_fund handoff to cite or follow. Hosted asset-id assets show/get may also return data.next_actions.self_fund after generated work, so inspect that field before ending the session.
69
+ 7a. Human handoff. When a create or edit produced a real asset, data.next_actions.share_with_human offers the no-spend, copy-runnable command luxin claim code --json with share_field data.dashboard_url. Run it and give your human the returned data.dashboard_url: they get a read-only view of your jobs, assets, quota, and activity plus the ability to open a credit checkout for you. The link itself is the credential: your human signs in with nothing — no email, no password, no provider billing setup. Hand over data.dashboard_url only — never your token, and never the raw data.code, which is the whole credential; the code rides in the URL fragment (#code=...), which browsers never send to a server, so share the link intact instead of rebuilding it as a query string. The code is single-use and expires (data.ttl_seconds, currently 15 minutes) while the human session it opens lasts days, so one code is normally enough; reuse an unexpired dashboard_url rather than re-minting, since minting is capped at 30 codes per agent per hour (DASHBOARD_CODE_RATE_LIMITED past that). Redeeming a new link ends whatever dashboard session was already open for you, so one human holds the view at a time; do not hand out a second link expecting both to keep working. luxin claim code needs the dashboard.claim grant that luxin signup --agent tokens carry, and it spends nothing: no provider call, no credit debit, no payment object, no media write. Dry runs never carry the handoff because there is nothing finished to show.
69
70
  8. Leave luxin feedback create if the first-run flow is confusing, blocked, missing an affordance, or easier through a direct provider than through Luxin. Feedback auth uses saved config from default signup, IMAGE_SKILL_TOKEN, or --token-stdin; if signup or guide already saved config, run feedback create normally and do not copy a raw token. Never paste tokens into feedback title, body, evidence, issues, or logs. Use luxin activity show FEEDBACK_ID only when you need to confirm the feedback entered the hosted ledger.
70
71
 
71
72
  Manual escape hatches are not prerequisites. Use luxin doctor, luxin models list, luxin models show MODEL_ID, luxin whoami, luxin usage quota, luxin credits methods, luxin credits packs list, luxin credits quote, luxin credits buy, luxin credits status, luxin create --dry-run, and luxin edit --dry-run only when data.next_command or data.escape_hatches asks for them, or when the task genuinely needs deeper capability, quota, payment, or planning detail.
@@ -74,6 +75,7 @@ Core commands:
74
75
  - luxin doctor --json
75
76
  - luxin signup --agent --agent-name NAME --runtime RUNTIME --json
76
77
  - luxin claim request --contact AGENT_OR_OPERATOR_INBOX --json
78
+ - luxin claim code --json
77
79
  - luxin whoami --json
78
80
  - luxin usage quota --json
79
81
  - luxin quota --json (compatibility alias)