Skip to content

🤖 feat: add multi-project workspace support#2759

Open
ThomasK33 wants to merge 29 commits intomainfrom
workspace-yw8w
Open

🤖 feat: add multi-project workspace support#2759
ThomasK33 wants to merge 29 commits intomainfrom
workspace-yw8w

Conversation

@ThomasK33
Copy link
Member

Summary

Adds VS Code-style multi-root workspace support to Mux. A user can create a single workspace spanning multiple projects (e.g., mux + mux-md). The agent gets one cwd — a container directory with symlinks to per-project worktrees — and works across all projects in a single session. Each project retains its own git identity.

Background

Multi-project workflows are common — an agent fixing a library and its consumer simultaneously, updating docs alongside source code, etc. Today each project gets its own workspace, forcing users to coordinate across separate sessions. This PR enables a single session to span multiple repos.

Implementation

Architecture

  • Container directory: ~/.mux/src/_workspaces/<name>/ contains symlinks (mux/ → worktree, mux-md/ → worktree)
  • Multi-project is an orchestration layer on top of existing per-project runtimes — runtimes themselves don't change
  • All projects share the same RuntimeConfig (mixed runtimes deferred)

New/Changed Components (12 commits)

Phase Component Key Files
1 Data ModelProjectRefSchema, projects field on metadata, isMultiProject()/getProjects() helpers src/common/orpc/schemas/workspace.ts, src/common/utils/multiProject.ts
2 Container Manager — creates/removes symlink container directories src/node/multiProject/containerManager.ts
3 MultiProjectRuntime — wraps per-project runtimes, delegates lifecycle + exec src/node/runtime/multiProjectRuntime.ts
4 Workspace LifecyclecreateMultiProject(), extended remove()/rename(), IPC route src/node/services/workspaceService.ts
5 Git Root DiscoverydiscoverGitRoots() for multi-root workspaces src/node/multiProject/gitRootDiscovery.ts
6 Symlink FixFileChangeTracker canonicalizes paths via realpath() src/node/services/utils/fileChangeTracker.ts
7 Sub-Agent Support — fork orchestrator creates per-project child worktrees + containers src/node/services/utils/forkOrchestrator.ts
8 Agent Context — bash tool description lists project directories src/node/services/tools/bash.ts
9 UI — "Multi-Project" sidebar section, command palette action, creation modal src/browser/components/ProjectSidebar/, MultiProjectWorkspaceCreateModal/
10 Refactor — centralized MULTI_PROJECT_CONFIG_KEY constant src/common/constants/multiProject.ts

Config Storage

Multi-project workspaces are stored under a synthetic "_multi" key in config.json:

{
  "projects": {
    "/path/to/mux": { "workspaces": [...] },
    "_multi": {
      "workspaces": [{
        "id": "abc1234567",
        "name": "my-feature",
        "projects": [
          { "projectPath": "/path/to/mux", "projectName": "mux" },
          { "projectPath": "/path/to/mux-md", "projectName": "mux-md" }
        ]
      }]
    }
  }
}

Validation

  • 29 new tests across 6 test files — all pass
  • 116 existing regression tests verified — no regressions
  • make static-check passes clean (typecheck + lint + formatting + docs links)

Risks

  • Config "_multi" key: new convention that config loading/filtering must handle. Existing workspaces unaffected (the projects field is optional).
  • Git status polling: N scripts instead of 1 per multi-project workspace. Mitigated by staggering/focus-based polling (deferred optimization).
  • Scattered git calls: ~6-8 files need multi-root updates for full git integration; this PR includes the discoverGitRoots() utility but integration into gitPatchArtifactService and gitStatus is deferred.

📋 Implementation Plan

Phase 1 — Data Model & Helpers

  • ProjectRefSchema with projectPath + projectName
  • Optional projects array on WorkspaceMetadataSchema and WorkspaceConfigSchema
  • isMultiProject() and getProjects() utility functions

Phase 2 — Container Directory Management

  • ContainerManager class: createContainer(), removeContainer(), getContainerPath()
  • Containers live at {srcBaseDir}/_workspaces/{workspaceName}/
  • Symlinks to per-project workspace directories

Phase 3 — MultiProjectRuntime Wrapper

  • Implements Runtime interface
  • Delegates lifecycle to per-project runtimes
  • Uses container path as cwd for exec

Phase 4 — Workspace Lifecycle

  • createMultiProject() on WorkspaceService with rollback on partial failure
  • Extended remove() to clean up all per-project workspaces + container
  • Extended rename() to rename all per-project workspaces + recreate container
  • IPC route workspace.createMultiProject

Phase 5 — Git Multi-Root Awareness

  • discoverGitRoots() — scans workspace for .git dirs in children

Phase 6 — FileChangeTracker Symlink Fix

  • realpath() canonicalization for file path storage

Phase 7 — Sub-Agent Support

  • Extended orchestrateFork for multi-project parents
  • Child workspaces inherit projects array

Phase 8 — Agent Context

  • buildBashToolDescription() lists project directories for multi-project workspaces

Phase 9 — UI

  • "Multi-Project" sidebar section
  • Command palette action + creation modal with project picker

Phase 10 — Refactor

  • Centralized MULTI_PROJECT_CONFIG_KEY constant

Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $32.73

@ThomasK33
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 212c278739

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed all 3 review comments:

  1. Multi-project cwd anchored to container pathAIService now creates MultiProjectRuntime for multi-project workspaces, ensuring getWorkspacePath() returns the _workspaces/<name> container path.
  2. Partial rename rollback — Added rollback logic that reverses already-renamed projects when a later rename fails, with logged errors for rollback failures.
  3. _multi marked as system project — Config entry now sets projectKind: "system" to hide from user-facing project lists.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e03a8da7d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed both round-2 comments:

  1. Multi-project initcreateMultiProject() now runs postCreateSetup + initWorkspace for each per-project runtime (matching the create() flow), with aggregated completion tracking and cancellation support.
  2. Container rename rollback — If createContainer() fails after renaming all project workspaces, all renames are rolled back before returning the error.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc2bd02e71

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed the remaining comment: rename failure catch block now recreates the old container (with original symlinks) after rolling back per-project renames, ensuring the workspace cwd remains functional even when container recreation fails.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4ee3291978

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed both comments:

  1. Path traversal validationcreateContainer() now validates each projectName is a safe path segment (rejects .., path separators, empty names) using path.posix.basename() + path.win32.basename() comparison.
  2. Runtime type guard — Both createMultiProject() and multi-project fork branch now reject non-local/worktree runtimes upfront with a clear error message, preventing SSH/Docker container creation attempts.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7a7835cc3d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed both comments:

  1. Fork metadata pass-throughWorkspaceService.fork() now passes parentMetadata to orchestrateFork(), enabling the multi-project fork path for user-initiated forks.
  2. Per-project trust resolution — Multi-project fork now resolves trust from config per-project instead of using a single shared flag. Added regression test verifying per-project trust differentiation.

@ThomasK33
Copy link
Member Author

@codex review

Rebased on main and resolved conflicts. All previous Codex comments have been addressed and threads resolved.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 18adf5b857

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed both comments:

  1. Per-project trunk in createMultiProject — Each project now resolves its own trunk branch via listLocalBranches + detectDefaultTrunkBranch, with fallback to the caller-provided branch. Supports repos with different default branches (e.g., main vs master).
  2. Per-project fallback trunk in fork — Multi-project fork fallback createWorkspace() now resolves trunk per-project using resolveMultiProjectFallbackTrunkBranch().

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e03c7f3444

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed: fork() now persists projects array on child workspace via forkResult.data.projects ?? sourceMetadata.projects, ensuring forked multi-project workspaces retain all project references on reload.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cbf1cf41cd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed both comments:

  1. Trust default — Unknown projects in multi-project forks now default to false (untrusted) instead of inheriting primary project trust.
  2. Multi-project initMultiProjectRuntime.initWorkspace() now iterates over ALL project runtimes, running init hooks for each with per-project paths. Returns aggregate result (first failure if any).

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca6f4a93da

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed both P2 comments:

  1. Project deletion guardProjectService.remove() now scans _multi workspace references before allowing project deletion. Projects referenced by active multi-project workspaces are blocked from removal.
  2. Per-project init envMultiProjectRuntime now supports an envResolver callback for per-project secret resolution during init. The fork flow wires this up to getEffectiveSecrets() per project.

@ThomasK33
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 638d12bfaf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed both P1 comments:

  1. Task fork env resolvertaskService.ts now sets envResolver on MultiProjectRuntime after fork, resolving per-project secrets via getEffectiveSecrets() with a per-project cache. Matches the existing workspaceService.ts fork pattern.
  2. Container deletion orderingremove() now attempts per-project deletions first and only removes the container after confirming all succeeded (or when force=true). Container stays intact if a deletion fails without force.

@ThomasK33
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d731b5012a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3928517835

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed both new findings:

  1. P1: Secrets merging — Added mergeMultiProjectSecrets() in aiService that collects secrets from all constituent projects, with primary project precedence on key conflicts.
  2. P2: Queued task fallback — When parent metadata lookup fails but the queued task has a projects array, we now synthesize minimal metadata to preserve multi-project fork behavior.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 976f3ac344

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed the trust gate finding — added upfront trust check in multi-project fork path that verifies all projects are trusted before any fork/create work begins. Returns error immediately if any project is untrusted.

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant