219 files, 2.0 MB, untracked in souveraine/docs and existing nowhere else. The volume is at 100% with no snapshots.
5.6 KiB
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 logicsrc/core/memory/conflict.rs- Conflict resolutionsrc/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
/synccommands - 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.