[ISSUE-199] Per-sandbox symlink layer for all mount sources - #200
Open
1996fanrui wants to merge 2 commits into
Open
[ISSUE-199] Per-sandbox symlink layer for all mount sources#2001996fanrui wants to merge 2 commits into
1996fanrui wants to merge 2 commits into
Conversation
1996fanrui
force-pushed
the
issue-199-per-sandbox-symlink-layer
branch
from
April 20, 2026 19:01
f7695ed to
2fd4675
Compare
Introduce a per-sandbox staging directory under SandboxDataRoot for
all mount sources (builtin tools and generic mounts). Each mount source
gets a staging entry named {md5(abs_path)}_{basename} in a flat directory.
The current implementation uses symlinks — Docker bind-mount follows symlinks
natively, enabling per-sandbox mount source management with no Docker-side changes.
Key changes:
- Add SandboxDataRoot() platform path (~/.local/share/agents-sandbox/mounts)
- Add createMountSymlink() helper with MD5 naming and idempotent behavior
- Rename SymlinkDir to MountStagingDir in sandboxRuntimeState
- Update materializeBuiltinTools/materializeGenericMounts to stage mount sources
- Docker Desktop magic path (/run/host-services/ssh-auth.sock) bypasses staging
- Allow symlink mount sources in validation (mount only, copy still rejected)
- Set MountStagingDir in restart recovery, preserve runtimeState for cleanup
- Clean up staging directory in deleteRuntimeArtifacts
Closes: #199
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update four design documents to reflect the new mount staging layer: - configuration_reference.md: add SandboxDataRoot to Fixed Platform Paths - daemon_state_management.md: add MountStagingDir to Category C, staging dir to Category D - sandbox_container_lifecycle.md: add staging dir creation step in Create Path - container_dependency_strategy.md: update mount/copy/builtin staging handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1996fanrui
force-pushed
the
issue-199-per-sandbox-symlink-layer
branch
from
April 20, 2026 19:29
2fd4675 to
bfb1e5a
Compare
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
Introduce a per-sandbox symlink directory for all mount sources (builtin tools and generic mounts). Instead of bind-mounting original host paths directly into containers, the daemon now creates a symlink in
~/.local/share/agents-sandbox/mounts/<sandbox_id>/pointing to each original path, and uses the symlink as the bind-mount source. Docker follows symlinks during bind-mount, so this requires no Docker-side changes.close #199
Changes
Core Implementation
internal/platform/dirs.go): AddSandboxDataRoot()following theExecLogRoot()patterninternal/control/service.go,cmd/agboxd/config.go): AddSandboxDataRootfield toServiceConfig, initialize from platform defaultinternal/control/docker_runtime_materialize.go): NewcreateMountSymlinkfunction withmd5(abs_path)_<basename>naming, idempotent semanticsinternal/control/docker_runtime.go): ExtendsandboxRuntimeStatewithSymlinkDir, create symlink dir inCreateSandbox, clean up indeleteRuntimeArtifactsmaterializeBuiltinTools,materializeBuiltinToolPath,materializeGenericMountsto route through symlink layerinternal/control/service_validation.go): Allow symlink sources for mount kind (usesos.Stat), keep rejecting for copy kind (usesos.Lstat)internal/control/service_events.go): RebuildSymlinkDirfromSandboxDataRoot + sandboxIDon restart, preserveruntimeStatefor all terminal statesSpecial Cases
/run/host-services/ssh-auth.sock) bypasses symlink layerSandboxDataRootis empty, all functions fall back to original behavior (no symlinks)Documentation
docs/configuration_reference.md: Add Sandbox data to Fixed Platform Paths tabledocs/daemon_state_management.md: AddSymlinkDirto Category C, symlink directory to Category Ddocs/sandbox_container_lifecycle.md: Add symlink dir creation step in Create Pathdocs/container_dependency_strategy.md: Update mount source rules for symlink layerTests
docker_runtime_symlink_test.go(414 lines): symlink naming, idempotency, replacement, normalization, builtin tools, generic mounts (dir/file/socket), magic path bypass, cleanup, fallback behaviorTestCreateSandboxCreatesSymlinkDir: verifies symlink dir created via Docker runtimeTestRestorePersistedSandboxesSetsSymlinkDir: verifies restart recovery rebuilds SymlinkDir