Repository navigation
Same project gets two identities (git:<sha> + dir:<hash>) on OpenCode 2 → memories split, Dreamer tasks duplicated, dashboard shows phantom duplicate #555
Description
Summary
On Windows + OpenCode 2 (OpenChamber), a single physical project accumulates two Magic Context project identities — one git:<root-commit> and one dir:<hash> — pointing at the same directory. Memories, sessions, and Dreamer state are then split across both buckets.
The dashboard surfaces this as the same project listed twice (e.g. two cobaltstack cards). More importantly, memories written under the dir: identity are invisible to sessions that resolve to the git: identity, and Dreamer tasks run twice for the same project (once per identity).
The v22_identity_rekey_map and identity_merge_log tables are both empty — nothing reconciled the duplicates.
Environment
- OS: Windows 11
- Harness: OpenCode 2.x via OpenChamber 2.0.0
- Magic Context:
@cortexkit/opencode-magic-context@0.43.2 - Store:
~/.local/share/cortexkit/magic-context/context.db - OpenCode store:
~/.local/share/opencode/opencode.db
Evidence
memories.project_path / session_projects.project_path contain two identities for one directory:
| project_path | resolved directory | sessions | memories |
|---|---|---|---|
git:7c1f0a9e4b2d38a6f5e0918273645abcde012345 |
D:/Projects/cobaltstack |
1698 | 801 |
dir:4b8e1f0a7c92 |
D:/Projects/cobaltstack |
34 | 97 |
Same pattern in other projects:
| project_path | directory | note |
|---|---|---|
git:2f6b8c0d1e3a49576b8c9d0e1f2a3b4c5d6e7f80 |
D:/Projects/internal-docs |
main identity |
dir:8a3c5e709b12 |
D:/Projects/internal-docs |
duplicate |
dir:1c2d3e4f5a6b |
D:/Tools/proxyprobe |
main identity (dir-based) |
git:9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f7081920 |
D:/Tools/proxyprobe |
duplicate |
git:0a1b2c3d4e5f60718293a4b5c6d7e8f901234567 |
D:/Projects/atlas-sync |
identity A |
git:9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c |
D:/Projects/atlas-sync |
identity B (root commit changed) |
State of the reconciliation tables:
v22_identity_rekey_map : 0 rows
identity_merge_log : 0 rows
migration_pending : 0 rows
Root cause (from source)
resolveProjectIdentity (dist, resolveProjectIdentity / resolveProjectIdentityStrict) derives git:<root-commit> via git rev-list --max-parents=0 HEAD, and on failure falls back to dir:<sha1(path)>:
ProjectIdentityError→directoryFallback(canonical)- The fallback is cached in
directoryFallbackCachefor non-git directories, and a transient cooldown (transientFailureCooldown) is applied when git metadata is present.
So any window where git resolution fails — "detected dubious ownership", a transient git rev-list failure, or a moment before .git is readable — writes memories under dir:<hash>. Once those memories exist, they stay under the fallback identity even after git resolution recovers, because nothing re-keys them.
Note: #214 (dubious ownership) was closed, but the consequence — a permanently split identity plus orphaned memories — is not repaired by that fix.
Impact
- Silent memory loss at read time. A session resolving as
git:7c1f0a9e…never sees the 97 memories stored underdir:4b8e1f0a7c92for the same directory. They are effectively invisible. - Duplicate maintenance cost. The Dreamer schedules and runs tasks per identity, so the same project runs the full task set twice.
- Misleading dashboard. The same project appears twice; users cannot tell the entries refer to one directory.
- Phantom projects. Non-git directories (home dir,
System32, OpenChamber per-chat folders,Downloads/*, worktrees) each become their own identity and each spawn their own Dreamer runs.
Requests
- Reconciliation path for split identities. Either re-run the v22 rekey for identities that now resolve to
git:, or expose an explicit merge (e.g.doctor --merge-identities <old> <new>/ an API) sodir:*memories can be folded into the matchinggit:*identity. - Self-healing. When
resolveProjectIdentitysucceeds via git for a directory that previously produced adir:fallback, consider migrating that directory'sdir:-keyed rows to the git identity automatically (the mapping is recoverable fromsession_projects+directory). - Dashboard hint. If two identities resolve to the same directory, show them as one project (or flag the split) instead of two unrelated cards.
Notes
- Related: OpenCode V2 readiness: existing-state migration and remaining V2 capability gaps #492 (OpenCode V2 readiness / existing-state migration), Fragmented memories: links, composites, and taxonomy-as-data #537 (fragmented memories), Magic Context fails to load when Git reports “detected dubious ownership in repository” #214 (dubious ownership).
allow_home_projectdefaults tofalse, yet adir:6f7a8b9c0d1eidentity forC:/Users/devexists with 111 sessions — possibly a separate gate bypass worth checking.
Activity
magic-alfonso commentedon Sep 28, 2026
Thanks for the detailed report and the queries. Your reading of the cause is right, and there's one more detail behind it.
When git fails for a directory that is a git repository (dubious ownership, a
git rev-listtimeout, a file that isn't readable yet), Magic Context tries to reuse the last git identity it saw for that directory. That memory only lives in the running process, though. So after a restart, the first failure (which happens more on Windows, especially under load) gets adir:identity. That identity sticks for the next 5 minutes, and anything written in that window stays under it.We're working on:
dir:identity. If git can't resolve it, Magic Context will use the identity it last recorded for that directory, or pause memory features for that session instead of creating a new identity;C:/Users/Phoenixgot an identity even thoughallow_home_projectis off), including Windows path forms;doctorcheck that lists directories with more than one identity and shows what's stored under each.How to repair existing splits (merging the
dir:memories into thegit:project, automatically or through an explicit doctor command) is still being decided. I'll update this issue when that's settled. The Proteus case with two differentgit:identities looks like a separate cause: an older version picked the first root commit from a repository with several roots, and that has since been fixed. We'll confirm it.Until then, nothing is lost: the memories under
dir:6021cc3a28f1are still incontext.db. They just aren't shown to sessions under thegit:identity.magic-alfonso commentedon Sep 28, 2026
An update: we decided to repair existing splits with an explicit command instead of doing it automatically in the background. Both parts are now on our main branch and will ship in the next release (0.44.2):
dir:identity. Each successful git resolution is recorded in a small file in Magic Context's storage folder, so it survives restarts. If git fails and no identity was recorded yet, memory features pause for that session instead of creating a new identity. Theallow_home_projectcheck now handles Windows path forms (drive-letter case, forward and back slashes,\\?\prefixes).doctor merge-identitiesrepairs an existing split. Without arguments it lists the splits it finds.--from <identity> --to <identity>previews exactly what would move (row counts per table, duplicate memories that would be combined, conflicting memories that would be kept, workspace and dreamer changes) without writing anything. Adding--applydoes the merge. It refuses to run while any OpenCode, Pi or ck-mc process has the database open, prints the backup location and the restore command first, backs upcontext.db, and merges in one transaction. Running it twice is safe. Identical memories are combined, keeping their history. Different memories are both kept, never overwritten.For your case, that's
doctor merge-identities --from dir:6021cc3a28f1 --to git:<your root>, run with OpenCode closed. It refuses projects running in Rust mode, which keep their memories in a different store. Yours run in TypeScript mode, so it applies. We'll post here when the release is out.magic-alfonso commentedon Sep 29, 2026
Fixed in 0.44.2, now on npm. A directory with git metadata no longer falls back to a
dir:identity: each project's git identity is recorded in Magic Context's storage folder and reused if git fails after a restart.allow_home_projectalso recognizes Windows spellings of the home directory.Existing splits aren't merged automatically.
npx @cortexkit/magic-context@latest doctor merge-identitieslists them;--from <identity> --to <identity>previews the merge, and adding--applyperforms it with a backup (with OpenCode and Pi closed). Details: https://docs.cortexkit.io/magic-context/help/troubleshooting/#merge-split-project-identitiesTo update: OpenCode 1 and Pi pick it up on restart; on OpenCode 2 open
/plugins, select Magic Context and press ctrl+u (or runopencode plugin update). If you still see this on 0.44.2, please reopen with a log.