feat(cli): agentbox shell --ssh-config for Codex / Claude desktop SSH#118
Conversation
…op SSH Write a `~/.ssh/config` alias on demand so external apps (the Codex app, Claude desktop) can connect to a box over plain SSH, and surface the identity-file path + a Codex deep link. - New `agentbox shell <box> --ssh-config` (+ `--json`): brings the box online, writes the alias, prints alias/host/user/identity + the `codex://settings/connections/ssh/add?name=<alias>` link and Claude desktop instructions. Gated to providers with a persistent per-box key (Hetzner) — Docker/Daytona/Vercel/E2B exit cleanly without writing. - Extract the shared bring-online → buildAttach → parseSshTarget → write alias flow into `cloud-ssh.ts` (`resolveCloudSshTarget` / `ensureCloudSshAlias`); reuse it from `code` and `open`. - Alias is now the box name (clean `ssh <box>` + Codex `name=` param); add `readAgentboxSshAlias` and surface `ssh alias` / `ssh identity` in cloud `inspect`. - Document the flow in the agentbox-info and fork skills. Claude-Session: https://claude.ai/code/session_011VoAz7mUaUGh6dKAvr7kAP
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 4 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3ece428. Configure here.
| * leave `~/.ssh/config` untouched. | ||
| */ | ||
| async function runSshConfig(box: BoxRecord, opts: ShellOptions): Promise<void> { | ||
| const conn = await resolveCloudSshTarget(box); |
There was a problem hiding this comment.
Docker box started before failure
Medium Severity
runSshConfig always calls resolveCloudSshTarget, which resumes or starts the box before checking SSH support. On Docker boxes (no buildAttach), the command still unpause/start the container, then errors—contrary to the documented “exit cleanly without writing config” behavior for unsupported providers.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 3ece428. Configure here.
| */ | ||
| export function agentboxAliasFor(boxName: string): string { | ||
| return `agentbox-cloud-${boxName}`; | ||
| return boxName; |
There was a problem hiding this comment.
SSH alias collides with user Host
Medium Severity
agentboxAliasFor now uses the bare box name as the Host alias. If the user already has a Host entry with that name in ~/.ssh/config, OpenSSH applies the first matching stanza per keyword, so the appended agentbox block may not supply the VPS HostName, key, or user—breaking ssh <box>, Codex, and Claude desktop handoff.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 3ece428. Configure here.
| */ | ||
| export function agentboxAliasFor(boxName: string): string { | ||
| return `agentbox-cloud-${boxName}`; | ||
| return boxName; |
There was a problem hiding this comment.
Legacy SSH blocks not removed
Low Severity
Renaming the managed alias to the box name means stripBlock / removeAgentboxSshAlias only touch markers for the new alias. Existing agentbox-cloud-<box> blocks from earlier releases are never removed on rewrite or destroy, leaving stale Host entries and confusing SSH config.
Reviewed by Cursor Bugbot for commit 3ece428. Configure here.
| // Mint the SSH target and (re)write the `~/.ssh/config` alias. Shared with | ||
| // `agentbox open` and `agentbox shell --ssh-config`. The inner tmux command | ||
| // is irrelevant here (Remote-SSH starts its own session). | ||
| const { alias } = await ensureCloudSshAlias(box); |
There was a problem hiding this comment.
Duplicate cloud lifecycle calls
Low Severity
prepareCloudAttach still runs pause/resume/start via probeState, then calls ensureCloudSshAlias, which runs the same lifecycle again inside resolveCloudSshTarget. The refactor duplicated bring-online logic instead of delegating once.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 3ece428. Configure here.
- Check SSH support (`buildAttach`) before any lifecycle action so an unsupported box (e.g. a stopped Docker box) errors without being started; add a `bringOnline` option to skip a redundant lifecycle pass. - `agentbox code` now passes `bringOnline: false` (it already brings the box online + waits) — removes the duplicate resume/start. - Migrate away legacy `agentbox-cloud-<box>` blocks on write/remove so the box-name rename doesn't leave stale Host entries behind. - Warn (don't fail) when `~/.ssh/config` already has a user-authored `Host <box>` that could shadow agentbox's entry. - Tests for legacy-block migration and conflict detection. Claude-Session: https://claude.ai/code/session_011VoAz7mUaUGh6dKAvr7kAP


What
Adds an explicit way to connect external apps (the Codex app, Claude desktop) to a box over plain SSH.
agentbox shell <box> --ssh-config(+--json) brings the box online, writes a~/.ssh/configalias, and prints the alias, host, user, identity-file path, a readyssh <box>command, the Codex deep linkcodex://settings/connections/ssh/add?name=<box>, and Claude-desktop instructions.Details
cloud-ssh.ts— extracted the duplicated "bring online →buildAttach→parseSshTarget→ write alias" flow intoresolveCloudSshTarget/ensureCloudSshAlias; reused fromcodeandopen.ssh <box>and Codexname=param). AddedreadAgentboxSshAliasand surfacedssh alias/ssh identityrows in cloudstatus --inspect.Verification
ssh-config.test.ts), plugin-skill bundle in sync ✅--ssh-configwrote the alias with the real IP + identity file;ssh <box>connected asvscode;--jsonandstatus --inspectcorrect; docker box hit the negative gate with no config write. Boxes torn down after.https://claude.ai/code/session_011VoAz7mUaUGh6dKAvr7kAP
Note
Medium Risk
Touches
~/.ssh/configand changes SSH Host alias naming (breaking for anyone relying onagentbox-cloud-*); Hetzner gating limits blast radius for external-app handoff.Overview
Adds
agentbox shell <box> --ssh-config(and--json) so Codex and Claude desktop can connect over SSH without opening an interactive shell. The command brings the box online, writes a managedHost <box-name>block in~/.ssh/config, and prints connection details plus a Codex deep link.Hetzner-only: resolution happens before any write; boxes without a persistent per-box
identityFile(Docker, Daytona token auth, etc.) exit with a clear error and leave~/.ssh/configunchanged.Refactor: duplicated cloud SSH logic moves into
cloud-ssh.ts(resolveCloudSshTarget/ensureCloudSshAlias), reused byagentbox codeandagentbox open.SSH aliases change from
agentbox-cloud-<name>to the box name itself.readAgentboxSshAliasand newssh alias/ssh identityrows on cloudinspectoutput. Host skills document the workflow.Reviewed by Cursor Bugbot for commit 3ece428. Configure here.