Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/substrate/tasks/remote-git-sync.md
Fimeg e480809c70 docs: rescue the agent-substrate tree out of a gitignored directory
219 files, 2.0 MB, untracked in souveraine/docs and existing nowhere else.
The volume is at 100% with no snapshots.
2026-07-26 12:11:50 -04:00

5.6 KiB

task_id title status assignee priority phase
remote-git-001 Remote Git Sync - Push/Pull with Conflict Resolution scoped TBD medium 2

Task: Remote Git Sync

Objective

Implement remote git sync (push/pull) with conflict resolution for the git-backed memory system. Currently only Gitea is supported; this adds general git remote support.

Background

Current state: src/core/memory/mod.rs has a TODO:

pub fn push(&self) -> Result<()> {
    // TODO: Implement push to remote
    todo!("push not yet implemented")
}

From Letta v3: Git as sync mechanism with clone/pull/push lifecycle.

The Sync Lifecycle

1. Initialization (Clone)

pub fn clone_remote(url: &str, agent_id: &str) -> Result<MemoryRepo> {
    // Clone from remote to ~/.souveraine/agents/{id}/memory/
    // Configure identity
    // Install hooks
}

2. Startup Sync (Pull)

pub async fn startup_sync(&self) -> Result<SyncResult> {
    // Stash local changes
    // Pull from remote
    // Handle conflicts
    // Restore stashed changes
    // Return sync summary
}

3. Runtime Sync (Auto-push)

pub fn auto_push(&self) -> Result<()> {
    // After every commit (optional)
    // Or periodic (configurable)
    // Push to remote
    // Retry on failure
}

4. Manual Sync

/souveraine sync push     - Push now
/souveraine sync pull     - Pull now
/souveraine sync status   - Check sync status

Supported Remotes

Remote Type Auth Use Case
HTTPS Token in URL Simple, token-based
SSH SSH keys Secure, key-based
Gitea API token Built-in support ()
GitHub PAT Popular hosting
GitLab Token Alternative hosting

Configuration

[memory.git_sync]
enabled = true
remote_url = "https://github.com/user/souveraine-memory.git"
auth_method = "token"  # or "ssh", "oauth"
auto_push = true
auto_pull_on_startup = true
push_interval_seconds = 300  # 5 minutes

[memory.git_sync.auth]
token = "ghp_..."  # Or env var: SOUVERAINE_GIT_TOKEN
ssh_key = "~/.ssh/souveraine_ed25519"

Conflict Resolution

Strategies:

Strategy When Action
Ours Local changes are source of truth Keep local, discard remote
Theirs Remote is authoritative Keep remote, stash local
Merge Both have valuable changes Attempt auto-merge
Manual Complex conflict Surface to user, pause sync

Conflict Detection:

pub enum ConflictResolution {
    Ours,       // Keep local
    Theirs,     // Keep remote
    Merge(Vec<MergeConflict>),  // Manual resolution needed
    Stash,      // Stash local, apply remote
}

impl MemoryRepo {
    pub fn resolve_conflicts(&self, strategy: ConflictStrategy) -> Result<ConflictResolution> {
        // Detect conflicts
        // Apply strategy
        // Return result
    }
}

User Notification:

[surfacing: sync] Sync conflict detected in system/persona.md
Local and remote both modified. Manual resolution required.

Options:
1. Keep local (ours)
2. Keep remote (theirs)
3. View diff and decide

Implementation

New Files:

  • src/core/memory/sync.rs - Sync logic
  • src/core/memory/conflict.rs - Conflict resolution
  • src/core/memory/remote.rs - Remote operations

Modify:

  • src/core/memory/mod.rs - Add sync methods, implement push()

APIs:

pub struct GitSync {
    repo: MemoryRepo,
    remote: RemoteConfig,
    strategy: ConflictStrategy,
}

impl GitSync {
    /// Clone from remote
    pub fn clone(url: &str, auth: &Auth) -> Result<Self>;
    
    /// Pull from remote
    pub async fn pull(&self) -> Result<SyncResult>;
    
    /// Push to remote
    pub async fn push(&self) -> Result<SyncResult>;
    
    /// Full sync (pull + push)
    pub async fn sync(&self) -> Result<SyncResult>;
    
    /// Check sync status
    pub fn status(&self) -> Result<SyncStatus>;
    
    /// Resolve conflicts
    pub fn resolve(&self, resolution: ConflictResolution) -> Result<()>;
}

pub struct SyncResult {
    pub pulled: Vec<Commit>,
    pub pushed: Vec<Commit>,
    pub conflicts: Vec<Conflict>,
    pub stashed: Option<Stash>,
}

CLI Commands

Add to main CLI:

souveraine sync pull [agent]
souveraine sync push [agent]
souveraine sync status [agent]
souveraine sync resolve --ours|--theirs <file>

Add to TUI slash commands:

/sync pull     - Pull from remote
/sync push     - Push to remote
/sync status   - Show sync status

Success Criteria

  • Push implemented and working
  • Pull implemented and working
  • HTTPS with token auth
  • SSH key auth
  • Auto-push on commit (optional)
  • Auto-pull on startup (optional)
  • Conflict detection
  • Conflict resolution (ours/theirs/merge)
  • Manual conflict resolution UI
  • Sync status display
  • CLI sync commands
  • TUI /sync commands
  • Unit tests for sync logic
  • Integration test with temp remote

References

  • src/core/memory/mod.rs (TODO comment)
  • LETTA_MEMFS_TECHNICAL_SPEC.md (git sync spec)
  • saf/gaps.md ("Remote Git Sync - Clone/pull/push")
  • git2 crate documentation

Estimated Scope

  • Core sync logic: 3-4 days
  • Auth (HTTPS/SSH): 2-3 days
  • Conflict resolution: 3-4 days
  • CLI commands: 1-2 days
  • TUI integration: 2-3 days
  • Testing: 2-3 days

Total: 13-19 days

Dependencies

  • Git2 crate ( already used)
  • Memory repo ( done)
  • HTTP client ( reqwest already used)
  • SSH libraries (optional)

Can Start Without

  • SSH can be added after HTTPS
  • Auto-sync can be manual first
  • Conflict UI can be CLI first, TUI later

Core push/pull with basic resolution is MVP.