feat(open): add Claude desktop to the 'open in' apps (CLI + hub)#176
Conversation
'agentbox open <box> --in claude' registers the box in the Claude desktop
app. Claude has no codex-style add-SSH deep link, but it reads SSH
environments from its own settings — ~/.claude/settings.json sshConfigs,
where sshHost accepts an ~/.ssh/config alias — so the CLI upserts
{id: agentbox-<alias>, name: AgentBox: <box>, sshHost: <alias>,
startDirectory: /workspace} there directly (schema verified against
Claude.app v1.19367) and launches the app; the box appears in its
Environment dropdown, where the app can also list/resume the box's
existing Claude sessions over SSH.
The upsert (apps/cli/src/lib/claude-app-config.ts) matches by id,
preserves every foreign entry and settings key, and refuses to touch a
settings file that doesn't parse. 'agentbox destroy' prunes the box's
entry. The persistent-SSH gate + alias write is shared with codex via
ensurePersistentSshAlias (docker + hetzner boxes). The hub's box-detail
Apps row gains the Claude launcher (validator, backend types, UI entry).
Verified live on a hetzner box: settings diff is exactly one entry,
double-open stays a single entry, the alias connects over plain ssh, and
the hub POST /boxes/:id/open {app: claude} launches the app.
Claude-Session: https://claude.ai/code/session_0156d47n9hxNTCAuyjX7rEch
|
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 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 50b832e. Configure here.
| } | ||
| } catch { | ||
| /* best-effort */ | ||
| } |
There was a problem hiding this comment.
Hub destroy skips Claude cleanup
Medium Severity
removeClaudeSshConfigs runs only in the agentbox destroy CLI action. Hub lifecycle destroy (UI and POST …/destroy) and the dashboard destroy path call provider.destroy directly and never prune the box’s sshConfigs entry, so environments opened via the hub can remain in Claude after the box is gone.
Reviewed by Cursor Bugbot for commit 50b832e. Configure here.
There was a problem hiding this comment.
Fixed in 7b11a1a — good catch. The writer moved into @agentbox/sandbox-core and the pruning now runs inside syncAgentboxSshConfig as an agentbox-prefixed orphan sweep against live box names: every lifecycle path syncs the ssh config (docker destroyBox — which the hub's provider.destroy reaches — CLI cloud destroy, and any later create/start/open), so an entry left by a path that skipped the sync self-heals on the next one. Verified live: seeded a fake agentbox-ghost-box entry, triggered a sync, orphan swept while the live box's entry and foreign entries survived.
… CLI destroy Bugbot: hub/dashboard destroys call provider.destroy directly and skipped the CLI-destroy-only prune, leaving dead environments in Claude. Move the writer into @agentbox/sandbox-core and sweep agentbox-prefixed orphans inside syncAgentboxSshConfig — every lifecycle path syncs (docker destroyBox, CLI cloud destroy, create/start), so an entry left by a path that skipped the sync self-heals on the next one. Foreign entries are never touched; a corrupt settings.json never breaks lifecycle (best-effort there, still fail-loud on explicit open --in claude). Claude-Session: https://claude.ai/code/session_0156d47n9hxNTCAuyjX7rEch


What
Adds
claudeto the open-in targets:agentbox open <box> --in clauderegisters the box in the Claude desktop app, and the hub's box-detail Apps row gains the matching launcher.Claude has no codex-style add-SSH deep link, but it reads SSH environments from its own settings —
~/.claude/settings.json→sshConfigs, wheresshHostaccepts an alias from~/.ssh/config(schema verified against Claude.app v1.19367's bundle). Since AgentBox runs on the host, the CLI upserts the entry directly:{ "id": "agentbox-<alias>", "name": "AgentBox: <box>", "sshHost": "<alias>", "startDirectory": "/workspace" }then launches the app — the box appears in Claude's Environment dropdown, where the app can also list and resume the box's existing Claude sessions over SSH (it syncs remote transcripts). Using the alias (not raw host/port) keeps the entry evergreen: docker's ephemeral loopback sshd port changes across restarts, but
syncAgentboxSshConfigkeeps the alias fresh.How
apps/cli/src/lib/claude-app-config.ts(new): id-keyed upsert intosshConfigsthat preserves every foreign entry and settings key, and refuses to touch a settings file that doesn't parse (it's the user's real Claude Code settings).agentbox destroyprunes the box's entry (best-effort).openInCodexintoensurePersistentSshAlias, shared by both app targets (docker + hetzner boxes; same actionable errors for daytona/vercel/e2b and pre-sshd docker boxes).claudeadded toOPEN_IN_APPS(validator),OpenInApp(backend types), and the Apps row (existingIcons.claudeglyph). The probe/open plumbing shells the CLI, so no backend logic changed.cli.mdx,access-your-box.mdx,docs/features.md.Verification
~/.claude/settings.json).open --in claude→ before/after diff of the real settings.json is exactly one entry; double-open stays a single entry;ssh <alias>connects (the exact command Claude.app spawns); Claude.app launched with the box in the Environment dropdown.GET /api/v1/open-targetsreportsclaude (docker, hetzner);POST /api/v1/boxes/:id/open {"app":"claude"}→{"ok":true}and the app opened; invalid app rejected with the updated list.Follow-up (separate repo): add Claude to the tray app's Open In… menu if it hardcodes the list.
https://claude.ai/code/session_0156d47n9hxNTCAuyjX7rEch
Note
Medium Risk
The CLI reads and writes the user's real
~/.claude/settings.json; safeguards limit blast radius but corrupt or unexpected schema could still block open/destroy cleanup until fixed manually.Overview
Adds
claudeas a first-classagentbox open --intarget alongside Codex, with the same docker + Hetzner persistent-SSH gating surfaced inopen --targetsand the hub/tray open-in lists.open --in claudereuses a new sharedensurePersistentSshAlias(factored out of the Codex path) to sync the box SSH alias, then upserts ansshConfigsentry in~/.claude/settings.json(no Codex-style deep link) and launches Claude.app so the box appears in the Environment dropdown.claude-app-config.tsowns read/merge/write byid, preserves unrelated settings, and refuses to modify invalid JSON.agentbox destroybest-effort removes the matchingagentbox-<alias>entry so stale SSH connections don’t linger. Hub/API types and the box Access → Apps row include Claude; docs updated.Reviewed by Cursor Bugbot for commit 50b832e. Configure here.