Repository navigation
fix(app): give a sandbox its project so New session lands in it - #221
Merged
Merged
Conversation
New session on a sandbox silently started the session on the local server: the sandbox looked selected while the agent ran on the host. A sandbox exposes exactly one directory — the project folder it was created with, at a fixed guest path (/workspace on vz and bwrap, the wslpath translation on WSL) — and the guest registers it as its own project at boot. The app's per-server project list, though, starts empty and nothing ever fills it: projects are only ever added by a user opening a folder. With no project for that server, home-model.openNewSession returns early and the titlebar's openNewTab fallback chain walks on to another server. Seed it from the server itself, reading sync.data.path.directory, which every server ctx already fetches, so it stays backend-agnostic. An explicit close is respected — re-opening it would make the sandbox's only project impossible to remove. The logic is fork-only (src/sandbox/projects.ts); global.tsx gains an import and one call, since SandboxesProvider is mounted above GlobalProvider and cannot reach ensureServerCtx. Co-Authored-By: Claude Opus 5 (1M context) <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
New session on a sandbox silently starts the session on the local server. The sandbox looks selected in the sidebar while the agent runs on the host —
pwdin a "sandbox" session prints a host path.Confirmed against live state on a Linux machine. The guest's own database had run zero sessions:
while the host sidecar's
opencode.dbheld the sessions the user thought were sandboxed.The app's persisted server store shows why:
A sandbox exposes exactly one directory — the project folder it was created with, at a fixed guest path (
/workspaceon vz and bwrap, the wslpath translation on WSL) — and the guest registers it as its own project at boot. But the app's per-server project list starts empty and nothing ever fills it: everyprojects.opencall site is a user opening a folder.With no project for that server:
home-model.openNewSession→if (!conn || !project) return— a silent no-op.openNewTabfallback chain → walks past the sandbox toserver.key, then to the first server with any project — the local one.The
sandbox:codev-coderow above shows the manual escape hatch is a trap too: the directory picker opens on the server's home (/home/codev), not its worktree, so the user ended up adding/home/codev/.cache/codevas their "project".Fix
Seed a sandbox's project list from the server itself, reading
sync.data.path.directory— which every server ctx already fetches as part of its bootstrap, so it needs no new request and stays backend-agnostic (no hardcoded/workspace, which would be wrong on WSL). An explicit close is respected: re-opening it would make the sandbox's only project impossible to remove.The logic is fork-only (
packages/app/src/sandbox/projects.ts).context/global.tsxgains an import and one call —SandboxesProvideris mounted aboveGlobalProviderinapp.tsx, so it cannot reachensureServerCtxand the call has to live in the Global init.DIVERGENCES.mdrecords that.Verification
Six tests in
test-browser/sandbox-projects.test.tsdrive the real function under real Solid reactivity (the parameter type is structural precisely so this needs no ctx mock): seeds fromdirectory, falls back toworktree, ignores non-sandbox servers, skips a sandbox that already has a project, respects a closed project, and seeds a sandbox that becomes ready later.bun typecheck,bun run test:unit(657 pass), andbun run test:browser(51 pass) all clean inpackages/app.The sandbox runtime itself was verified healthy in the same investigation —
/pathreportsworktree: /workspace,/projectlists it,/configcarries the brokered gateway, and egress is correctly limited to the broker (models.devandregistry.npmjs.orgfail withEAI_AGAINinside the guest). The gap was purely that the app never told the sandbox server which project to open.Follow-up not in this PR
The directory picker opening on
path.homerather thanpath.directoryis what produced the/home/codev/.cache/codevproject above. Seeding makes that path unnecessary for the common case, but the picker default is still worth revisiting — it affects any server whose home and worktree differ.🤖 Generated with Claude Code