Back to Cmux

V2 Socket API + Test Migration

docs/v2-api-migration.md

1.38.15.1 KB
Original Source

V2 Socket API + Test Migration

This doc tracks the migration from the existing v1 line protocol (space-delimited commands) to a v2 JSON protocol intended for LLM agents.

Goals

  • Add a v2 JSON socket protocol (handle-based: window_id, workspace_id, pane_id, surface_id).
  • Keep v1 fully working until v2 reaches feature parity.
  • Re-implement the existing automated test suite to use v2.
  • Run both suites:
    • v1 tests (existing tests/)
    • v2 tests (new tests_v2/)

Non-Goals (for initial parity)

  • Removing v1.
  • Changing existing v1 behaviors/output formats.

Status

  • Implement v2 request/response envelope (JSON, newline-delimited)
  • Implement v2 core methods (workspaces/surfaces/panes/input/notifications/browser)
  • Implement v2 multi-window methods (windows + cross-window workspace moves)
  • Add surface.trigger_flash (agent-visible highlight for a surface)
  • Implement v2 debug/test methods (simulate typing, render stats, screenshots, etc.)
  • Add tests_v2/ using v2 client
  • Add runners for v1 + v2 suites on the VM (./scripts/run-tests-v1.sh, ./scripts/run-tests-v2.sh)
  • Verify v1 suite passes (VM)
  • Verify v2 suite passes (VM)

Notes:

  • A close-top nested split sequence (T-shape) could leave terminal views detached from the window until the user switched workspaces. Fix: a debounced post-close reattach pass (see Sources/Workspace.swift, Sources/Panels/TerminalPanel.swift).

V2 Protocol Sketch

Each request is one JSON object per line:

json
{"id":"1","method":"workspace.list","params":{}}

Each response is one JSON object per line:

json
{"id":"1","ok":true,"result":{...}}

Errors:

json
{"id":"1","ok":false,"error":{"code":"not_found","message":"workspace not found"}}

Notes:

  • id is echoed back when present (string or number).
  • v2 methods should accept IDs; v2 responses may include ephemeral index fields for ordering/debugging, but IDs are the stable handles.

Method Parity Checklist (v1 -> v2)

Windows:

  • list_windows -> window.list
  • current_window -> window.current
  • focus_window -> window.focus
  • new_window -> window.create
  • close_window -> window.close
  • move_workspace_to_window -> workspace.move_to_window

Workspaces:

  • list_workspaces -> workspace.list
  • new_workspace -> workspace.create
  • select_workspace -> workspace.select
  • current_workspace -> workspace.current
  • close_workspace -> workspace.close

Surfaces / Splits:

  • list_surfaces -> surface.list
  • focus_surface / focus_surface_by_panel -> surface.focus
  • new_split -> surface.split
  • new_surface -> surface.create
  • close_surface -> surface.close
  • drag_surface_to_split -> surface.drag_to_split
  • refresh_surfaces -> surface.refresh
  • surface_health -> surface.health
  • trigger_flash -> surface.trigger_flash (new in v2)

Panes:

  • list_panes -> pane.list
  • focus_pane -> pane.focus
  • list_pane_surfaces -> pane.surfaces
  • new_pane -> pane.create

Input:

  • send / send_surface -> surface.send_text
  • send_key / send_key_surface -> surface.send_key

Notifications:

  • notify -> notification.create
  • notify_surface -> notification.create_for_surface
  • notify_target -> notification.create_for_target
  • list_notifications -> notification.list
  • clear_notifications -> notification.clear
  • set_app_focus -> app.focus_override.set
  • simulate_app_active -> app.simulate_active

Browser:

  • open_browser -> browser.open_split
  • navigate -> browser.navigate
  • browser_back -> browser.back
  • browser_forward -> browser.forward
  • browser_reload -> browser.reload
  • get_url -> browser.url.get
  • focus_webview -> browser.focus_webview
  • is_webview_focused -> browser.is_webview_focused

Debug / Test-only:

  • set_shortcut -> debug.shortcut.set
  • simulate_shortcut -> debug.shortcut.simulate
  • simulate_type -> debug.type
  • activate_app -> debug.app.activate
  • is_terminal_focused -> debug.terminal.is_focused
  • read_terminal_text -> debug.terminal.read_text
  • render_stats -> debug.terminal.render_stats
  • layout_debug -> debug.layout
  • bonsplit_underflow_count/reset -> debug.bonsplit_underflow.*
  • empty_panel_count/reset -> debug.empty_panel.*
  • focus_notification -> debug.notification.focus
  • flash_count/reset -> debug.flash.*
  • panel_snapshot/panel_snapshot_reset -> debug.panel_snapshot.*
  • screenshot -> debug.window.screenshot

Test Migration

v1 suite stays in tests/.

v2 suite lives in tests_v2/ and should:

  • use a v2 JSON client (tests_v2/cmux.py)
  • avoid depending on v1 text output formats

VM runners:

  • v1: ssh cmux-vm 'cd /Users/cmux/GhosttyTabs && ./scripts/run-tests-v1.sh'
  • v2: ssh cmux-vm 'cd /Users/cmux/GhosttyTabs && ./scripts/run-tests-v2.sh'

Open Questions

  • Should v2 require explicit workspace_id/surface_id for all operations, or default to the currently-focused ones?
  • For move/reorder operations (future): what are the policies for empty workspaces/windows?