warpmetal 0.4.2 → 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.
@@ -137,6 +148,48 @@ recipient, and never sends ETH or SOL for a sponsored payment. In an unattended
137
148
  run, use a preconfigured refill or escalation mechanism or stop with
138
149
  `funding_required`.
139
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
+
140
193
  The x402api Agent Wallet is a separate, merchant-neutral executable. Install
141
194
  its matching `x402api-pay` skill with `x402api skill install --output <agent-skill-directory>/x402api-pay --json`.
142
195
  Do not use `x402api pay`, `payment submit`, or `payment reconcile` for WarpMetal:
@@ -180,7 +233,6 @@ compatible external signer.
180
233
  warpmetal runtime enable --server <serverId> --json
181
234
  warpmetal runtime install \
182
235
  --server <serverId> \
183
- --identity ~/.ssh/warpmetal-owner \
184
236
  --ssh-user ubuntu \
185
237
  --confirm INSTALL \
186
238
  --wait \
@@ -202,7 +254,7 @@ cleanup, access-grant, and strict host-key connection workflow.
202
254
 
203
255
  ## Release status
204
256
 
205
- The initial development release is published at
257
+ The package is published at
206
258
  `https://www.npmjs.com/package/warpmetal`. The source is publicly visible but
207
259
  remains `UNLICENSED`; choose an explicit license before describing the project
208
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.2",
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.
@@ -52,18 +54,27 @@ or price from documentation or a previous session.
52
54
 
53
55
  ## Prepare an order
54
56
 
55
- Confirm the intended plan, exact OS, hostname, and existing SSH public-key file
56
- 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.
57
62
 
58
63
  ```sh
59
64
  warpmetal order prepare \
60
65
  --plan <planId> \
61
66
  --hostname <hostname> \
62
67
  --os '<exact live OS name>' \
63
- --ssh-public-key-file <public-key-path> \
68
+ --generate-ssh-key \
64
69
  --json
65
70
  ```
66
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
+
67
78
  The CLI saves the generated recovery credential privately and does not print
68
79
  it. Preserve the reported task and server IDs in the conversation, but do not
69
80
  open the state file to retrieve the credential.
@@ -124,6 +135,31 @@ human is chatting and the terms changed; in an unattended run, proceed only if
124
135
  the replacement remains within standing authority. On `manual_review` or an
125
136
  ambiguous attempt, stop and never create another payment.
126
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
+
127
163
  ## Provision and manage
128
164
 
129
165
  Poll a prepared or paid order with:
@@ -141,7 +177,7 @@ For routine management, prove possession of the installed SSH key without
141
177
  reading it:
142
178
 
143
179
  ```sh
144
- warpmetal server login --server <serverId> --identity <private-key-path> --json
180
+ warpmetal server login --server <serverId> --json
145
181
  warpmetal server get --server <serverId> --json
146
182
  ```
147
183
 
@@ -182,7 +218,7 @@ preserve the key; update `known_hosts` only when the verified key changed and
182
218
  never bypass a mismatch. Then wait for grants to become applied and refresh
183
219
  every connection profile with `sandbox access refresh --confirm REFRESH`
184
220
  before connecting. Do not fall back to raw API calls for deletion, networking,
185
- renewal, or another unsupported mutation.
221
+ or another unsupported mutation.
186
222
 
187
223
  ## Use Agent Runtime
188
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
@@ -70,8 +71,10 @@ skill automatically.
70
71
  contract/mint or `paymentTerms.recipient`. Sponsored launch payments never
71
72
  ask the buyer to fund ETH or SOL. Recheck the balance after the transfer.
72
73
  7. If funding is short in an unattended run, use only a preconfigured refill
73
- or escalation mechanism. Otherwise report `funding_required` and stop; do
74
- 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.
75
78
 
76
79
  Treat the dedicated wallet's funded balance as spend authority available to
77
80
  the agent, bounded by any wallet-local maximum payment policy and task or
@@ -137,6 +140,17 @@ expiry, sponsorship lifetime, file type, or permissions do not match the saved
137
140
  challenge. Keep `--payment-signature-file` only as a compatibility path for
138
141
  another external signer.
139
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
+
140
154
  ## Retries and recovery
141
155
 
142
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.
@@ -28,6 +28,12 @@
28
28
  - Never read or transmit an SSH private key. Pass only its filesystem path to
29
29
  `warpmetal server login`, `warpmetal runtime install`,
30
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`.
31
37
  - WarpMetal disables VPS password and keyboard-interactive SSH login after
32
38
  initial provisioning and every OS reload. Never request, store, invent, or
33
39
  expect a VPS login password; use the submitted public key and matching
@@ -72,6 +78,14 @@ use unsupported or buyer-funded payment rails. If the wallet is short and no
72
78
  preconfigured refill or escalation mechanism exists, report
73
79
  `funding_required` and stop.
74
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
+
75
89
  A reload requires both `confirm: "ERASE"` and `powerOffFirst: true`. Treat
76
90
  `powerOffFirst` as explicit authorization for WarpMetal to shut down the
77
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",