feat(workspaces-sync): auto-publish from codemux-remote hosts#46
Merged
Conversation
Workspaces an agent creates directly on a host (via the MCP
`workspace_create` tool, or a manual `codemux-remote workspace
register`) now surface in every dev device's overview without an
explicit push. The model is deliberately asymmetric: codemux-app
dev devices keep their existing manual push/pull (preserves the
"close laptop, continue in cloud" flow and user agency over what
leaves the device); codemux-remote hosts auto-publish because
they're always-on, SSH-reachable, and exist to be used as hosts.
Pipeline:
1. `codemux-remote workspace list` CLI reads the daemon's SQLite
directly and prints `{host_id, workspaces[]}`. Works even when
the daemon isn't running.
2. `hosts_inventory::spawn` runs every 60s after a 12s warm-up;
per configured host with a server_id it probes (reusing the
`~/.local/bin/codemux-remote` PATH fallback), SSHes
`codemux-remote workspace list`, and reconciles into
`workspaces_sync` as sibling-only rows keyed by
`(host_server_id, origin_uid)`.
3. The existing 30s push tick uploads dirty rows to the cloud, so
other devices see new host-side workspaces within ~90s.
Pull-conflict guard: `AdoptionPreview.same_branch_project_exists_at`
points at the local workspace_id when another local workspace
matches `(basename(project_path), git_branch)` with the remote row.
The dialog renders SameBranchProjectBlock with an "Open the
existing workspace" CTA and hides Pull, so a pull can't silently
clobber work the user is already doing locally.
Schema: additive `ALTER TABLE workspaces_sync ADD COLUMN origin_uid
TEXT`. Local-only — cross-device dedupe for the same physical host
workspace published by two devices simultaneously is best-effort
and converges on the next pull. Tracked as a known limitation.
Touches:
- src-tauri/src/bin/codemux_remote.rs: `workspace list` subcommand
- src-tauri/src/database.rs: origin_uid column + 5 helpers
- src-tauri/src/hosts_inventory.rs: new poller + reconcile
- src-tauri/src/lib.rs: spawn the poller
- src-tauri/src/commands/workspaces_sync.rs: conflict detection
- src/components/workspaces-overview/pull-to-device-dialog.tsx:
SameBranchProjectBlock variant
- docs/features/workspaces-sync.md, remote-hosts.md: design
rationale + identity contract + known limitations
Tests: 33 new unit tests across DB helpers, parser, reconcile,
conflict detection, and dialog variant; 3 new CLI/parse/reconcile
integration tests in tests/codemux_remote_inventory.rs; CLI
shape contract test in tests/codemux_remote_binary.rs. Smoke-
verified against a real codemux-remote on pandora.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
workspace_createtool, orcodemux-remote workspace register) now surface in every dev device's overview within ~90s without an explicit push from any laptop.(basename(project_path), git_branch)match).Pipeline
codemux-remote workspace list [--state-dir]CLI reads the daemon's SQLite directly (no running daemon required) and prints{host_id, workspaces[]}.hosts_inventory::spawnruns every 60s after a 12s warm-up. Per configured host with aserver_id: probe (reusing the~/.local/bin/codemux-remotePATH fallback), SSHcodemux-remote workspace list, reconcile intoworkspaces_syncas sibling-only rows keyed by(host_server_id, origin_uid).workspaces_sync::pushtick uploads dirty rows to the cloud, so other devices see new host-side workspaces within ~90s.Schema
Additive
ALTER TABLE workspaces_sync ADD COLUMN origin_uid TEXT. Local-only — cross-device dedupe of the same physical host workspace published by two devices simultaneously is best-effort and converges on the next pull. Documented as a known limitation indocs/features/workspaces-sync.md.What's unchanged
reconcile_from_snapshotworkspace_id IS NOT NULL; new sibling rows have NULL and are skipped)SameBranchProjectBlocklayered cleanly betweenalreadyAdoptedandcan_host_adopt; falls through to the same branches as before when no conflictTest plan
cargo test --lib workspaces_sync::— 19 pass (4 new for the remote-discovered helpers)cargo test --lib hosts_inventory::— 8 pass (argv lock-in, parser round-trip, reconcile insert/idempotent/rename/soft-delete/per-host scope)cargo test --lib commands::workspaces_sync::— 6 pass (conflict-guard true positives + false-positive guards)cargo test --test codemux_remote_binary— 4 pass (1 new for theworkspace listCLI shape)cargo test --test codemux_remote_inventory— 3 pass (CLI → parser → reconcile round-trip; idempotent re-poll; rename + close propagation)npm test pull-to-device-dialog— 11 pass (1 new forSameBranchProjectBlock)npm run check— cleancargo check --lib— cleancodemux-remote workspace listreturned expected envelope, smoke artifacts cleaned upTwo pre-existing lib failures (
agent_browser::resolve_binary_…,commands::mcp::project_codemux_entry_is_filtered_out) reproduce on clean main, unrelated to this change.