Repository navigation
fix(pixel): tell sandboxed Pixel what its exec sandbox provides - #6763
Open
Lightheartdevs wants to merge 1 commit into
Open
Lightheartdevs wants to merge 1 commit into
Lightheartdevs wants to merge 1 commit into
Conversation
Pixel was never told what the exec sandbox contains, so on coding tasks it spends tool calls finding out: in a photo-renamer run it issued five exec probes for Pillow, piexif and exifread before writing any file, and those calls used up the run's failure budget; another install lost three attempts to "pip: not found" / "No module named pip". The image has Pillow and no pip, and no network to install anything. Add one static sentence group to the system conversation contract when trusted configuration proves sandboxed exec (sandbox mode "all" with exec host "sandbox"): Debian 12 with Python 3.11, Pillow and python-docx beyond the standard library, the installed commands, no pip/pytest/Node.js/npm and no network (nothing can be installed), and where files can be written. Native (full-access) exec and unproven modes get no sandbox claim. The text is in the plugin, not the workspace template: every Linux, WSL and native macOS install loads the pixel-ods plugin, so it reaches existing installs on update regardless of owner-edited TOOLS.md, and it needs no vendor/pixel bundle regeneration. It is release-constant, so the system prompt stays byte-identical across turns. sandbox_runtime_contract.test.mjs ties every stated fact to its source: each package in the sandbox Dockerfile's apt-get install line must map to a phrase in the contract (or be marked deliberately unadvertised), the base image's Debian release must map to the stated Python, no other install path (pip/npm/COPY) may exist, the absent tools must stay absent, and render-config.mjs must keep network none, a read-only root, a writable /workspace and a /tmp tmpfs. It also checks that the Linux/WSL and native macOS installers build that Dockerfile and render that config. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
Pixel is never told what its exec sandbox contains. The workspace
TOOLS.md"Shell" section says only that shell runs in the sandbox with a read-only root filesystem. So on coding tasks Pixel spends tool calls finding out:execprobes (python3 -c "from PIL import Image",import piexif,import exifread) before it wrote any file. Those calls used up the run's failure budget and the turn stopped.pip: not found,pip3: not foundandNo module named pip.The sandbox image (
ods/vendor/pixel/deploy/sandbox/Dockerfile) ships Python 3.11 with Pillow and python-docx. It has no pip, and the sandbox has no network, so nothing can be installed.Fix
Add one static contract,
ODS_SANDBOX_RUNTIME_CONTRACT, after the conversation contract. It is added only when trusted configuration proves sandboxed exec, meaningexecutionHostForAgentreturnssandbox(sandbox modeallwith exec hostsandbox). It tells Pixel:import PIL) and python-docx (import docx)python3 -m unittest/tmpis small scratch space. The root filesystem, including home, is read-only.In native (full-access) mode, and in any mode that is not proven, Pixel gets no sandbox claim.
Why the plugin and not the workspace template
The text lives in
pixel-agent/plugin/prompt-contract.mjs(conversationContractForExecution):cp -n, so changes to it never reach existing workspaces.migrate-workspace-source-boundary.mjsruns only in Linuxapply.sh.bootstrap-capabilities.mjschanges onlyTOOLS.mdfiles whose digest still matches the shipped one, so owner-edited files would be skipped.vendor/pixel. Nopixel.bundleregeneration is needed, and nothing overlaps fix(pixel): remove the owner's private operating contract from the workspace template #6755's template scrub. This branch does not need to be built on fix(pixel): remove the owner's private operating contract from the workspace template #6755.systemContext, the session-stable part. The September 16 core and compact core hashes are unchanged.Platforms
All platforms use the same image definition:
vendor/pixel/scripts/bootstrap.shbuildsdeploy/sandboxasopenclaw-sandbox:bookworm-slim.service-plan.ps1disables Pixel on native Windows. So Windows uses the Linux path and the same image.pixel-native-bootstrap.pybuilds the samedeploy/sandboxDockerfile forlinux/arm64, taggedods-pixel-native-sandbox:<version>-uid-<uid>-<ref>. Bookworm arm64 ships the same packages and Python 3.11.All three render the sandbox through
render-config.mjs: networknone, a read-only root,/workspaceread-write, and/tmpas a 256 MB tmpfs.The only differences between platforms are the image tag and the CPU architecture.
Drift test
tests/sandbox_runtime_contract.test.mjsfails CI when the image or the sandbox settings stop matching the text.test-linux.ymlrunspixel-agent/tests/*.test.mjson every PR, so a change to the Dockerfile alone is caught. The test checks that:apt-get installline maps to a phrase in the contract, or is explicitly marked unadvertised (ca-certificates, andcurl, which is useless without network). Adding or removing a package fails.bookworm) maps to the stated Python (3.11). A new release fails until the text is updated.pip/npm/gem/cargo/go install, nocurl | sh, and noCOPY/ADD.render-config.mjskeeps networknone,readOnlyRoot: true,workspaceAccess: "rw", workdir/workspace, and a/tmptmpfs.I checked by hand that each of these changes fails the test: adding
python3-numpy, removingpython3-docx, addingnodejs, switching the base totrixie, adding aRUN pip installline, adding aCOPYline, setting network tobridge, and settingreadOnlyRoot: false.Validation
Full Linux pixel-agent suite (
node --test tests/*.test.mjs):The #6753 failure (
tower2 replay through the registered hooks: the refused cleanup keeps the current pass...indeletion_refusal_delivery.test.mjs) is not caused by this branch. It also fails on main + #6753 without this change, and passes on #6753 alone, which is behind main.Conflicts
git merge-treeagainst open PRs:tool-loop-guard.mjs(fix(pixel): stop whole-file rewrites and test bisection after failed tool results (output efficiency C1-C4) #6716 also inworkspace-preview-inspect.mjs), fix(pixel): keep the system prompt byte-stable across owner messages #6654 inindex.js, and Improve Pixel task execution, evidence reuse, and visible progress #6645 in several files. This branch adds no conflicts.🤖 Generated with Claude Code