Support workspace tasks across a shared root with scope-driven repositories and verifiable merge gates. - Route task work through one workspace directory with per-repository acquisition and isolation. - Add sandbox session policies and per-repository verification command handling. - Enforce required pre-merge checks and honest merge blocking for workspace changes. - Update workspace, workflow, and sandbox documentation and release metadata. Files changed: .changeset/fn-158-workspace-single-root.md | 7 + docs/sandbox.md | 6 +- docs/workflow-steps.md | 6 +- docs/workspaces.md | 12 +- .../core/src/__tests__/legacy-adoption.test.ts | 15 +- .../src/__tests__/required-pre-merge-steps.test.ts | 25 ++++ .../core/src/__tests__/store-bypass-review.test.ts | 24 ++- packages/core/src/__tests__/task-merge.test.ts | 24 +++ .../core/src/__tests__/worktree-layout.test.ts | 29 ++++ packages/core/src/db/legacy-adoption.ts | 20 ++- packages/core/src/index.gate.ts | 4 + packages/core/src/index.ts | 4 + .../core/src/merge/required-pre-merge-steps.ts | 26 ++++ packages/core/src/merge/task-merge.ts | 35 ++++- packages/core/src/store.ts | 59 ++++++-- packages/core/src/task-store/lifecycle-ops.ts | 1 + packages/core/src/task-store/merge-queue-ops.ts | 5 +- packages/core/src/task-store/moves.ts | 13 +- packages/core/src/task-store/task-artifacts-ops.ts | 11 +- packages/core/src/tasks/worktree-layout.ts | 43 +++++- packages/core/src/types/workflow/workflow-steps.ts | 3 +- .../executor-workspace-session-cwd.test.ts | 42 ++++-- .../src/__tests__/node-worktree-isolation.test.ts | 13 +- .../src/__tests__/pi-create-fn-agent.test.ts | 16 ++ .../engine/src/__tests__/project-engine.test.ts | 20 ++- .../src/__tests__/reviewer-workspace.test.ts | 30 +++- .../src/__tests__/run-verification-command.test.ts | 90 +++++++++++- .../__tests__/sandbox/sandbox-exec-policy.test.ts | 16 +- .../src/__tests__/sandbox/session-policy.test.ts | 45 ++++++ .../__tests__/workspace-add-repo-midflight.test.ts | 9 ++ .../engine/src/__tests__/workspace-e2e.test.ts | 13 +- .../workspace-root-worktree-routing.test.ts | 18 +-- packages/engine/src/agent-tools.ts | 15 +- packages/engine/src/agents/agent-runtime.ts | 19 +++ .../engine/src/agents/agent-session-helpers.ts | 15 ++ packages/engine/src/execution/hold-release.ts | 29 ++++ .../engine/src/execution/run-verification-tool.ts | 114 ++++++++++++++- .../create-authoritative-workflow-seams.ts | 20 +-- packages/engine/src/executor/deps-bags.ts | 5 +- .../executor/ensure-graph-custom-node-worktree.ts | 24 ++- .../executor/ensure-task-worktree-for-planning.ts | 36 ++--- .../engine/src/executor/execute-workflow-step.ts | 4 +- .../src/executor/finalize-already-reviewed-task.ts | 6 +- .../src/executor/prepare-graph-node-execution.ts | 14 +- .../engine/src/executor/run-graph-custom-node.ts | 161 +++++++++++++-------- packages/engine/src/executor/run-implementation.ts | 117 ++++++++++++--- packages/engine/src/merge/merger-ai.ts | 16 +- packages/engine/src/merger.ts | 20 ++- packages/engine/src/pi.ts | 150 ++++++++++++++++--- packages/engine/src/project-engine.ts | 10 +- packages/engine/src/runtimes/in-process-runtime.ts | 4 +- packages/engine/src/sandbox/bubblewrap-backend.ts | 55 ++++++- packages/engine/src/sandbox/bubblewrap-policy.ts | 10 +- packages/engine/src/sandbox/index.ts | 1 + .../engine/src/sandbox/sandbox-exec-backend.ts | 45 +++++- packages/engine/src/sandbox/sandbox-exec-policy.ts | 18 ++- packages/engine/src/sandbox/session-policy.ts | 41 ++++++ packages/engine/src/sandbox/types.ts | 11 ++ packages/engine/src/self-healing.ts | 1 + packages/engine/src/triage.ts | 10 ++ .../engine/src/worktree/worktree-acquisition.ts | 53 ++++--- 61 files changed, 1393 insertions(+), 315 deletions(-) Fusion-Task-Id: FN-158 Fusion-Task-Lineage: ba57f5a2-fa69-4210-8ea7-3d124be3deb2 Co-authored-by: Fusion <noreply@runfusion.ai>
4.1 KiB
Sandbox Backends
Linux bubblewrap backend
Fusion supports an opt-in Linux sandbox backend using bubblewrap (bwrap).
- Enable with
sandbox.backend = "bubblewrap" - Default remains
native - If unavailable, behavior follows
failureMode(fail-hardorfallback-native)
Install
- Debian/Ubuntu:
sudo apt install bubblewrap - Fedora:
sudo dnf install bubblewrap
Policy mapping
policyToBwrapArgs() translates sandbox policy into bwrap args:
- Writable binds (
--bind): worktree path, pnpm store path, plus configuredallowedWritePaths - Read-only binds (
--ro-bind): repo root (when distinct), system runtime paths (/usr,/bin,/lib,/lib64), TLS/DNS paths, and node binary directory - Temporary filesystem:
--tmpfs /tmp - Working directory:
--chdir <worktreePath> - Network isolation:
allowNetwork=falseadds--unshare-net - Environment isolation:
--clearenvplus allowlisted passthrough (PATH,HOME,USER,LANG,LC_*,NODE_*,npm_*,PNPM_*,CI,FUSION_*)
Port 4040 guard
Port 4040 is reserved for the production dashboard. Sandbox policy rejects allowedPorts containing 4040 unless allowPort4040Override=true is explicitly set.
Fusion task sessions
Task sessions resolve the backend with prompt override, project setting, then the native default. When an isolating backend is selected, the declared task boundary is its writable root; workspace tasks use their one task directory, and linked repository worktrees additionally receive the Git administration paths required for commits. The agent bash tool and streaming verification both run through that backend. The JavaScript boundary remains active underneath as portable defense in depth when the backend is native or falls back to native.
Defaults remain unchanged: sandboxing is experimental, backend defaults to native, and failureMode defaults to fail-hard because host namespace capability is not universal.
Use fusionWorktreePreset(ctx) to get the standard Fusion-friendly defaults:
- Worktree writable
- pnpm store writable
.fusion/compatibility metadata and task artifacts are not added to writable mounts
Troubleshooting
If you see bwrap: setting up uid map: Permission denied, unprivileged user namespaces may be disabled by host policy/kernel settings. Enable user namespaces or use sandbox.backend = "native" as a fallback.
Related settings
See docs/settings-reference.md for full sandbox settings schema and precedence.
macOS sandbox-exec backend
Fusion supports an opt-in macOS sandbox backend using Apple's sandbox-exec (Seatbelt).
- Enable with
sandbox.backend = "sandbox-exec" - Default remains
native - If unavailable, behavior follows
failureMode(fail-hardorfallback-native)
Install / availability
/usr/bin/sandbox-exec ships with macOS. If detection fails, install Xcode Command Line Tools and retry.
Policy mapping
policyToSbplProfile() translates policy into an SBPL profile:
- Base deny policy with additive allows
- Writable paths: worktree, pnpm store,
/private/tmp, and user temp (/private/var/folders/.../T/) - Read paths: repo root (when needed), Node binary directory, and curated system/runtime paths (
/usr,/bin,/sbin,/System,/Library, resolver/cert/hosts/services/timezone paths) - Network:
allowNetwork=trueenables outbound and local bind,allowNetwork=falsedenies network
Port 4040 guard
Port 4040 is always blocked in the emitted SBPL profile ((deny network-bind (local ip "*:4040"))), and policy rejects explicit 4040 allowance unless allowPort4040Override=true is set.
.fusion/ write guard
Writable paths under .fusion/ (including .fusion/project.json, retained migration inputs, and .fusion/tasks/**) are rejected by policy validation.
Troubleshooting
If commands fail with sandbox-exec: ...: Operation not permitted, expand allowedReadPaths/allowedWritePaths for required inputs/outputs.
Deprecation note
Apple marks sandbox-exec as deprecated. It remains functional for many workflows, but failureMode = "fallback-native" is the recommended hedge when host support varies.