warpmetal 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,10 +4,12 @@ The official command-line client and portable Agent Skill for WarpMetal.
4
4
 
5
5
  The CLI uses the public API at `https://api.warpmetal.com`, stores generated
6
6
  WarpMetal credentials in a user-private state file, and never reads or stores
7
- wallet private keys or SSH private-key contents. Version 0.4 adds a guarded
8
- x402api Agent Wallet handoff: WarpMetal writes the exact credential-free payment
9
- request, explains the next commands to an agent, validates the returned payment
10
- artifact, and submits it without absorbing wallet custody.
7
+ wallet private keys or SSH private-key contents. Version 0.5 adds dedicated
8
+ hostname-based VPS identities, bounded autonomous renewal, verified lifecycle
9
+ email, and signed refill requests through the x402api Agent Wallet. WarpMetal
10
+ writes the exact credential-free payment request, explains the next commands to
11
+ an agent, validates the returned payment artifact, and submits it without
12
+ absorbing wallet custody.
11
13
 
12
14
  ## Distribution
13
15
 
@@ -60,9 +62,18 @@ warpmetal order prepare \
60
62
  --plan agent \
61
63
  --hostname codex-workspace \
62
64
  --os '<exact name from warpmetal catalog>' \
63
- --ssh-public-key-file ~/.ssh/id_ed25519.pub
65
+ --generate-ssh-key \
66
+ --json
64
67
  ```
65
68
 
69
+ The generated key defaults to
70
+ `${WARPMETAL_HOME:-~/.config/warpmetal}/ssh/warpmetal-codex-workspace`. A
71
+ collision receives a random suffix; existing keys are never overwritten. Once
72
+ checkout returns `serverId`, the CLI binds that ID to the identity so
73
+ `warpmetal server login` and `warpmetal runtime install` can select it without
74
+ an `--identity` flag. Use `--ssh-public-key-file` instead when supplying a
75
+ user-managed public key.
76
+
66
77
  Pass `--json` for structured, secret-redacted output. Use
67
78
  `WARPMETAL_API_URL` for an alternate API origin and `WARPMETAL_HOME` for an
68
79
  alternate state directory.
@@ -109,10 +120,26 @@ warpmetal checkout submit \
109
120
  Check the payer wallet address and balance with:
110
121
 
111
122
  ```sh
123
+ x402api wallet show --wallet <wallet-name> --json
112
124
  x402api wallet address --wallet <wallet-name> --json
113
125
  x402api wallet balance --wallet <wallet-name> --json
114
126
  ```
115
127
 
128
+ For a new dedicated wallet, configure the enforceable local per-payment
129
+ ceiling when it is created:
130
+
131
+ ```sh
132
+ x402api wallet create --name <wallet-name> \
133
+ --network <exact-challenge-network> \
134
+ --maximum-payment-atomic <per-payment-policy-cap> --json
135
+ ```
136
+
137
+ Require `maximumPaymentAtomic` to cover the live charge without exceeding the
138
+ task or operator limit. Among valid sponsored terms, honor an explicit network
139
+ or asset preference, otherwise prefer an already funded compatible wallet,
140
+ then the first compatible term in live challenge order. Never switch terms
141
+ after authorization.
142
+
116
143
  If funding is short in an interactive conversation, tell the human the exact
117
144
  top-up in normal and atomic units, the network, stablecoin and contract/mint,
118
145
  and the payer wallet's public receiving address. The human sends the token to
@@ -121,6 +148,48 @@ recipient, and never sends ETH or SOL for a sponsored payment. In an unattended
121
148
  run, use a preconfigured refill or escalation mechanism or stop with
122
149
  `funding_required`.
123
150
 
151
+ ## Autonomous renewal and refill
152
+
153
+ Configure renewal only with explicit bounds. This example allows at most 12
154
+ renewals, enforces a 30 USDC per-payment ceiling and a 360 USDC cumulative
155
+ budget, and requests a verified notification recipient:
156
+
157
+ ```sh
158
+ warpmetal renewal configure \
159
+ --server <serverId> \
160
+ --renew-before-days 3 \
161
+ --maximum-payment-atomic 30000000 \
162
+ --maximum-renewals 12 \
163
+ --maximum-total-spend-atomic 360000000 \
164
+ --allowed-network eip155:8453 \
165
+ --allowed-asset 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
166
+ --wallet <dedicated-wallet> \
167
+ --email ops@example.com \
168
+ --json
169
+ ```
170
+
171
+ The recipient must follow the one-time verification link before lifecycle or
172
+ refill mail is sent. A recurring unattended agent can then run:
173
+
174
+ ```sh
175
+ warpmetal renewal due --all --json
176
+ warpmetal renewal run --all-due --json
177
+ ```
178
+
179
+ Inside policy, the CLI returns the exact Agent Wallet authorization and submit
180
+ argv. If balance is insufficient, run the returned `refillWorkflow.argv` with
181
+ its `X402API_NOTIFICATION_URL` environment value. `x402api wallet
182
+ notify-refill` signs an opaque subscription reference and wallet-produced
183
+ balance fields; it cannot choose an email address. WarpMetal verifies the
184
+ wallet signature and current on-chain balance before emailing the verified
185
+ human the network, stablecoin, public wallet address, and required minimum
186
+ top-up. The human may transfer more than that minimum; the renewal policy—not
187
+ the refill target—remains the spending authority.
188
+
189
+ The agent never sends a partial x402 payment. If no verified refill path
190
+ exists, it reports `funding_required`. If a previous payment is pending or
191
+ ambiguous, it reconciles the saved attempt and never signs a second payment.
192
+
124
193
  The x402api Agent Wallet is a separate, merchant-neutral executable. Install
125
194
  its matching `x402api-pay` skill with `x402api skill install --output <agent-skill-directory>/x402api-pay --json`.
126
195
  Do not use `x402api pay`, `payment submit`, or `payment reconcile` for WarpMetal:
@@ -164,7 +233,6 @@ compatible external signer.
164
233
  warpmetal runtime enable --server <serverId> --json
165
234
  warpmetal runtime install \
166
235
  --server <serverId> \
167
- --identity ~/.ssh/warpmetal-owner \
168
236
  --ssh-user ubuntu \
169
237
  --confirm INSTALL \
170
238
  --wait \
@@ -186,7 +254,7 @@ cleanup, access-grant, and strict host-key connection workflow.
186
254
 
187
255
  ## Release status
188
256
 
189
- The initial development release is published at
257
+ The package is published at
190
258
  `https://www.npmjs.com/package/warpmetal`. The source is publicly visible but
191
259
  remains `UNLICENSED`; choose an explicit license before describing the project
192
260
  as open source or inviting third-party reuse.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "warpmetal",
3
- "version": "0.4.1",
4
- "description": "Agent-safe CLI and skill for purchasing and managing WarpMetal VPS servers",
3
+ "version": "0.5.0",
4
+ "description": "Agent-safe CLI and skill for purchasing, renewing, and managing WarpMetal VPS servers",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "warpmetal": "bin/warpmetal.js"
@@ -38,6 +38,8 @@
38
38
  "agent-skills",
39
39
  "codex",
40
40
  "claude",
41
- "x402"
41
+ "x402",
42
+ "autonomous-renewal",
43
+ "ssh"
42
44
  ]
43
45
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: warpmetal
3
- description: Safely purchase and manage WarpMetal VPS servers and Agent Runtime sandboxes with the official warpmetal CLI, including x402api Agent Wallet payment handoff. Use when a shell-capable agent needs live VPS discovery, x402 payment authorization, ordering, provisioning, server management, optional runtime installation, fixed-size sandbox creation, persistent or temporary lifetime, per-agent SSH access, sandbox connection, access revocation, or workspace deletion.
3
+ description: Safely purchase, renew, and manage WarpMetal VPS servers and Agent Runtime sandboxes with the official warpmetal CLI and x402api Agent Wallet. Use when a shell-capable agent needs live VPS discovery, hostname-based SSH identity creation, x402 payment or refill handling, bounded autonomous renewal, human lifecycle notifications, ordering, provisioning, server management, optional runtime installation, sandbox creation, per-agent SSH access, revocation, or deletion.
4
4
  ---
5
5
 
6
6
  # WarpMetal
@@ -23,6 +23,8 @@ with ad hoc HTTP commands.
23
23
  funding a wallet, authorizing payment, or resolving an ambiguous attempt.
24
24
  7. Read [references/runtime.md](references/runtime.md) before requesting,
25
25
  installing, accessing, expiring, or deleting Agent Runtime sandboxes.
26
+ 8. Read [references/renewals.md](references/renewals.md) before configuring or
27
+ executing an autonomous renewal or requesting a wallet refill.
26
28
 
27
29
  Never read, print, summarize, upload, or commit the WarpMetal state file,
28
30
  x402api keystore, password file, payment request envelope, or payment artifact.
@@ -43,24 +45,36 @@ warpmetal health --json
43
45
  warpmetal catalog --json
44
46
  ```
45
47
 
46
- Stop if `purchasingReady` is false. Select `planId` and the exact OS `name`
47
- from the live catalog. Do not reuse an OS name or price from documentation or
48
- a previous session.
48
+ Stop the current purchase if `purchasingReady` is false. In unattended
49
+ scheduling, recheck after 60 seconds, then double the delay after each failed
50
+ check up to 15 minutes and honor a longer `Retry-After`; never hot-loop. In an
51
+ interactive conversation, report the unavailable state and stop. Select
52
+ `planId` and the exact OS `name` from the live catalog. Do not reuse an OS name
53
+ or price from documentation or a previous session.
49
54
 
50
55
  ## Prepare an order
51
56
 
52
- Confirm the intended plan, exact OS, hostname, and existing SSH public-key file
53
- with the user. Ask before generating a new SSH key pair.
57
+ Confirm the intended plan, exact OS, and actual hostname. In a live human
58
+ conversation, ask before generating a new SSH key pair. In an unattended run,
59
+ generate a dedicated identity only when the automation policy permits creating
60
+ local credentials. Use the actual hostname as the readable key name; the CLI
61
+ adds `warpmetal-` and a short suffix only when a file already exists.
54
62
 
55
63
  ```sh
56
64
  warpmetal order prepare \
57
65
  --plan <planId> \
58
66
  --hostname <hostname> \
59
67
  --os '<exact live OS name>' \
60
- --ssh-public-key-file <public-key-path> \
68
+ --generate-ssh-key \
61
69
  --json
62
70
  ```
63
71
 
72
+ Use `--ssh-public-key-file <public-key-path>` instead only when a suitable key
73
+ was explicitly selected. Never run raw `ssh-keygen` for the VPS owner identity.
74
+ The CLI creates and binds `serverId -> key name -> fingerprint -> local paths`.
75
+ Inspect the safe mapping with `warpmetal server identity --server <serverId>
76
+ --json`; do not open the state file.
77
+
64
78
  The CLI saves the generated recovery credential privately and does not print
65
79
  it. Preserve the reported task and server IDs in the conversation, but do not
66
80
  open the state file to retrieve the credential.
@@ -88,6 +102,11 @@ its matching `x402api-pay` skill, and select or fund a dedicated
88
102
  network-specific wallet. Require `agentWalletSupported: true`,
89
103
  `sponsoredNetworkFee: true`, and `buyerNativeFeeRequired: false` on the chosen
90
104
  live term. Never fall back to a historical buyer-funded or TRON profile.
105
+ Honor an explicit task or operator network and asset preference. Otherwise use
106
+ a compatible sufficiently funded wallet, then the first compatible term in the
107
+ live challenge's order. Never switch terms after authorization. Require the
108
+ wallet's `maximumPaymentAtomic` to cover the live amount without exceeding the
109
+ task or operator limit.
91
110
 
92
111
  After interactive confirmation or autonomous policy validation, invoke the
93
112
  returned authorize argv once. The separate
@@ -116,6 +135,31 @@ human is chatting and the terms changed; in an unattended run, proceed only if
116
135
  the replacement remains within standing authority. On `manual_review` or an
117
136
  ambiguous attempt, stop and never create another payment.
118
137
 
138
+ ## Renew autonomously within policy
139
+
140
+ Configure a bounded server policy before unattended renewal. Require a
141
+ per-payment ceiling and either a maximum renewal count or `renewThrough`; use a
142
+ cumulative ceiling when required by the operator. Bind a local Agent Wallet
143
+ whose network and asset exactly match the policy. See
144
+ [references/renewals.md](references/renewals.md) for commands and the complete
145
+ state machine.
146
+
147
+ In a live human conversation, disclose the exact renewal terms before signing.
148
+ In an unattended run, do not seek conversational approval when the policy,
149
+ wallet ceiling, exact live challenge, and balance all permit payment. Stop on a
150
+ price, asset, network, count, horizon, or total-budget mismatch.
151
+
152
+ Run `warpmetal renewal prepare --server <serverId> --json`, then invoke only
153
+ the returned `paymentWorkflow.authorize.argv` and
154
+ `paymentWorkflow.submit.argv`. If authorization reports insufficient balance,
155
+ set the returned `refillWorkflow.environment`, invoke its exact argv once, and
156
+ stop until funding arrives. The signed refill intent resolves to a verified
157
+ human contact; never add an email address to it. Never make a partial payment.
158
+
159
+ After funding, prepare again, authorize exactly once, submit with WarpMetal,
160
+ and confirm the returned `termEndsAt`. On `reconcile_pending` or
161
+ `manual_review`, do not create another authorization.
162
+
119
163
  ## Provision and manage
120
164
 
121
165
  Poll a prepared or paid order with:
@@ -133,7 +177,7 @@ For routine management, prove possession of the installed SSH key without
133
177
  reading it:
134
178
 
135
179
  ```sh
136
- warpmetal server login --server <serverId> --identity <private-key-path> --json
180
+ warpmetal server login --server <serverId> --json
137
181
  warpmetal server get --server <serverId> --json
138
182
  ```
139
183
 
@@ -174,7 +218,7 @@ preserve the key; update `known_hosts` only when the verified key changed and
174
218
  never bypass a mismatch. Then wait for grants to become applied and refresh
175
219
  every connection profile with `sandbox access refresh --confirm REFRESH`
176
220
  before connecting. Do not fall back to raw API calls for deletion, networking,
177
- renewal, or another unsupported mutation.
221
+ or another unsupported mutation.
178
222
 
179
223
  ## Use Agent Runtime
180
224
 
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "WarpMetal VPS"
3
- short_description: "Purchase and manage WarpMetal compute safely"
4
- default_prompt: "Use $warpmetal to purchase a VPS through the guarded x402 wallet handoff and manage isolated agent sandboxes safely."
3
+ short_description: "Purchase, renew, and manage WarpMetal compute"
4
+ default_prompt: "Use $warpmetal to purchase or renew a VPS with a dedicated SSH identity, bounded x402 payment policy, and safe lifecycle management."
@@ -4,6 +4,8 @@
4
4
 
5
5
  - Discovery
6
6
  - Purchase and provisioning
7
+ - SSH identities
8
+ - Renewal and notifications
7
9
  - Server management
8
10
  - Agent Runtime and sandboxes
9
11
  - Per-agent access
@@ -27,7 +29,7 @@ warpmetal order prepare \
27
29
  --plan <live planId> \
28
30
  --hostname <dns-label> \
29
31
  --os '<exact live OS name>' \
30
- --ssh-public-key-file <path> \
32
+ (--generate-ssh-key [--ssh-key-name <name>] | --ssh-public-key-file <path>) \
31
33
  [--runtime-file <runtime.json>] [--confirm TEMPORARY] \
32
34
  [--email <address>] \
33
35
  [--idempotency-key <key>] \
@@ -74,12 +76,53 @@ It reports only safe attempt metadata. The compatibility
74
76
  never creates, imports, reads, or stores wallet keys and does not sign x402
75
77
  challenges itself. See [payments.md](payments.md).
76
78
 
79
+ ## SSH identities
80
+
81
+ ```sh
82
+ warpmetal identity generate --hostname <dns-label> [--ssh-key-name <name>] --json
83
+ warpmetal identity list --json
84
+ warpmetal server identity --server <serverId> --json
85
+ warpmetal server identity attach \
86
+ --server <serverId> --identity <private-key-path> \
87
+ [--ssh-key-name <name>] --json
88
+ ```
89
+
90
+ Generated identities live under the private WarpMetal state directory. The
91
+ default name is `warpmetal-<actual-hostname>`. Existing files are never
92
+ overwritten; a collision adds a short suffix. Order completion binds the local
93
+ identity to `serverId`, and later SSH-backed commands select it automatically.
94
+
95
+ ## Renewal and notifications
96
+
97
+ ```sh
98
+ warpmetal renewal configure \
99
+ --server <serverId> --renew-before-days <n> \
100
+ --maximum-payment-atomic <amount> \
101
+ (--maximum-renewals <n> | --renew-through <UTC>) \
102
+ [--maximum-total-spend-atomic <amount>] \
103
+ --allowed-network <network> --allowed-asset <asset> \
104
+ --wallet <name> [--refill-target-atomic <amount>] [--email <address>] --json
105
+ warpmetal renewal status --server <serverId> --json
106
+ warpmetal renewal due (--server <serverId> | --all) --json
107
+ warpmetal renewal prepare --server <serverId> --json
108
+ warpmetal renewal submit --server <serverId> \
109
+ --payment-artifact <path> [--wait] --json
110
+ warpmetal renewal run (--server <serverId> | --all-due) --json
111
+ warpmetal notifications configure --server <serverId> --email <address> \
112
+ [--events <comma-separated-events>] --json
113
+ warpmetal notifications status --server <serverId> --json
114
+ ```
115
+
116
+ `renewal prepare` returns exact payment and refill argv arrays. `renewal run`
117
+ is an agent-facing state machine, not a wallet-signing daemon. See
118
+ [renewals.md](renewals.md).
119
+
77
120
  ## Server management
78
121
 
79
122
  ```sh
80
123
  warpmetal server login \
81
124
  --server <serverId> \
82
- --identity <private-key-path> \
125
+ [--identity <private-key-path>] \
83
126
  --json
84
127
 
85
128
  warpmetal server get --server <serverId> --json
@@ -95,7 +138,8 @@ warpmetal server power \
95
138
  warpmetal server reload \
96
139
  --server <serverId> --confirm ERASE --power-off-first \
97
140
  [--acknowledge-agent-runtime-reset] [--hostname <name>] \
98
- [--os <exact-live-os-name>] [--ssh-public-key-file <public-key-path>] \
141
+ [--os <exact-live-os-name>] \
142
+ [--generate-ssh-key [--ssh-key-name <name>] | --ssh-public-key-file <path>] \
99
143
  [--idempotency-key <key>] [--wait] [--timeout-seconds <n>] --json
100
144
 
101
145
  warpmetal operation get \
@@ -122,7 +166,7 @@ process listings.
122
166
  warpmetal runtime enable --server <serverId> [--idempotency-key <key>] --json
123
167
  warpmetal runtime get --server <serverId> [--wait] [--timeout-seconds <n>] --json
124
168
  warpmetal runtime install \
125
- --server <serverId> --identity <owner-key> --ssh-user <admin-user> \
169
+ --server <serverId> [--identity <owner-key>] --ssh-user <admin-user> \
126
170
  --confirm INSTALL [--wait] [--timeout-seconds <n>] --json
127
171
 
128
172
  warpmetal sandbox create \
@@ -5,6 +5,7 @@
5
5
  - Trust boundary
6
6
  - Wallet setup and funding
7
7
  - Exact purchase workflow
8
+ - Exact renewal and refill workflow
8
9
  - Retries and recovery
9
10
 
10
11
  ## Trust boundary
@@ -42,7 +43,20 @@ skill automatically.
42
43
  already permits it and a secure password source is configured; otherwise
43
44
  reuse a preconfigured wallet or stop. Keep Base and Solana wallets separate;
44
45
  never import the owner's primary seed or key. TRON wallet management exists,
45
- but the published launch payer cannot authorize TRON.
46
+ but the published launch payer cannot authorize TRON. Configure the local
47
+ per-payment ceiling at creation and inspect it before reuse:
48
+
49
+ ```sh
50
+ x402api wallet create --name <name> \
51
+ --network <exact-challenge-network> \
52
+ --maximum-payment-atomic <per-payment-policy-cap> --json
53
+ x402api wallet show --wallet <name> --json
54
+ ```
55
+
56
+ Require `maximumPaymentAtomic` to be at least the exact live amount and no
57
+ higher than the task or operator limit. If an existing wallet has no ceiling
58
+ or an unsuitable one, do not treat its full balance as bounded authority;
59
+ use a suitably capped dedicated wallet or stop.
46
60
  5. Use both public, safe commands before requesting funding:
47
61
 
48
62
  ```sh
@@ -57,8 +71,10 @@ skill automatically.
57
71
  contract/mint or `paymentTerms.recipient`. Sponsored launch payments never
58
72
  ask the buyer to fund ETH or SOL. Recheck the balance after the transfer.
59
73
  7. If funding is short in an unattended run, use only a preconfigured refill
60
- or escalation mechanism. Otherwise report `funding_required` and stop; do
61
- not invent a human approval step or funding source.
74
+ mechanism returned by WarpMetal. For a configured renewal, set the returned
75
+ `refillWorkflow.environment`, invoke `refillWorkflow.argv` once, and stop
76
+ until funding arrives. Otherwise report `funding_required` and stop; do not
77
+ invent a human approval step or funding source.
62
78
 
63
79
  Treat the dedicated wallet's funded balance as spend authority available to
64
80
  the agent, bounded by any wallet-local maximum payment policy and task or
@@ -106,6 +122,12 @@ launch profiles are sponsored Base USDC and sponsored Solana USDC/USDT, bound
106
122
  by the strict `com.x402api.gas-sponsorship` extension. Stop on an expired gas
107
123
  reservation or any buyer-funded, unsupported, or unbound alternative.
108
124
 
125
+ Among valid sponsored terms, honor an explicit task or operator network and
126
+ asset preference. Otherwise prefer a compatible wallet that is already
127
+ sufficiently funded. If several terms remain, choose the first compatible term
128
+ in the live challenge's advertised order. Do not switch terms after
129
+ authorization.
130
+
109
131
  Do not replace the two-stage workflow with `x402api pay`, `payment submit`, or
110
132
  `payment reconcile`. Those wallet commands can submit an exact credential-free
111
133
  endpoint; WarpMetal checkout requires a private owner token that must never
@@ -118,6 +140,17 @@ expiry, sponsorship lifetime, file type, or permissions do not match the saved
118
140
  challenge. Keep `--payment-signature-file` only as a compatibility path for
119
141
  another external signer.
120
142
 
143
+ ## Exact renewal and refill workflow
144
+
145
+ Renewal uses the same signer boundary and exact artifact checks as purchase,
146
+ but the merchant body is `{"serverId":"..."}` and submission returns through
147
+ `warpmetal renewal submit`. Read [renewals.md](renewals.md) for policy limits,
148
+ scheduling, signed refill notification, and recovery states.
149
+
150
+ Never use an initial-purchase artifact for renewal or a renewal artifact for a
151
+ later term. The resource URL, body, challenge digest, gas reservation, and
152
+ current `termEndsAt` generation are different.
153
+
121
154
  ## Retries and recovery
122
155
 
123
156
  - `payment_pending` or `payment_finalizing`: keep the same checkout bytes and
@@ -0,0 +1,127 @@
1
+ # WarpMetal renewal and refill workflow
2
+
3
+ ## Contents
4
+
5
+ - Configure standing authority
6
+ - Schedule renewal checks
7
+ - Authorize and submit renewal
8
+ - Request a refill
9
+ - Stop and recovery states
10
+
11
+ ## Configure standing authority
12
+
13
+ Create a durable backend policy and local Agent Wallet binding:
14
+
15
+ ```sh
16
+ warpmetal renewal configure \
17
+ --server <serverId> \
18
+ --renew-before-days 3 \
19
+ --maximum-payment-atomic <per-renewal-cap> \
20
+ (--maximum-renewals <count> | --renew-through <UTC>) \
21
+ [--maximum-total-spend-atomic <total-cap>] \
22
+ --allowed-network <exact-CAIP-2-network> \
23
+ --allowed-asset <exact-contract-or-mint> \
24
+ --wallet <agent-wallet-name> \
25
+ [--refill-target-atomic <target>] \
26
+ [--email <human-address>] \
27
+ --json
28
+ ```
29
+
30
+ `--email` queues verification; refill and expanded lifecycle notices remain
31
+ disabled until the human opens the verification link. A refill target is a
32
+ funding target, not spend permission, and cannot exceed the per-renewal cap.
33
+ The human may transfer more than the displayed deficit. The agent may spend
34
+ only the exact renewal amount allowed by policy.
35
+
36
+ The WarpMetal CLI stores only the local wallet name. The backend stores
37
+ non-secret limits, counters, payment rail, time horizon, and an opaque
38
+ notification reference. WarpMetal never receives the wallet key.
39
+
40
+ ## Schedule renewal checks
41
+
42
+ Use a recurring agent, scheduler, CI job, or cron to invoke:
43
+
44
+ ```sh
45
+ warpmetal renewal due --all --json
46
+ warpmetal renewal run --server <serverId> --json
47
+ ```
48
+
49
+ The CLI does not install a daemon. Treat actions as follows:
50
+
51
+ - `not_due`: stop successfully until the next scheduled check.
52
+ - `policy_required`: configure or deliberately revise policy.
53
+ - `approval_required`: stop; a ceiling or horizon prevents autonomous spend.
54
+ - `sign_payment`: follow the returned exact payment workflow.
55
+ - `refill_required`: follow the signed refill workflow and stop.
56
+ - `reconcile_pending`: preserve the artifact and reconcile; never authorize again.
57
+ - `manual_review`: stop all payment and mutation retries.
58
+ - `renewed`: verify the new `termEndsAt` and stop successfully.
59
+
60
+ ## Authorize and submit renewal
61
+
62
+ ```sh
63
+ warpmetal renewal prepare --server <serverId> --json
64
+ ```
65
+
66
+ The command validates server state and policy, preserves the exact body
67
+ `{"serverId":"..."}`, validates the sponsored x402 challenge, selects exactly
68
+ one policy-compatible rail, and returns:
69
+
70
+ ```text
71
+ paymentWorkflow.authorize.argv
72
+ paymentWorkflow.submit.argv
73
+ refillWorkflow.environment
74
+ refillWorkflow.argv
75
+ ```
76
+
77
+ Invoke the authorize argv once. It writes an owner-only artifact. Then invoke
78
+ the submit argv, equivalent to:
79
+
80
+ ```sh
81
+ warpmetal renewal submit \
82
+ --server <serverId> \
83
+ --payment-artifact <owner-only-artifact-path> \
84
+ --wait \
85
+ --json
86
+ ```
87
+
88
+ WarpMetal validates the artifact against the saved renewal body, challenge,
89
+ resource, policy network, policy asset, per-payment cap, sponsorship, and
90
+ buyer payment identifier before adding the private management credential.
91
+
92
+ ## Request a refill
93
+
94
+ When Agent Wallet reports insufficient asset balance, do not authorize a
95
+ partial payment and do not create another wallet merely to bypass the policy.
96
+ Set the exact returned `X402API_NOTIFICATION_URL`, then invoke the returned:
97
+
98
+ ```sh
99
+ x402api wallet notify-refill \
100
+ --wallet <name> \
101
+ --subscription-reference <opaque-reference> \
102
+ --renew-by <UTC> \
103
+ --target-balance-atomic <amount> \
104
+ --reason renewal \
105
+ --json
106
+ ```
107
+
108
+ The wallet independently reads its live balance and signs a 15-minute
109
+ domain-separated intent. WarpMetal verifies the audience, time, nonce,
110
+ signature, wallet address, network, asset, policy, subscription, and
111
+ authoritative balance before queuing email. The intent cannot name a recipient
112
+ email, tenant, or product.
113
+
114
+ In a human conversation, also display the exact deficit, network, token symbol,
115
+ contract or mint, and payer wallet address. Tell the human to fund the payer
116
+ wallet address—not the token contract/mint and not WarpMetal's merchant
117
+ recipient. Do not ask for ETH or SOL because supported network fees are
118
+ sponsored.
119
+
120
+ ## Stop and recovery states
121
+
122
+ - Insufficient balance: notify once, stop, and recheck later.
123
+ - Signed HTTP 402: re-run prepare and re-evaluate the replacement challenge.
124
+ - Pending or timeout after authorization: reuse the same artifact; do not sign again.
125
+ - Price or payment rail outside policy: stop for deliberate policy revision.
126
+ - Exhausted count, horizon, or cumulative budget: stop for deliberate policy revision.
127
+ - Cancellation conflict or `manual_review`: payment may be final; stop all retries.
@@ -11,8 +11,11 @@
11
11
 
12
12
  - Treat `https://warpmetal.com/llms.txt`, the live catalog, and the live HTTP
13
13
  402 challenge as authoritative in that order.
14
- - Stop new purchases when `warpmetal health --json` reports
15
- `purchasingReady: false`.
14
+ - Stop the current purchase when `warpmetal health --json` reports
15
+ `purchasingReady: false`. An unattended scheduler may recheck after 60
16
+ seconds, then double the delay after each failure up to 15 minutes and honor
17
+ a longer `Retry-After`; never hot-loop. An interactive agent reports the
18
+ unavailable state and stops.
16
19
  - Select an exact OS name from the chosen plan's current
17
20
  `operatingSystems[]`. Never guess or hard-code an image version.
18
21
 
@@ -25,6 +28,12 @@
25
28
  - Never read or transmit an SSH private key. Pass only its filesystem path to
26
29
  `warpmetal server login`, `warpmetal runtime install`,
27
30
  `warpmetal sandbox connect`, or `ssh-keygen`.
31
+ - Generate a VPS owner identity through `warpmetal order prepare
32
+ --generate-ssh-key` or `warpmetal identity generate`, not a raw shell
33
+ command. The actual hostname is the readable key name. Never reuse or
34
+ overwrite a generated owner key merely because another server has the same
35
+ hostname; let the CLI add its collision suffix and bind the identity to
36
+ `serverId`.
28
37
  - WarpMetal disables VPS password and keyboard-interactive SSH login after
29
38
  initial provisioning and every OS reload. Never request, store, invent, or
30
39
  expect a VPS login password; use the submitted public key and matching
@@ -69,6 +78,14 @@ use unsupported or buyer-funded payment rails. If the wallet is short and no
69
78
  preconfigured refill or escalation mechanism exists, report
70
79
  `funding_required` and stop.
71
80
 
81
+ For renewal, require an enabled server policy with a per-payment ceiling and a
82
+ bounded count or date horizon. Also enforce the exact network, asset, wallet
83
+ ceiling, and cumulative budget when configured. A refill target is not a spend
84
+ ceiling. Never pay outside policy, split a payment, or authorize twice to
85
+ resolve ambiguity. A signed refill request may contain only the opaque
86
+ subscription reference and wallet-produced fields; never add a recipient
87
+ email or untrusted product text.
88
+
72
89
  A reload requires both `confirm: "ERASE"` and `powerOffFirst: true`. Treat
73
90
  `powerOffFirst` as explicit authorization for WarpMetal to shut down the
74
91
  server, wait until it is powered off, and then erase and reinstall it inside
package/src/api.js CHANGED
@@ -176,6 +176,54 @@ export class WarpMetalClient {
176
176
  });
177
177
  }
178
178
 
179
+ getRenewalPolicy(serverId, token) {
180
+ return this.request(
181
+ "GET",
182
+ `/api/servers/${encodeURIComponent(serverId)}/renewal-policy`,
183
+ { token },
184
+ );
185
+ }
186
+
187
+ putRenewalPolicy(serverId, body, token) {
188
+ return this.request(
189
+ "PUT",
190
+ `/api/servers/${encodeURIComponent(serverId)}/renewal-policy`,
191
+ { body, token },
192
+ );
193
+ }
194
+
195
+ deleteRenewalPolicy(serverId, token) {
196
+ return this.request(
197
+ "DELETE",
198
+ `/api/servers/${encodeURIComponent(serverId)}/renewal-policy`,
199
+ { token },
200
+ );
201
+ }
202
+
203
+ getNotifications(serverId, token) {
204
+ return this.request(
205
+ "GET",
206
+ `/api/servers/${encodeURIComponent(serverId)}/notifications`,
207
+ { token },
208
+ );
209
+ }
210
+
211
+ putNotifications(serverId, body, token) {
212
+ return this.request(
213
+ "PUT",
214
+ `/api/servers/${encodeURIComponent(serverId)}/notifications`,
215
+ { body, token },
216
+ );
217
+ }
218
+
219
+ renewalCheckout(planId, { bodyText, token, paymentSignature }) {
220
+ return this.checkout(`/api/checkout/${encodeURIComponent(planId)}/renew`, {
221
+ bodyText,
222
+ token,
223
+ paymentSignature,
224
+ });
225
+ }
226
+
179
227
  powerServer(serverId, action, token, idempotencyKey) {
180
228
  return this.request(
181
229
  "POST",