warpmetal 0.8.8 → 0.8.10

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
@@ -156,11 +156,15 @@ receipt finality while provisioning or renewal proceeds.
156
156
 
157
157
  For an interactive initial purchase, `checkout challenge` may also return a
158
158
  short-lived `humanCheckout` object. Its `url` and `qrPayload` are the same
159
- `https://pay.x402api.com/c/...` bearer capability for the exact charge; encode
160
- that URL as the QR, never the WarpMetal recipient address. The buyer connects
161
- their own wallet and needs only the advertised USDC/USDT balance because
162
- x402api sponsors the native gas. This is an alternative to the agent-wallet
163
- workflow, not a second payment. After browser payment, run the exact
159
+ `https://pay.x402api.com/c/...` bearer capability for the exact charge.
160
+ Present the exact URL as a clickable x402api handoff. If a QR is useful for
161
+ another device, encode only the identical `qrPayload` and explain that
162
+ scanning opens the hosted checkout without authorizing payment. x402api owns
163
+ any wallet selection or wallet-specific opening QR inside that page; never
164
+ synthesize a wallet link or encode the WarpMetal recipient address. The buyer
165
+ needs only the advertised USDC/USDT balance because x402api sponsors the native
166
+ gas. This is an alternative to the agent-wallet workflow, not a second
167
+ payment. After browser payment, run the exact
164
168
  `humanCheckout.afterPayment.argv` status command. When the ready result asks
165
169
  for `ask_human_for_notification_email`, ask the owner and add the optional
166
170
  lifecycle-notification address they provide. Autonomous purchases and renewals
@@ -363,42 +367,79 @@ warpmetal sandbox access keygen \
363
367
  --json
364
368
  ```
365
369
 
366
- On the first install in a server trust epoch, JSON output includes
367
- `hostKeyTrust.state: "trusted_first_use"` and the safe Ed25519 fingerprint.
368
- Later installs report `"matched"`. First-use trust protects continuity after
369
- that observation, but it cannot detect an active attacker on the first
370
- connection. Provider-console host-key pre-enrollment remains an optional
371
- higher-assurance alternative when it is available.
370
+ ### Install a standard sandbox SSH alias
372
371
 
373
- WarpMetal CLI v0.8.7 with Agent Runtime v0.1.25 or newer can enable the narrowly
374
- scoped AppArmor exception required by a verified workload that creates an inner
375
- Bubblewrap PID namespace and private `/proc`:
372
+ Use a separate keypair and access grant for each sandbox. After the grant is
373
+ `applied`, install its token-free profile as a concrete OpenSSH alias:
376
374
 
377
375
  ```sh
378
- warpmetal runtime install \
379
- --server <serverId> \
380
- --ssh-user root \
381
- --confirm INSTALL \
382
- --nested-private-procfs enable \
383
- --wait \
376
+ warpmetal sandbox access install-ssh \
377
+ --connection-file <profile-path> \
378
+ --identity <sandbox-private-key-path> \
379
+ --alias <alias> \
384
380
  --json
381
+
382
+ ssh <alias>
383
+ ssh -t <alias> codex
384
+ ssh <alias> codex exec '<task>'
385
+ ssh -t <alias> claude
386
+ ssh <alias> claude -p '<task>'
387
+ ssh -t <alias> agent
388
+ ssh <alias> agent -p '<task>'
389
+ ```
390
+
391
+ Install and authenticate Codex, Claude Code, or Cursor CLI inside the
392
+ sandbox first. Provider credentials are sandbox-owned and remain in its
393
+ persistent home; WarpMetal does not install these tools, perform their login,
394
+ or receive their credentials.
395
+
396
+ The alias is local-only. It prepends a managed include to `~/.ssh/config` and
397
+ uses the profile's pinned host key plus the sandbox identity. It never uses or
398
+ exposes the VPS owner management key. The server-side forced gateway maps that
399
+ identity to only its assigned sandbox, cannot open a host shell, and retains
400
+ `ClearAllForwardings yes` together with agent and X11 forwarding denial.
401
+
402
+ An exact reinstall is safe and unchanged. If an authenticated access refresh
403
+ produces a new profile, refresh the profile first and then explicitly replace
404
+ the local alias:
405
+
406
+ ```sh
407
+ warpmetal sandbox access refresh \
408
+ --server <serverId> --sandbox <sandboxId> --grant <grantId> \
409
+ --connection-file <profile-path> --confirm REFRESH --wait --json
410
+ warpmetal sandbox access install-ssh \
411
+ --connection-file <profile-path> \
412
+ --identity <sandbox-private-key-path> \
413
+ --alias <alias> --confirm REFRESH --json
414
+ ```
415
+
416
+ Remove only that managed alias and pin with explicit confirmation; unrelated
417
+ SSH configuration is preserved:
418
+
419
+ ```sh
420
+ warpmetal sandbox access remove-ssh --alias <alias> --confirm REMOVE --json
385
421
  ```
386
422
 
387
- This is an explicit host-scoped opt-in for nested-Bubblewrap hosts, not a
388
- requirement for ordinary VPS or Runtime workloads that use only the outer
389
- sandbox. The default `preserve` action leaves the current policy state
390
- unchanged. Use `disable` during an approved maintenance window to unload
391
- WarpMetal's policy and restore the pre-install file and loaded-policy state.
392
- Because Runtime sandboxes share one Unix owner, treat an enabled policy as
393
- available to every sandbox on that Runtime host whose process matches the
394
- signed, root-owned bwrap path; it is not a per-sandbox permission.
395
-
396
- Common inner-boundary designs are planning with an exact read-only checkout,
397
- coding with only one approved checkout and output directory writable, and QA
398
- with an exact candidate plus isolated test processes and scratch space. The
399
- boundary protects a persistent trusted runner from repository-controlled
400
- commands and sibling attempts. GitHub access, installing Codex or another AI
401
- CLI, and delegating to subagents do not by themselves require this capability.
423
+ [Codex Desktop's remote-connections contract](https://learn.chatgpt.com/docs/remote-connections)
424
+ discovers concrete aliases from `~/.ssh/config`, requires `ssh <alias>` to
425
+ work, and starts the remote app server through the login shell. Install Codex
426
+ inside the sandbox and ensure Codex is on the login-shell `PATH` before choosing
427
+ the alias in Codex Desktop.
428
+
429
+ The tested Cursor Remote SSH path is incompatible with this boundary because
430
+ it requests dynamic forwarding, which WarpMetal deliberately denies. Do not
431
+ weaken sandbox forwarding controls to make the IDE connect. Use the supported
432
+ [Cursor CLI](https://cursor.com/docs/cli/overview) interactively with
433
+ `ssh -t <alias> agent` or in
434
+ [headless mode](https://cursor.com/docs/cli/headless) with
435
+ `ssh <alias> agent -p '<task>'` instead.
436
+
437
+ On the first install in a server trust epoch, JSON output includes
438
+ `hostKeyTrust.state: "trusted_first_use"` and the safe Ed25519 fingerprint.
439
+ Later installs report `"matched"`. First-use trust protects continuity after
440
+ that observation, but it cannot detect an active attacker on the first
441
+ connection. Provider-console host-key pre-enrollment remains an optional
442
+ higher-assurance alternative when it is available.
402
443
 
403
444
  Installation gives pre-existing Docker containers exact liveness checks and
404
445
  tracks common container-runtime processes without collecting application
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "warpmetal",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "description": "Agent-safe CLI and skill for purchasing, renewing, and managing WarpMetal VPS servers",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  "node": ">=20.0.0"
17
17
  },
18
18
  "scripts": {
19
- "check": "node --check bin/warpmetal.js && node --check src/api.js && node --check src/args.js && node --check src/cli.js && node --check src/connection.js && node --check src/errors.js && node --check src/host-trust.js && node --check src/install-skill.js && node --check src/installer.js && node --check src/payment.js && node --check src/runtime.js && node --check src/ssh.js && node --check src/state.js && node --check src/version.js",
19
+ "check": "node --check bin/warpmetal.js && node --check src/api.js && node --check src/args.js && node --check src/cli.js && node --check src/connection.js && node --check src/errors.js && node --check src/host-trust.js && node --check src/install-skill.js && node --check src/installer.js && node --check src/payment.js && node --check src/runtime.js && node --check src/ssh-alias.js && node --check src/ssh.js && node --check src/state.js && node --check src/version.js",
20
20
  "plugin:check": "node --test test/plugin.test.js",
21
21
  "test": "node --test",
22
22
  "prepack": "npm run check && npm test"
@@ -90,11 +90,14 @@ open either file.
90
90
 
91
91
  In an interactive initial purchase, the result may also contain
92
92
  `humanCheckout`. Offer it as an alternative to the local agent wallet. Show
93
- `humanCheckout.url` as clickable text and render only the identical
94
- `humanCheckout.qrPayload` URL as the purchase QR; never render the recipient
95
- address as this QR. The URL is an expiring bearer capability, so do not log,
96
- save, or send it anywhere except to the buyer who requested this purchase. If
97
- the buyer uses it, do not authorize or submit through the agent wallet. Run the
93
+ `humanCheckout.url` as clickable x402api text. If another-device acquisition
94
+ is useful, render only the identical `humanCheckout.qrPayload` URL as a QR and
95
+ explain that scanning opens the hosted checkout without authorizing payment.
96
+ x402api owns any wallet selection and wallet-specific opening QR inside that
97
+ page; never synthesize a wallet link or render the recipient address as this
98
+ QR. The URL is an expiring bearer capability, so do not log, save, or send it
99
+ anywhere except to the buyer who requested this purchase. If the buyer uses it,
100
+ do not authorize or submit through the agent wallet. Run the
98
101
  exact `humanCheckout.afterPayment.argv` command, wait for the server to become
99
102
  ready, then follow `ask_human_for_notification_email`: ask the owner for the
100
103
  optional lifecycle-notification address and add only the address they provide.
@@ -293,16 +296,6 @@ must match. Explain that TOFU cannot detect an active attacker on the first
293
296
  connection; never use `ssh-keyscan`, accept a mismatch, or expose a generic pin
294
297
  reset.
295
298
 
296
- For any verified workload that creates an inner Bubblewrap PID namespace and
297
- private `/proc`, CLI 0.8.7 with Runtime 0.1.25 or newer may add
298
- `--nested-private-procfs enable` to the approved Runtime install. Planning with
299
- a read-only checkout, coding in one writable checkout, and independent QA are
300
- common uses. GitHub access, an AI CLI, or subagent delegation alone does not
301
- require it. Omission means `preserve`, which leaves policy state unchanged;
302
- `disable` is an explicit maintenance action. The exception is host-scoped
303
- rather than sandbox-scoped, so separate workloads onto different VPS hosts when
304
- they must not share it.
305
-
306
299
  Omitted lifetime means persistent. A temporary sandbox requires
307
300
  `--confirm TEMPORARY`, expires 15 minutes to 24 hours after first reaching
308
301
  running, and permanently deletes its workspace at expiry. Never describe a
@@ -314,6 +307,38 @@ pinned host keys, then connect only through `warpmetal sandbox connect`.
314
307
  Never give an agent the owner host key, owner token, SSH-derived management
315
308
  token, runtime bootstrap, or node token.
316
309
 
310
+ CLI 0.8.10 or newer can turn the already-applied token-free profile into a
311
+ standard concrete OpenSSH alias. Read [references/runtime.md](references/runtime.md)
312
+ before installing one. Use a separate keypair and grant for each sandbox, and
313
+ pass the sandbox identity—not the VPS owner management key:
314
+
315
+ ```sh
316
+ warpmetal sandbox access install-ssh \
317
+ --connection-file <profile-path> \
318
+ --identity <sandbox-private-key-path> \
319
+ --alias <alias> --json
320
+ ssh <alias>
321
+ ```
322
+
323
+ The local alias preserves the forced gateway: it cannot open a host shell and
324
+ does not relax forwarding denial. Provider authentication and credentials stay
325
+ inside the sandbox. After an authenticated profile refresh, update the alias
326
+ only with the explicit second confirmation:
327
+
328
+ ```sh
329
+ warpmetal sandbox access refresh \
330
+ --server <serverId> --sandbox <sandboxId> --grant <grantId> \
331
+ --connection-file <profile-path> --confirm REFRESH --wait --json
332
+ warpmetal sandbox access install-ssh \
333
+ --connection-file <profile-path> \
334
+ --identity <sandbox-private-key-path> \
335
+ --alias <alias> --confirm REFRESH --json
336
+ ```
337
+
338
+ Remove it only with
339
+ `warpmetal sandbox access remove-ssh --alias <alias> --confirm REMOVE --json`.
340
+ Do not edit the generated fragment or host pin manually.
341
+
317
342
  If the installed CLI lacks a required runtime command, stop, explain the
318
343
  version limitation, and ask before upgrading the official npm package. Do not
319
344
  reconstruct runtime changes with raw HTTP, ad hoc SSH, Podman, Docker, or host
@@ -75,8 +75,11 @@ workflow.
75
75
  For interactive initial purchases, the response may additionally include
76
76
  `humanCheckout.url`, the identical `qrPayload`, `expiresAt`, and an exact
77
77
  `afterPayment.argv` command. The URL is a short-lived bearer capability for the
78
- same charge, not a recipient address. If the buyer pays in the hosted checkout,
79
- do not submit an agent-wallet artifact; run the returned status command and,
78
+ same charge, not a recipient address. Present the URL as a clickable x402api
79
+ handoff. An optional QR contains that exact web link for another-device
80
+ acquisition; scanning it does not authorize payment, and x402api owns any
81
+ wallet-specific choices inside the hosted page. If the buyer pays there, do not
82
+ submit an agent-wallet artifact; run the returned status command and,
80
83
  after ready, follow `ask_human_for_notification_email` to offer lifecycle
81
84
  notices. The CLI does not persist the hosted URL. Renewal commands never expose
82
85
  or use this interactive option.
@@ -213,7 +216,6 @@ warpmetal runtime get --server <serverId> [--wait] [--timeout-seconds <n>] --jso
213
216
  warpmetal runtime install \
214
217
  --server <serverId> [--identity <owner-key>] --ssh-user root \
215
218
  --confirm INSTALL \
216
- [--nested-private-procfs <preserve|enable|disable>] \
217
219
  [--wait] [--timeout-seconds <n>] --json
218
220
 
219
221
  warpmetal sandbox create \
@@ -242,15 +244,6 @@ SCP operation is strict; changed keys, malformed pins, and failed or ambiguous
242
244
  reloads never replace trust. This TOFU step cannot detect an active attacker on
243
245
  the first connection. Provider-console pre-enrollment is optional and stronger.
244
246
 
245
- The nested-private-procfs action requires CLI 0.8.7 and Runtime 0.1.25 or
246
- newer. It defaults to `preserve`. `enable` is a host-level opt-in for any
247
- verified workload that creates an inner Bubblewrap PID namespace and private
248
- `/proc`; read-only planning, single-workspace coding, and independent QA are
249
- common examples. GitHub use, an AI CLI, or subagent delegation alone does not
250
- require it. `disable` unloads WarpMetal's policy and restores the recorded
251
- pre-enable state. It is not a per-sandbox capability because Runtime sandboxes
252
- share one Unix owner.
253
-
254
247
  See [runtime.md](runtime.md) for capacity, lifetime, cleanup, polling, and
255
248
  installation safety. Exit 8 means accepted or pending, never applied.
256
249
 
@@ -268,6 +261,10 @@ warpmetal sandbox access get \
268
261
  warpmetal sandbox access refresh \
269
262
  --server <serverId> --sandbox <sandboxId> --grant <grantId> \
270
263
  --connection-file <profile-path> --confirm REFRESH [--wait] --json
264
+ warpmetal sandbox access install-ssh \
265
+ --connection-file <profile-path> --identity <sandbox-private-key-path> \
266
+ --alias <alias> [--confirm REFRESH] --json
267
+ warpmetal sandbox access remove-ssh --alias <alias> --confirm REMOVE --json
271
268
  warpmetal sandbox access revoke \
272
269
  --server <serverId> --sandbox <sandboxId> --grant <grantId> \
273
270
  --confirm REVOKE [--wait] --json
@@ -282,6 +279,37 @@ creation requires `--wait`.
282
279
  the currently applied grant and API-reported pinned host keys; use it after an
283
280
  OS reload and supervisor reinstall.
284
281
 
282
+ `sandbox access install-ssh` is local-only and requires CLI 0.8.10 or newer.
283
+ It turns the reviewed profile and sandbox-private identity into a concrete
284
+ alias in `~/.ssh/config`. Exact replay is unchanged. If the profile, endpoint,
285
+ pin, or identity changes, first run the authenticated `sandbox access refresh`
286
+ command above, then repeat `sandbox access install-ssh ... --confirm REFRESH`.
287
+ Removal requires exact `--confirm REMOVE` and preserves unrelated SSH config.
288
+
289
+ Use a separate keypair and grant for each sandbox. The alias never uses or
290
+ exposes the VPS owner management key; the forced gateway cannot open a host
291
+ shell, and forwarding remains disabled with `ClearAllForwardings yes`.
292
+ Authentication for user-installed tools happens inside the sandbox. Common
293
+ interactive and one-shot entry points are:
294
+
295
+ ```sh
296
+ ssh <alias>
297
+ ssh -t <alias> codex
298
+ ssh <alias> codex exec '<task>'
299
+ ssh -t <alias> claude
300
+ ssh <alias> claude -p '<task>'
301
+ ssh -t <alias> agent
302
+ ssh <alias> agent -p '<task>'
303
+ ```
304
+
305
+ [Codex Desktop](https://learn.chatgpt.com/docs/remote-connections) reads
306
+ the concrete alias from `~/.ssh/config` and starts Codex through the sandbox
307
+ login shell, so Codex must be installed and on that login-shell `PATH`. The
308
+ tested Cursor Remote SSH route requests prohibited dynamic forwarding and is
309
+ not compatible with this boundary. Keep forwarding denied and use the
310
+ [Cursor CLI](https://cursor.com/docs/cli/overview) interactive or
311
+ [headless](https://cursor.com/docs/cli/headless) commands shown above.
312
+
285
313
  ## Skill installation and state
286
314
 
287
315
  ```sh
@@ -125,9 +125,13 @@ argv arrays returned under `paymentWorkflow`:
125
125
 
126
126
  For an interactive initial purchase, an optional `humanCheckout` object offers
127
127
  a second presentation path for the same charge. Its `url` and `qrPayload` must
128
- be identical hosted-checkout URLs; render that URL as the QR and copyable link,
129
- never a recipient address. If the buyer completes this path, skip agent-wallet
130
- authorization and run `humanCheckout.afterPayment.argv`. Continue bounded
128
+ be identical hosted-checkout URLs. Present `url` as the clickable x402api
129
+ handoff. If a QR is useful for another device, render only the exact
130
+ `qrPayload` and explain that scanning opens the checkout without authorizing
131
+ payment. x402api owns wallet selection and any wallet-specific opening QR
132
+ inside that page; never synthesize a wallet link or render a recipient address.
133
+ If the buyer completes this path, skip agent-wallet authorization and run
134
+ `humanCheckout.afterPayment.argv`. Continue bounded
131
135
  status polling until ready, then ask for the optional lifecycle-notification
132
136
  email when the result returns `ask_human_for_notification_email`. The hosted
133
137
  URL expires at `humanCheckout.expiresAt`, is not persisted by the CLI, and is
@@ -58,7 +58,6 @@ warpmetal runtime install \
58
58
  --identity <owner-private-key-path> \
59
59
  --ssh-user root \
60
60
  --confirm INSTALL \
61
- [--nested-private-procfs <preserve|enable|disable>] \
62
61
  --wait \
63
62
  --json
64
63
  warpmetal runtime get --server <serverId> --wait --json
@@ -81,29 +80,6 @@ is an optional higher-assurance alternative, not a requirement. Only a locally
81
80
  recorded successful reload that reports an owner-host-key refresh creates one
82
81
  new operation-bound trust epoch; failed or ambiguous reloads do not.
83
82
 
84
- `--nested-private-procfs` is supported by `warpmetal` CLI 0.8.7 with Agent
85
- Runtime 0.1.25 or newer. Its default is `preserve`, which makes no AppArmor
86
- policy change. Select `enable` only when this VPS is intentionally dedicated to
87
- a verified workload that creates an inner Bubblewrap PID namespace and private
88
- procfs. Ordinary VPS users and Runtime workloads that rely only on the outer
89
- sandbox do not need it. Select `disable` only during an approved maintenance
90
- action to unload WarpMetal's policy and restore the exact file and loaded-policy
91
- state that existed before enablement.
92
-
93
- Examples include a planner with an exact read-only checkout, a coder with only
94
- one approved checkout and output directory writable, and QA with an exact
95
- candidate plus isolated test processes and scratch space. This protects a
96
- persistent trusted runner from repository-controlled commands and sibling
97
- attempts. GitHub access, installing an AI CLI, and subagent delegation alone do
98
- not require nested private procfs.
99
-
100
- This setting is host-scoped, not sandbox-scoped. Runtime sandboxes share one
101
- Unix owner, so every sandbox on the host can use the exception only through the
102
- signed, root-owned, fixed bwrap path matched by the policy. Enabling it does not
103
- authorize arbitrary bwrap binaries or change the trust boundary for the
104
- Runtime image selected by WarpMetal's authenticated backend. Isolate workloads
105
- on separate VPS hosts if they must not share this host capability.
106
-
107
83
  The signed installer is designed to preserve container workloads already
108
84
  running on a supported host. It selects `crun` for WarpMetal's private rootless
109
85
  Podman service, refuses APT removals and DNF erasures, protects installed
@@ -128,17 +104,6 @@ host automatically:
128
104
  unexpectedly; stop and review the host package logs;
129
105
  - `runtime_legacy_migration_required`: preview Podman state needs a separate,
130
106
  explicitly reviewed migration and was not reset.
131
- - `runtime_nested_private_procfs_architecture_unsupported`: the requested
132
- coding-host policy is unsupported by this CPU architecture;
133
- - `runtime_apparmor_state_unverifiable`: the host's current AppArmor state
134
- cannot be established safely;
135
- - `runtime_apparmor_policy_conflict`: an existing file or loaded-policy state
136
- conflicts with WarpMetal's recorded transaction;
137
- - `runtime_apparmor_policy_rollback_failed`: the installer could not restore
138
- the exact prior AppArmor state; stop and perform operator recovery.
139
- - `runtime_apparmor_policy_recovery_failed`: an interrupted prior policy
140
- transaction could not be recovered; stop and perform operator recovery.
141
-
142
107
  There is no force bypass. If `runtime_reboot_required` is returned, schedule
143
108
  the reboot as a separate maintenance action and retry only after the host and
144
109
  its existing workloads are healthy. The ordinary installer never installs a
@@ -262,6 +227,93 @@ The sandbox record is retained, but its old workspace is not; reconciliation
262
227
  creates a new empty workspace. Never bypass a host-key mismatch or reuse the
263
228
  pre-reload profile.
264
229
 
230
+ ### Install a concrete OpenSSH alias
231
+
232
+ CLI 0.8.10 or newer can install the reviewed profile as a standard local alias
233
+ without another API request:
234
+
235
+ ```sh
236
+ warpmetal sandbox access install-ssh \
237
+ --connection-file <profile-path> \
238
+ --identity <sandbox-private-key-path> \
239
+ --alias <alias> \
240
+ --json
241
+ ```
242
+
243
+ Use a separate keypair and grant for each sandbox. The identity must be the
244
+ private half of that sandbox grant, never the VPS owner management key. The
245
+ command validates the closed token-free profile and its fingerprints, then
246
+ prepends a managed include to `~/.ssh/config`. It writes a private alias
247
+ fragment and dedicated pinned known-hosts file. Exact reinstall is idempotent.
248
+
249
+ If an authenticated access refresh changes the profile, endpoint, host pin, or
250
+ identity, run the server-backed profile refresh first and then explicitly
251
+ replace the local alias:
252
+
253
+ ```sh
254
+ warpmetal sandbox access refresh \
255
+ --server <serverId> \
256
+ --sandbox <sandboxId> \
257
+ --grant <grantId> \
258
+ --connection-file <profile-path> \
259
+ --confirm REFRESH \
260
+ --wait \
261
+ --json
262
+ warpmetal sandbox access install-ssh \
263
+ --connection-file <profile-path> \
264
+ --identity <sandbox-private-key-path> \
265
+ --alias <alias> \
266
+ --confirm REFRESH \
267
+ --json
268
+ ```
269
+
270
+ Never replace a pin merely because an SSH connection reports a mismatch. The
271
+ alias installer consumes only the already-refreshed API profile and does not
272
+ scan or trust a network key. Remove one alias without changing unrelated SSH
273
+ configuration:
274
+
275
+ ```sh
276
+ warpmetal sandbox access remove-ssh --alias <alias> --confirm REMOVE --json
277
+ ```
278
+
279
+ The generated host block pins the exact host keys, selects only the sandbox
280
+ identity, disables password and keyboard-interactive authentication, retains
281
+ `ClearAllForwardings yes`, disables agent/X11 forwarding and local commands,
282
+ and contains neither `RemoteCommand` nor `RequestTTY`. The existing server-side
283
+ forced gateway still maps the key to exactly one sandbox. The alias cannot open
284
+ a host shell and never uses or exposes the owner management key.
285
+
286
+ After installing and authenticating each provider tool inside the sandbox, use
287
+ the alias for interactive or one-shot work:
288
+
289
+ ```sh
290
+ ssh <alias>
291
+ ssh -t <alias> codex
292
+ ssh <alias> codex exec '<task>'
293
+ ssh -t <alias> claude
294
+ ssh <alias> claude -p '<task>'
295
+ ssh -t <alias> agent
296
+ ssh <alias> agent -p '<task>'
297
+ ```
298
+
299
+ Provider authentication and credentials are sandbox-owned and persist only in
300
+ the sandbox home. WarpMetal does not install, authenticate, configure, or
301
+ receive credentials for Codex, Claude Code, or Cursor CLI.
302
+
303
+ [Codex Desktop](https://learn.chatgpt.com/docs/remote-connections)
304
+ discovers a concrete alias through `~/.ssh/config`, requires ordinary
305
+ `ssh <alias>` connectivity, and launches the remote app server through the
306
+ login shell. Codex must therefore be installed inside the sandbox and on the
307
+ login-shell `PATH` before selecting the alias in Codex Desktop.
308
+
309
+ The tested Cursor Remote SSH path requests dynamic forwarding, which the
310
+ Runtime correctly denies, so Cursor IDE remote access is not supported by this
311
+ restricted alias. Do not relax forwarding controls. Use the official
312
+ [Cursor CLI](https://cursor.com/docs/cli/overview) interactively with
313
+ `ssh -t <alias> agent` or in
314
+ [headless mode](https://cursor.com/docs/cli/headless) with
315
+ `ssh <alias> agent -p '<task>'` instead.
316
+
265
317
  Connect without an owner management credential:
266
318
 
267
319
  ```sh