You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Web/Desktop directory picker persists every subdirectory of $HOME as a project (v2) #46679
Opening the directory picker in the Web or Desktop app (the "Open folder" / "Add workspace" picker, which starts at $HOME) permanently writes dozens of unrelated directories into the project table. Every ~/.cache, ~/.cargo, ~/.ssh, ~/Downloads, ~/Music and so on then shows up as a project in the TUI's Open dialog (ctrl+o) and in every other project list.
The picker itself is read-only from the user's point of view. Browsing the tree should not register projects.
Expected: Browsing in the picker writes nothing. Only directories the user opens, or that own a session or worktree, appear as projects.
Actual: Every subdirectory of $HOME that the picker preloaded is a row in project and an entry in every project list. Dotdirectories are included.
Reproduced on Linux with the Web app; the TUI shows the result in the Ctrl + O picker.
Plugins
No response
OpenCode version
v2 beta (v0.0.0-beta-18743)
Steps to reproduce
Start the v2 server and open the Web app (or Desktop).
Open the directory picker so it mounts at $HOME. Let the tree render.
Open the TUI and press ctrl+o.
Look at the Projects category, or run:
SELECT id, worktree FROM project WHERE vcs IS NULLORDER BY time_updated DESC;
If helpful, I've asked Claude Code to write a root cause:
Four steps, all on `v2` at `fd73a85de4`:
1. `packages/app/src/workspaces/selection/dialog.tsx:155` — on first mount the picker preloads every child directory of the start path with `sdk.api.file.list({ location: { directory: absolute } })`, one request per child directory.
2. `packages/protocol/src/api.ts:170` — `FileSystemGroup` runs under `locationMiddleware`, so each of those requests boots a `Location` for the probed directory.
3. `packages/core/src/location.ts:24` — booting a `Location` calls `Project.resolve(ref.directory)`.
4. `packages/core/src/project.ts:357` — a directory without a `.git` or `.hg` marker falls through to `persist({ id: Hash.fast("directory:" + directory), vcs: undefined })`, which is an unconditional `upsertProject`. This branch was added in #45107 ("add directory projects", `9361117504`).
There is no read-only path through `Project.resolve`. The existing `discovery: false` option only skips the config and plugin scan; it does not skip the write.
`Project.list()` (`packages/core/src/project.ts:221`) is a bare `SELECT * FROM project`, and the TUI Open dialog (`packages/tui/src/component/dialog-open.tsx:142`) shows every row except `/` and duplicates. So each probed directory becomes a visible project.
Activity
heimoshuiyu commentedon Sep 3, 2026
fixed #46970