Skip to content

feat: use git remote URL for cross-machine project memory sync#43

Open
jim80net wants to merge 4 commits intosupermemoryai:mainfrom
jim80net:feature/git-remote-project-tags
Open

feat: use git remote URL for cross-machine project memory sync#43
jim80net wants to merge 4 commits intosupermemoryai:mainfrom
jim80net:feature/git-remote-project-tags

Conversation

@jim80net
Copy link
Copy Markdown

@jim80net jim80net commented Apr 3, 2026

Summary

Resolves #38

Uses git remote origin URL as the project identifier for memory container tags, enabling automatic cross-machine project memory synchronization.

Problem

Currently, project memories use sha256(directory) as the identifier:

  • Different machines have different paths for the same project
  • Result: project memories don't sync across machines
  • Setting projectContainerTag affects ALL projects (memory pollution)

Solution

// Before
return `${CONFIG.containerTagPrefix}_project_${sha256(directory)}`;

// After
const remoteUrl = getGitRemoteUrl(directory);
if (remoteUrl) {
  return `${CONFIG.containerTagPrefix}_project_${sha256(remoteUrl)}`;
}
return `${CONFIG.containerTagPrefix}_project_${sha256(directory)}`;

Benefits

  • Transparent: Works without user configuration
  • Automatic sync: Same git remote = same project tag across all machines
  • Automatic isolation: Different repositories stay separate
  • Backward compatible: Falls back to directory hash if no git remote

Test Plan

  1. Clone same repo on two different machines with different paths
  2. Create a project memory on Machine A
  3. Verify memory appears on Machine B
  4. Verify different repos have different project tags

Example

Machine Path Git Remote Project Tag
A /home/user/projects/spark git@github.com:user/spark.git opencode_project_{hash(remote)}
B /work/code/spark git@github.com:user/spark.git opencode_project_{hash(remote)}
C /dev/other-project git@github.com:user/other.git opencode_project_{hash(other_remote)}

Machines A and B now share project memories. Machine C has its own isolated memories.

Resolves supermemoryai#38

Problem:
- Project memories use directory path hash as identifier
- Different machines have different paths for the same project
- Result: project memories don't sync across machines
- Setting projectContainerTag affects ALL projects (memory pollution)

Solution:
- Use git remote origin URL as primary project identifier
- Same git remote = same project tag across all machines
- Fallback to directory hash if no git remote

Benefits:
- Transparent: works without user configuration
- Automatic sync for same repository across machines
- Automatic isolation for different repositories
- Backward compatible: falls back to existing behavior
Comment on lines +59 to +62
const remoteUrl = getGitRemoteUrl(directory);
if (remoteUrl) {
return `${CONFIG.containerTagPrefix}_project_${sha256(remoteUrl)}`;
}

This comment was marked as outdated.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Valid finding. Existing users have memories stored under sha256(directory). Switching to sha256(normalizeGitUrl(remoteUrl)) orphans those memories on upgrade — not just when adding a remote after creation.

Fixed in a88b0bd: all read operations (search, list, compaction context fetch) now query both the canonical remote-based tag and the legacy directory-based tag, deduplicating by memory ID. Writes go only to the new tag, so memories gradually migrate forward.

SSH and HTTPS URLs for the same repo (e.g. git@github.com:user/repo.git
vs https://github.com/user/repo) produced different hashes, silently
breaking cross-machine memory sync. Normalize URLs to a canonical form
before hashing. Also restores trailing newline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
return url
.replace(/^[a-z+]+:\/\//, "") // strip protocol (https://, git://, ssh://)
.replace(/^[^@]+@/, "") // strip user@ prefix (git@, user@)
.replace(/:(\d+)\//, "/$1/") // preserve port numbers (e.g. :8080/)

This comment was marked as outdated.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Evaluated and this is not a real issue. The port number is part of the server identity — if a server runs on port 2222, all clones will include :2222 and they normalize consistently to gitlab.local/2222/user/repo.

The only failure case would be one machine using ssh://git@gitlab.local:22/user/repo.git (explicitly specifying the default port) while another uses ssh://git@gitlab.local/user/repo.git. This is vanishingly rare — no standard git tooling generates URLs with the default port.

Stripping port numbers would actually be worse: it would incorrectly unify repos from different servers on the same host but different ports (e.g., a staging and production GitLab on the same machine).

… upgrade

Existing users have project memories stored under sha256(directory).
After switching to sha256(normalizeGitUrl(remoteUrl)), those memories
become silently inaccessible. Fix by querying both the new canonical
tag and the legacy directory-based tag for all read operations (search,
list, compaction context), deduplicating by memory ID. Writes go only
to the new canonical tag so memories gradually migrate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/index.ts Outdated
Comment on lines +449 to +452
const currentMems = result.memories || [];
const legacyMems = legacyListResult.success ? (legacyListResult.memories || []) : [];
const listSeenIds = new Set(currentMems.map((m: any) => m.id));
const memories = [...currentMems, ...legacyMems.filter((m: any) => !listSeenIds.has(m.id))];

This comment was marked as outdated.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Valid. All three merge sites now apply .slice(0, limit) after dedup. Fixed in ff06340.

Merging memories from both current and legacy tags could return up to
double the configured limit. Apply slice after dedup in all three merge
sites: initial context injection, list tool, and compaction fetch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

Is the logic of the current configuration file unable to achieve synchronization of specific project memory across multiple devices?

1 participant