Repository navigation
Description
Summary
ProjectV2.resolve() in packages/core/src/project.ts makes project identity fully dependent on git detection succeeding. When git.repo.discover() returns null — non-git directory, git not yet initialized, transient discovery failure, workspace root above multiple repos — the fallback collapses both the project ID and the directory into shared, non-unique values:
const repo = yield* git.repo.discover(input)
if (!repo) return { id: ID.global, directory: AbsolutePath.make(path.parse(input).root), vcs: undefined }Two separate directories that both fail git detection get:
- same
id: ID.global - same
directory: "/"(root of the filesystem, viapath.parse(input).root)
This means any two unrelated directories that fail git discovery become indistinguishable as the same project, merging their sessions, permissions, and history in the UI.
Why this happens more than it seems
Failing git discovery isn't rare/edge-case:
- Workspace layouts where the launch directory is a plain folder containing multiple git repos as subdirectories (common multi-repo workspace setup).
- Directory not yet
git init'd when opencode starts. - Any transient failure in
git.repo.discover().
In all these cases the directory path itself is still perfectly known and unique — we just choose to throw it away and substitute /.
Downstream impact (confirmed via source + related issues)
- Session bucket collision —
/sessionspicker filters byprojectID. All directories that fall back toglobalshare one bucket, so sessions from completely unrelated projects show up mixed together. (New session created via /new gets projectID=global instead of the directory's project, making prior sessions invisible in /sessions #42230, Same git directory gets two project IDs and /sessions only shows the latest project's sessions #36464, bug(core): empty git repos share the same "global" project ID, causing sessions to leak across unrelated directories #39773, session list and TUI mix sessions from unrelated non-git directories #38529) - Permission path breakage — tool permission rules evaluate paths relative to
worktree. Withworktree === "/",path.relative("/", "/home/.../file.md")produces a long root-relative fragment instead of a project-relative path, so scoped permission rules silently stop matching. (Non-git projects use "/" as worktree, breaking permission path resolution #24694) - Security concern raised by community — root-relative worktree implicitly gives filesystem-root-scoped permission context to a directory that never asked for it. See community pushback in Non-git projects use "/" as worktree, breaking permission path resolution #24694.
This was already root-caused and fixed once: #24694 had a working PR (#33668, fix(project): use directory root for non-git projects) that normalized the opened directory as worktree/sandbox instead of /. Both the issue and the PR were closed automatically by the 60-day stale-bot, not by a maintainer decision, and multiple users have asked for reopening since.
Proposed fix direction
Stop treating git discovery as a prerequisite for project identity. Instead:
- Primary identity key = normalized absolute directory path. Every directory gets a stable, unique project identity by default, git or not.
- Git remains an enrichment/merge signal, not a gate. If git is present, use remote URL / root commit to additionally unify multiple worktrees or clones of the same repo under one project — exactly like today's
remote(repo) ?? previous ?? root(repo)logic — but only to merge, never to collapse unrelated directories intoglobal. ID.globalshould be reserved for the literal filesystem root or an explicit "no project" case, not used as a catch-all for "git detection failed here."- Directory used for worktree/sandbox/permission scoping should always be the resolved input directory, never
path.parse(input).root.
This restores directory-level isolation (which several users report as previous/expected behavior) without requiring a new config flag — every directory is inherently its own project by default, and git just adds cross-directory linking on top when applicable.
Related issues
- Non-git projects use "/" as worktree, breaking permission path resolution #24694 — original report + fix PR fix(project): use directory root for non-git projects #33668, closed by stale-bot, community asked to reopen
- New session created via /new gets projectID=global instead of the directory's project, making prior sessions invisible in /sessions #42230 — downstream symptom:
/newcreates session withprojectID=global, hiding prior sessions - Same git directory gets two project IDs and /sessions only shows the latest project's sessions #36464, bug(core): empty git repos share the same "global" project ID, causing sessions to leak across unrelated directories #39773, session list and TUI mix sessions from unrelated non-git directories #38529 — same symptom family, likely duplicates of the same root cause
- Support branch or local-clone based project identity strategy #29644 — different but adjacent: configurable identity strategy (remote/branch/path precedence) for git repos specifically; this issue is about the non-git fallback path, narrower in scope and shouldn't require new config surface
Environment
- opencode version: 1.18.29
- OS: macOS (darwin)
- Reproduced with: workspace root directory containing multiple independent git repos as subdirectories, launched opencode from the workspace root instead of from inside each repo
Activity
resolvereturnsglobalbeforeproject_directoryis consulted #48870 as a duplicate of this issuethdxr commentedon Oct 11, 2026
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (
opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊
akib1689 commentedon Oct 12, 2026
This is still the problem is still present in the V2. reproduced in OpenCode 2.0.27 (macOS, Homebrew)
#38529, #53450, #54679 also mention similar sort of things..