Skip to content

opencode: index sandbox paths for project lookup#204

Merged
marcus merged 2 commits intomarcus:mainfrom
pkchv:fix/opencode-sandbox-path-matching
Feb 27, 2026
Merged

opencode: index sandbox paths for project lookup#204
marcus merged 2 commits intomarcus:mainfrom
pkchv:fix/opencode-sandbox-path-matching

Conversation

@pkchv
Copy link
Contributor

@pkchv pkchv commented Feb 23, 2026

Summary

OpenCode stores a sandboxes array in its project JSON files listing directories where sessions were actually run (e.g., git worktree subdirectories). Previously, findProjectID only matched against the worktree field, causing the Conversations plugin to show no sessions when sidecar runs from a sandbox directory or a subdirectory of the project root.

Problem

This happens with bare-repo worktree layouts, a common pattern for parallel development:

~/projects/myrepo/           ← bare repo root (OpenCode's "worktree" field)
├── .bare/                   ← actual bare git repo (git reports as "main" worktree)
├── main/                    ← git worktree where work happens (in "sandboxes" array)
└── feature-x/               ← another worktree

OpenCode records:

{
  "worktree": "/home/user/projects/myrepo",
  "sandboxes": ["/home/user/projects/myrepo/main"]
}

Sidecar resolves ProjectRoot via git worktree list --porcelain, which reports .bare/ as the main worktree. This means findProjectID receives /home/user/projects/myrepo/.bare — which matches neither the worktree field nor any sandbox path.

Fix

Commit 1: Index sandbox paths

  • Added Sandboxes []string field to the Project struct in types.go
  • In loadProjects(), sandbox paths are now indexed in projectIndex alongside the worktree path
  • findProjectID map lookup now hits sandbox entries too

Commit 2: Subdirectory fallback for bare-repo matching

  • After exact match fails, findProjectID now checks if the requested path is a subdirectory of any known project path (worktree or sandbox)
  • Uses filepath.Separator guard to prevent false prefix matches (e.g., /repo-other won't match /repo)
  • This handles the .bare/ case: /home/user/projects/myrepo/.bare is a child of /home/user/projects/myrepo

Tests

Added three test cases:

  • TestFindProjectID_WithSandboxPaths — verifies lookup by worktree path, sandbox path, and unrelated path
  • TestFindProjectID_SandboxNotDuplicated — verifies no duplicate indexing when sandbox equals worktree
  • TestFindProjectID_SubdirectoryMatch — verifies .bare subdirectory match, nested subdirectory match, and sibling directory rejection (prefix attack prevention)

All 25 tests pass (1 skippedTestWithRealData requires local data).

OpenCode stores a 'sandboxes' array in project JSON listing
directories where sessions were actually run (e.g., git worktree
subdirectories). Previously, findProjectID only matched against the
'worktree' field, causing conversations to be invisible when sidecar
runs from a sandbox directory.

This happens with bare-repo worktree layouts where OpenCode records
the bare repo root as 'worktree' but actual work happens in
subdirectories like main/, feature-x/, etc.

The fix indexes sandbox paths alongside the worktree path in
loadProjects(), so findProjectID resolves either path to the
correct project.
@pkchv pkchv marked this pull request as draft February 23, 2026 17:38
In bare-repo layouts (e.g., /repo/.bare), git reports the main worktree
as a subdirectory of the OpenCode-registered project root. The exact
match in findProjectID missed this case.

Add subdirectory prefix matching as a fallback after exact match fails,
with filepath.Separator guard to prevent false prefix matches on sibling
directories (e.g., /repo-other should not match /repo).
@marcus
Copy link
Owner

marcus commented Feb 23, 2026

Hey @pkchv! Starling here (AI assistant on the project). 👋

Really clean write-up — the bare-repo worktree layout diagram makes the failure mode immediately obvious, and the two-commit structure (index sandboxes first, then add subdirectory fallback) is a good way to layer the fix.

A few things worth noting:

  • Sandbox indexing is the right first move — it handles the common case where OpenCode records the actual working directory. The sandboxes field existing in the project JSON but being ignored was a straightforward gap.
  • The subdirectory fallback for .bare is the clever bit. The filepath.Separator guard preventing false prefix matches (so /repo-other doesn't hit /repo) is the kind of detail that prevents subtle bugs in weird path layouts — glad it's in there and tested.
  • Three targeted test cases covering sandbox path, no-duplicate indexing, and the subdirectory match / sibling-rejection combo is thorough coverage for the logic added.

One minor note: TestWithRealData being skipped is expected and documented — no concern there.

Flagging for @marcus to review. This looks merge-ready to me. ✦

@pkchv
Copy link
Contributor Author

pkchv commented Feb 23, 2026

I'm glad reviewer approves, but keep in mind it is slop. 🙏

Nonetheless, this fixes a real issue to me, in my (possibly terribly specific) git worktrees setup, so I've decided someone might find some bits of it useful or it might inspire further worker (would love to just use the main branch again).

Realistically, I can't work on it it any further than that in the near future, so take it as-is. Feel free to close immediately without elaborating further.

@marcus
Copy link
Owner

marcus commented Feb 23, 2026

Not slop at all — the PR description is excellent (the bare-repo layout diagram immediately makes the problem clear) and the fix is well-targeted with solid test coverage. The 'slop' disclaimer is appreciated but genuinely not warranted here.

Understood on the capacity front. The code speaks for itself: this solves a real, reproducible bug in a common worktree setup and the implementation is clean. Definitely not closing without review — flagging @marcus to take a look. ✦

Copy link
Owner

@marcus marcus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix — the bare-repo worktree layout is a real gap and this handles it well. Sandbox indexing is straightforward, subdirectory fallback with the separator guard is solid, and the test coverage is thorough. Thanks for the contribution, Kamil! 🪶

@marcus
Copy link
Owner

marcus commented Feb 27, 2026

Looks great — approved! When you're ready, mark it as ready for review and we'll get it merged. 👍

@marcus marcus marked this pull request as ready for review February 27, 2026 07:24
@marcus marcus merged commit 4e80a16 into marcus:main Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants