Skip to content

fix(mxc): agent tools fail in Windows workspace subdirectories - #115399

Merged
RomneyDa merged 3 commits into
openclaw:mainfrom
paulcam206:paulcam/mxc-workdir-validation
Aug 11, 2026
Merged

RomneyDa merged 3 commits into
openclaw:mainfrom
paulcam206:paulcam/mxc-workdir-validation

Conversation

@paulcam206

@paulcam206 paulcam206 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Two failures on the MXC sandbox backend.

Agent tools could not run from Windows workspace subdirectories. A valid
child of the agent workspace written with slash-normalized Windows path
semantics was rejected. Invalid workdirs also failed inconsistently:
validateWorkdir is contracted to return null when a workdir is unusable,
but only ENOENT counted as "missing", so a workdir nested under a file raised
ENOTDIR on Linux and escaped as a raw filesystem error.

Every MXC sandbox provisioning attempt crashed. Building the filesystem
bridge threw before any tool could run:

SandboxProvisioningError: Cannot read properties of undefined (reading 'containerWorkdir')

Why This Change Was Made

MXC now owns validation of agent-selected workdirs by opting into the
backend-owned workdirValidation contract, reusing its existing workspace
resolver for canonicalization, containment, existence, and directory checks
before execution. Generic Docker and SSH path behavior is unchanged.

The ENOENT-only classification appeared at three sibling sites in the same
file, so a shared isMissingPathError guard fixes the class rather than the
one reported path.

The provisioning crash was a class-field initialization-order bug.
MxcFsBridge initialized three fields from this.sandbox, but sandbox is a
constructor parameter property. Plugin sources load through jiti, which
evaluates field initializers before assigning parameter properties, so
this.sandbox was undefined. Those fields are now assigned in the
constructor body from the parameter.

User Impact

Agents configured with the MXC backend can provision a sandbox at all, and can
execute tools from valid Windows workspace subdirectories. Invalid, missing,
out-of-workspace, and nested-under-a-file directories are rejected before MXC
launches and surface as a normal unavailable-workdir result rather than a raw
filesystem error.

Evidence

Exact head and base

  • Head: 88ce07175543df5400d0122d2a55d12e41ec73c8
  • Base: e69c3df2361b38285917c29b0c90867c75b8ebe9 (current main at rebase)
  • Scope: extensions/mxc/src/mxc-backend.ts,
    extensions/mxc/src/fs-bridge.ts,
    extensions/mxc/test/mxc-backend.test.ts (+56 / -7)

Local checks

  • node scripts/run-vitest.mjs extensions/mxc/test/mxc-backend.test.ts — 49/49
  • pnpm tsgo — clean
  • oxfmt --check on all three changed files — clean
  • CRLF-aware whitespace check — clean

Real Windows proof

Fresh Hyper-V desktop guest hydrated from this exact head via
.github/workflows/crabbox-hydrate.yml (hydrate-windows-daemon):

01-vitest-49
01-vitest-49.mp4
01-vitest-49 contact

Runtime proof of the provisioning fix

The test suite cannot cover the provisioning crash. tsconfig.json sets
useDefineForClassFields: false, so tsgo and Vitest both apply legacy field
ordering and the buggy code passes them — it passed 49/49 while the Gateway was
crashing. The bug only appears under the jiti loader the Gateway uses for
plugin sources.

So this is proved separately, on the same guest, at the same head. The proof
loads the real plugin registry from the built dist/plugins/loader.js — the
same module the Gateway uses — with mxc enabled. The loader resolves the
plugin to TypeScript source and evaluates it through jiti, then the real
MxcFsBridge is constructed through the real createMxcFsBridge using the
production alias map and production jiti options taken verbatim from dist.
No synthetic class, no stand-in, no hand-rolled loader.

PASS mxc-plugin-present
PASS plugin-resolves-to-typescript-source -> ...\extensions\mxc\index.ts
PASS real-loader-evaluated-mxc-entry-via-jiti -> status=loaded
     note: activation status detail -> activated
PASS load-real-fs-bridge-via-jiti
PASS construct-real-MxcFsBridge -> MxcFsBridge
PASS resolve-child-workdir -> ...\child
PASS backend-owns-workdir-validation -> backend
PASS validate-accepts-child-workdir -> ...\child
PASS validate-rejects-missing -> null
PASS validate-rejects-under-a-file -> null
PASS validate-rejects-out-of-workspace -> null
REAL MXC PROVISIONING PROOF: PASS
02-provisioning-proof-PASS 02-provisioning-proof-PASS contact
02-provisioning-proof-PASS.mp4

The proof discriminates

A proof that only ever passes proves nothing. On the same guest, only
extensions/mxc/src/fs-bridge.ts was reverted to its pre-fix parent
(ae7d52b57aea419db2074abf8d552e1e1ee0d355) and the identical proof re-run:

PASS load-real-fs-bridge-via-jiti
FAIL construct-real-MxcFsBridge -> Cannot read properties of undefined (reading 'containerWorkdir')
REAL MXC PROVISIONING PROOF: FAIL (1)

Character-for-character the error reported from the live Gateway. The file was
then restored to head and the guest tree verified clean.

03-provisioning-proof-PREFIX-FAIL
03-provisioning-proof-PREFIX-FAIL.mp4
03-provisioning-proof-PREFIX-FAIL contact

Please read the 49/49 as covering the workdir-validation behavior, not the
provisioning crash. The discrimination pair above is what covers the crash.

Recordings capture the runs as they execute rather than a still of an
already-finished prompt, and the guest taskbar clock in each screenshot matches
the capture timestamp in its metadata.json, confirming live frames rather than
a stale framebuffer.

Maintainer verification

Verified locally by the author on the Windows setup that originally hit the
provisioning crash.

Structured review

Both re-run against this rebased head:

  • Autoreview (Codex gpt-5.6-sol, branch mode against the base above):
    TruffleHog clean, zero accepted/actionable findings,
    verdict "patch is correct (0.99)".
  • ClawSweeper local-range review: decision=keep_open, confidence high,
    overall "patch is correct (0.86)", zero review findings, no merge-risk
    labels, security review cleared.

An earlier ClawSweeper pass flagged the ENOTDIR gap as an availability risk.
That finding was verified against the source, fixed across all three sibling
sites, and covered by a new regression test; re-reviews since have returned no
merge-risk labels.

Known unrelated failure

src/agents/bash-tools.exec-workdir.test.ts has 3 Windows-only failures
(containerCwd slash direction). Re-confirmed after this rebase: they reproduce
identically on base e69c3df2361 with this PR's changes absent, so they are
pre-existing and out of scope here.

Follow-up

The class-field ordering divergence between the repo tsconfig and the jiti
plugin loader is a latent hazard for any plugin, not just MXC — a scan found
exactly one instance, fixed here. Filed as #119014 with a proposed guard.

@paulcam206
paulcam206 marked this pull request as ready for review July 28, 2026 21:05
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 29, 2026
@clawsweeper

clawsweeper Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed August 5, 2026, 8:47 PM ET / August 6, 2026, 00:47 UTC.

ClawSweeper review

What this changes

This PR makes the MXC sandbox validate agent-selected work directories and moves filesystem-bridge initialization into the constructor to prevent provisioning crashes under the plugin source loader.

Regression provenance

Possible regression — probable (reproduction; reviewed change). No predecessor PR is attributed.

Merge readiness

⚠️ Ready for maintainer review - 2 items remain

Keep open: current main still contains both MXC failure paths, while this focused owner-local repair uses the existing backend validation contract and has discriminating exact-head Windows/jiti runtime proof.

Priority: P1
Reviewed head: 88ce07175543df5400d0122d2a55d12e41ec73c8

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) Focused implementation with strong discriminating runtime proof and no actionable correctness or security finding.
Proof confidence 🦞 diamond lobster (5/6) ✨ media proof bonus Sufficient (recording): The PR body provides an exact-head Windows run through the real plugin registry and jiti loader, plus a controlled pre-fix failure showing the reported provisioning error.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (recording): The PR body provides an exact-head Windows run through the real plugin registry and jiti loader, plus a controlled pre-fix failure showing the reported provisioning error.
Evidence reviewed 7 items Current main still has the provisioning hazard: Current main initializes three bridge fields from the constructor parameter property before the constructor body; the PR instead assigns them from the constructor argument.
Existing backend-validation contract: The sandbox contract explicitly supports backend-owned workdir validation returning a canonical path or null; MXC owns the relevant path semantics.
Caller behavior: The agent execution path invokes the backend validator after tool adjustments and treats a null result as an unavailable workdir before launch.
Findings None None.
Security None None.

How this fits together

MXC is the sandbox plugin used by agent tools. Tool-selected directories and sandbox configuration flow through its backend and filesystem bridge before an agent command is launched.

flowchart LR
A[Agent tool request] --> B[MXC backend]
B --> C[Workdir validation]
C --> D[Sandbox setup]
D --> E[Filesystem bridge]
E --> F[Tool execution]
Loading

Before merge

  • Resolve merge risk (P1) - The branch is behind current main; refresh it against main before merge, although current main has no changes in the three MXC paths.
  • Complete next step (P2) - The open branch already contains the bounded repair; normal exact-head refresh and maintainer merge review are the remaining actions.
Agent review details

Security

None.

PR surface

Source +26, Tests +23. Total +49 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 2 33 7 +26
Tests 1 23 0 +23
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 56 7 +49

Review metrics

Metric Value Why it matters
Production versus test delta production +33/-7; tests +23/-0 The production growth implements the existing backend-validation contract and constructor-order invariant; the added tests cover normalized, missing, and non-directory workdirs.

Merge-risk options

Maintainer options:

  1. Decide the mitigation before merge
    Preserve the MXC-local repair, refresh it against current main, and merge after exact-head checks remain green.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Technical review

Best possible solution:

Preserve the MXC-local repair, refresh it against current main, and merge after exact-head checks remain green.

Do we have a high-confidence way to reproduce the issue?

Yes. The exact-head Windows runtime probe discriminates fixed from pre-fix bridge behavior, and current main retains the same source-loader path and hazardous initializers.

Is this the best way to solve the issue?

Yes. MXC owns its workspace mapping, so using the established backend validator avoids changing generic Docker, SSH, or core behavior for plugin-specific path semantics.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against a1064adb6861.

Labels

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides an exact-head Windows run through the real plugin registry and jiti loader, plus a controlled pre-fix failure showing the reported provisioning error.
  • add proof: 🎥 video: Contributor real behavior proof includes video or recording evidence. The PR body provides an exact-head Windows run through the real plugin registry and jiti loader, plus a controlled pre-fix failure showing the reported provisioning error.
  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (recording): The PR body provides an exact-head Windows run through the real plugin registry and jiti loader, plus a controlled pre-fix failure showing the reported provisioning error.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.
  • remove status: 📣 needs proof: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P1: Affected MXC users cannot provision a sandbox or run agent tools in valid Windows workspace subdirectories.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (recording): The PR body provides an exact-head Windows run through the real plugin registry and jiti loader, plus a controlled pre-fix failure showing the reported provisioning error.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides an exact-head Windows run through the real plugin registry and jiti loader, plus a controlled pre-fix failure showing the reported provisioning error.
  • proof: 🎥 video: Contributor real behavior proof includes video or recording evidence. The PR body provides an exact-head Windows run through the real plugin registry and jiti loader, plus a controlled pre-fix failure showing the reported provisioning error.

Evidence

What I checked:

  • Current main still has the provisioning hazard: Current main initializes three bridge fields from the constructor parameter property before the constructor body; the PR instead assigns them from the constructor argument. (extensions/mxc/src/fs-bridge.ts:37, a1064adb6861)
  • Existing backend-validation contract: The sandbox contract explicitly supports backend-owned workdir validation returning a canonical path or null; MXC owns the relevant path semantics. (src/agents/sandbox/backend-handle.types.ts:67, a1064adb6861)
  • Caller behavior: The agent execution path invokes the backend validator after tool adjustments and treats a null result as an unavailable workdir before launch. (src/agents/bash-tools.exec-workdir.ts:298, a1064adb6861)
  • Current main has not superseded the patch: There is no current-main diff in the three MXC paths since the PR base, and the PR head is not an ancestor of main. (extensions/mxc/src/mxc-backend.ts:204, a1064adb6861)
  • Exact-head real behavior proof: The PR body records a Windows 11 run at 88ce071 that loads the real MXC plugin through the production jiti path, constructs the real bridge, validates accepted and rejected workdirs, and fails with the reported error when only the pre-fix bridge file is restored. (88ce07175543)
  • Feature-history provenance: Current-main blame attributes the field-initializer area to the recent MXC refactor commit; this is routing evidence, not an attribution of fault. (extensions/mxc/src/fs-bridge.ts:37, b6a4e6e2a60d)

Likely related people:

  • steipete: Current-main blame ties the affected filesystem-bridge initialization area to this recent MXC refactor. (role: recent area contributor; confidence: high; commits: b6a4e6e2a60d; files: extensions/mxc/src/fs-bridge.ts, src/plugins/plugin-module-loader-cache.ts)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (25 earlier review cycles; latest 8 shown)
  • reviewed 2026-08-03T18:03:57.746Z sha b5ca3a4e633b35f8616cb401803c6e998d1469f3 :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-03T19:03:05.708Z sha 39f8e4382c5bc0ea16cf07f6064393d94ac0825e :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-03T20:02:16.698Z sha f69a565c83ae97b80c3f298db3e29a6c6fb1af7c :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-03T21:03:00.277Z sha f69a565c83ae97b80c3f298db3e29a6c6fb1af7c :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-03T21:25:06.321Z sha f69a565c83ae97b80c3f298db3e29a6c6fb1af7c :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-03T23:02:46.686Z sha 8e160b8366be9cce429ddb714011d8bead79cbab :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-04T04:11:13.594Z sha 8e160b8366be9cce429ddb714011d8bead79cbab :: needs maintainer review before merge. :: none
  • reviewed 2026-08-05T19:31:59.373Z sha 88ce071 :: needs real behavior proof before merge. :: none

@paulcam206
paulcam206 marked this pull request as draft July 29, 2026 17:24
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 29, 2026
@paulcam206
paulcam206 force-pushed the paulcam/mxc-workdir-validation branch from 69a8aee to 7f09404 Compare July 29, 2026 18:00
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jul 29, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 29, 2026
@paulcam206
paulcam206 marked this pull request as ready for review July 30, 2026 04:21
@paulcam206
paulcam206 force-pushed the paulcam/mxc-workdir-validation branch from 7f09404 to c167d38 Compare July 30, 2026 22:34
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 30, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 31, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Aug 1, 2026
@paulcam206
paulcam206 force-pushed the paulcam/mxc-workdir-validation branch from b5ca3a4 to 39f8e43 Compare August 3, 2026 18:48
@openclaw-barnacle openclaw-barnacle Bot added size: XS and removed size: S triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Aug 3, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Aug 3, 2026
@clawsweeper clawsweeper Bot added proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Aug 3, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Aug 4, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: fc20c06c-e8c0-4649-9efd-ad87fac71a4f
validateWorkdir declares that unusable workdirs return null, but only ENOENT was classified as missing. A workdir nested under a file raises ENOTDIR on Linux, which escaped as a raw filesystem error instead of the normal unavailable-workdir result.

The same ENOENT-only classification appeared at three sibling sites in this file, so the shared isMissingPathError guard fixes the whole class rather than the single reported path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d7253887-71c9-4083-a591-91979c981e39
MxcFsBridge initialized three fields from this.sandbox, but sandbox is a constructor parameter property. Plugin sources load through jiti, which evaluates field initializers before assigning parameter properties, so this.sandbox was still undefined and every MXC sandbox provisioning failed with SandboxProvisioningError: Cannot read properties of undefined (reading 'containerWorkdir').

Assign the derived fields in the constructor body from the sandbox parameter instead. The repo tsconfig sets useDefineForClassFields=false, so tsgo and Vitest (esbuild) both apply legacy ordering and could not observe the failure; only the jiti-loaded runtime path did.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d7253887-71c9-4083-a591-91979c981e39
@paulcam206

Copy link
Copy Markdown
Contributor Author

@RomneyDa - can you take a look?

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

Labels

P1 High-priority user-facing bug, regression, or broken workflow. plugin: mxc proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 🎥 video Contributor real behavior proof includes video or recording evidence. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants