Skip to content

[BUG]: Project ID collision when repos cloned from same source share sessions #6696

@bcheung

Description

@bcheung

Repos cloned from the same source share the same root commit hash, causing them to share sessions unexpectedly. Opening opencode in either repo shows sessions from both.

Affected workflows

  • Cloned templates (e.g., create-react-app, Next.js starters)
  • Forks
  • Any "clone and change origin" workflow

Reproduction

#!/bin/bash
set -e

WORKDIR=$(mktemp -d)
cd "$WORKDIR"

# Create template repo and clone it twice
mkdir template && cd template
git init -q && echo "template" > README.md && git add . && git commit -qm "init"
cd "$WORKDIR"
git clone -q template clone-a
git clone -q template clone-b

# Run opencode in each
(cd "$WORKDIR/clone-a" && opencode run "respond with only: session from clone-a")
(cd "$WORKDIR/clone-b" && opencode run "respond with only: session from clone-b")

# Verify collision
echo "clone-a project ID: $(cat "$WORKDIR/clone-a/.git/opencode")"
echo "clone-b project ID: $(cat "$WORKDIR/clone-b/.git/opencode")"
# Both are identical - opening opencode in either shows sessions from both

Root cause

Project ID is derived from the first root commit hash:

if (!id) {
const roots = await $`git rev-list --max-parents=0 --all`
.quiet()
.nothrow()
.cwd(worktree)
.text()
.then((x) =>
x
.split("\n")
.filter(Boolean)
.map((x) => x.trim())
.toSorted(),
)
id = roots[0]
if (id) Bun.file(path.join(git, "opencode")).write(id)
}

Related

Notes on solution

The fix probably needs to be conditional:

  • Worktree → Share project ID with main repo (current behavior is correct for this case)
  • Git repo (not worktree) → Need deterministic unique ID that doesn't collide across clones. Root commit alone isn't sufficient. Options: include absolute path in hash, or remote origin URL, or generate UUID on first run.
  • Not a git repo → Could use absolute path

Key insight: PR #5647 correctly handles worktrees. This issue is specifically about the non-worktree clone scenario.

Side note: worktree caching

In git worktrees, .git is a file (not directory) pointing to .git/worktrees/<name>/. The current cache write to .git/opencode fails silently. Depending on the solution chosen here, this silent failure may cause issues if the fix relies on persisting something to that file.

let id = await Bun.file(path.join(git, "opencode"))
.text()
.then((x) => x.trim())
.catch(() => {})

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions