Skip to content

Same project gets two identities (git:<sha> + dir:<hash>) on OpenCode 2 → memories split, Dreamer tasks duplicated, dashboard shows phantom duplicate #555

Closed

Description

@morpheus9393

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 directoryFallbackCache for 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

  1. Silent memory loss at read time. A session resolving as git:7c1f0a9e… never sees the 97 memories stored under dir:4b8e1f0a7c92 for the same directory. They are effectively invisible.
  2. Duplicate maintenance cost. The Dreamer schedules and runs tasks per identity, so the same project runs the full task set twice.
  3. Misleading dashboard. The same project appears twice; users cannot tell the entries refer to one directory.
  4. 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

  1. 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) so dir:* memories can be folded into the matching git:* identity.
  2. Self-healing. When resolveProjectIdentity succeeds via git for a directory that previously produced a dir: fallback, consider migrating that directory's dir:-keyed rows to the git identity automatically (the mapping is recoverable from session_projects + directory).
  3. 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

Activity

  1. magic-alfonso commented on Sep 28, 2026

    @magic-alfonso

    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-list timeout, 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 a dir: identity. That identity sticks for the next 5 minutes, and anything written in that window stays under it.

    We're working on:

    • stopping new splits: a directory that has git metadata will never get a 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;
    • the home-directory case you spotted (C:/Users/Phoenix got an identity even though allow_home_project is off), including Windows path forms;
    • a doctor check 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 the git: 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 different git: 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:6021cc3a28f1 are still in context.db. They just aren't shown to sessions under the git: identity.

  2. magic-alfonso commented on Sep 28, 2026

    @magic-alfonso

    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):

    • New splits are prevented. A directory with git metadata never gets a 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. The allow_home_project check now handles Windows path forms (drive-letter case, forward and back slashes, \\?\ prefixes).
    • doctor merge-identities repairs 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 --apply does 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 up context.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.

  3. magic-alfonso commented on Sep 29, 2026

    @magic-alfonso

    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_project also recognizes Windows spellings of the home directory.

    Existing splits aren't merged automatically. npx @cortexkit/magic-context@latest doctor merge-identities lists them; --from <identity> --to <identity> previews the merge, and adding --apply performs it with a backup (with OpenCode and Pi closed). Details: https://docs.cortexkit.io/magic-context/help/troubleshooting/#merge-split-project-identities

    To update: OpenCode 1 and Pi pick it up on restart; on OpenCode 2 open /plugins, select Magic Context and press ctrl+u (or run opencode plugin update). If you still see this on 0.44.2, please reopen with a log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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