agent-orchestrator/changelog/hash-based-architecture-mig...

469 lines
11 KiB
Markdown

# Migration Guide: Hash-Based Architecture
**Date**: 2026-02-17
**Breaking Change**: Yes
**Affects**: All users with existing sessions
## What Changed
Agent Orchestrator has migrated from flat, configurable directories (`dataDir` and `worktreeDir`) to a **hash-based project isolation** architecture. This change eliminates configuration overhead and prevents collisions when running multiple orchestrator instances from different directories.
### Before (Flat Architecture)
```yaml
# agent-orchestrator.yaml
dataDir: ~/.ao-sessions
worktreeDir: ~/.ao-worktrees
projects:
my-app:
path: ~/repos/my-app
```
**Problems**:
- Multiple configs sharing same `dataDir` caused session collisions
- Manual path configuration required
- No isolation between orchestrator instances
- Backwards compatibility code added complexity
### After (Hash-Based Architecture)
```yaml
# agent-orchestrator.yaml
# No dataDir or worktreeDir needed!
projects:
my-app:
path: ~/repos/my-app
```
**Benefits**:
- Zero configuration — paths auto-derived from config location
- Complete isolation — each config gets unique namespace
- Collision-free — SHA256 hash prevents conflicts
- Clean codebase — no backwards compatibility code
## Architecture Details
### Directory Structure
All orchestrator data now lives under `~/.agent-orchestrator/`:
```
~/.agent-orchestrator/
├── {hash}-{projectId}/ # Unique per config+project
│ ├── .origin # Stores config path (collision detection)
│ ├── sessions/ # Session metadata
│ │ ├── int-1 # Metadata for session int-1
│ │ ├── int-2
│ │ └── archive/ # Archived metadata
│ └── worktrees/ # Git worktrees
│ ├── int-1/ # Worktree for session int-1
│ └── int-2/
```
### Hash Generation
The hash is the first 12 characters of `SHA256(realpath(dirname(configPath)))`:
```typescript
// Config at: ~/projects/acme/agent-orchestrator.yaml
// Hash of: /Users/you/projects/acme
// Result: a3b4c5d6e7f8
// Final path: ~/.agent-orchestrator/a3b4c5d6e7f8-my-app/
```
**Why 12 chars?** Balance between uniqueness (collision probability ~1 in 16 billion) and path length.
### Session Naming Layers
Three levels of naming for compatibility:
1. **User-facing**: `int-1`, `ao-42` (short, clean)
2. **Tmux**: `a3b4c5d6e7f8-int-1` (globally unique across all configs)
3. **Metadata file**: `int-1` (within project-specific `sessions/` directory)
## Breaking Changes
### 1. Config File Changes
**REMOVED fields** (will cause validation errors if present):
- `dataDir`
- `worktreeDir`
**REQUIRED field**:
- `configPath` (automatically set by `loadConfig()`)
**Migration**:
```diff
# agent-orchestrator.yaml
- dataDir: ~/.ao-sessions
- worktreeDir: ~/.ao-worktrees
projects:
my-app:
path: ~/repos/my-app
```
### 2. Metadata File Locations
**Before**:
```
~/.ao-sessions/
├── int-1 # Flat directory, all projects mixed
├── int-2
├── ao-1
└── ao-2
```
**After**:
```
~/.agent-orchestrator/
├── a3b4c5d6e7f8-integrator/sessions/
│ ├── int-1 # Integrator project sessions
│ └── int-2
└── f9e8d7c6b5a4-my-app/sessions/
├── ao-1 # My-app project sessions
└── ao-2
```
**Impact**: Existing metadata files **will not be automatically migrated**. See migration steps below.
### 3. Worktree Locations
**Before**:
```
~/.ao-worktrees/
├── integrator/
│ ├── int-1
│ └── int-2
└── my-app/
├── ao-1
└── ao-2
```
**After**:
```
~/.agent-orchestrator/
├── a3b4c5d6e7f8-integrator/worktrees/
│ ├── int-1
│ └── int-2
└── f9e8d7c6b5a4-my-app/worktrees/
├── ao-1
└── ao-2
```
**Impact**: Existing worktrees **will not be automatically migrated**. Git will report them as "missing" and they must be manually removed.
### 4. Environment Variables
**Before**:
```bash
AO_DATA_DIR=~/.ao-sessions # Flat path
```
**After**:
```bash
AO_DATA_DIR=~/.agent-orchestrator/a3b4c5d6e7f8-integrator/sessions/
```
**Impact**: Scripts or hooks relying on `AO_DATA_DIR` pointing to a flat directory will break.
### 5. API Changes (For Plugin Developers)
**Removed from `OrchestratorConfig`**:
```typescript
interface OrchestratorConfig {
dataDir: string; // REMOVED
worktreeDir: string; // REMOVED
configPath: string; // NOW REQUIRED
}
```
**New Path Utilities** (use these instead):
```typescript
import {
getSessionsDir,
getWorktreesDir,
getProjectBaseDir,
generateConfigHash,
generateInstanceId,
validateAndStoreOrigin,
} from "@composio/ao-core";
// Calculate paths dynamically
const sessionsDir = getSessionsDir(configPath, projectPath);
const worktreesDir = getWorktreesDir(configPath, projectPath);
```
## Migration Steps
### Step 1: Clean Up Config File
Remove `dataDir` and `worktreeDir` from your config:
```bash
# Edit your agent-orchestrator.yaml
vim ~/path/to/agent-orchestrator.yaml
```
Remove these lines:
```yaml
dataDir: ~/.ao-sessions
worktreeDir: ~/.ao-worktrees
```
### Step 2: Kill Existing Sessions
**IMPORTANT**: Existing sessions will **not** automatically migrate. You must kill them first.
```bash
# List all tmux sessions
tmux ls
# Kill all orchestrator sessions (adjust prefix as needed)
tmux ls | grep -E '^(int|ao|app)-[0-9]+:' | cut -d: -f1 | xargs -I{} tmux kill-session -t {}
# Or kill all tmux sessions (nuclear option)
tmux kill-server
```
### Step 3: Clean Up Old Directories
**Worktrees** must be removed from git:
```bash
# For each project, remove old worktrees
cd ~/repos/integrator
# List worktrees
git worktree list
# Remove each old worktree
git worktree remove ~/.ao-worktrees/integrator/int-1 --force
git worktree remove ~/.ao-worktrees/integrator/int-2 --force
# ... repeat for all
# Prune stale references
git worktree prune
```
**Metadata** can be archived for reference:
```bash
# Archive old metadata (optional)
mv ~/.ao-sessions ~/.ao-sessions-backup-$(date +%Y%m%d)
# Or delete if you don't need it
rm -rf ~/.ao-sessions
```
**Worktree directory** can be removed after cleaning up git references:
```bash
# Remove old worktree directory (after git worktree remove)
rm -rf ~/.ao-worktrees
```
### Step 4: Update to Latest Version
```bash
# Pull latest code
git pull origin main
# Reinstall dependencies
pnpm install
# Rebuild packages
pnpm build
```
### Step 5: Start Fresh
```bash
# Start orchestrator (creates new directory structure)
ao start
# Spawn new sessions (uses hash-based paths)
ao spawn my-app INT-1234
```
### Step 6: Verify New Structure
```bash
# Check that new directories were created
ls -la ~/.agent-orchestrator/
# You should see directories like:
# a3b4c5d6e7f8-my-app/
# .origin
# sessions/
# worktrees/
# Check tmux sessions have hash prefix
tmux ls
# Should show: a3b4c5d6e7f8-int-1, a3b4c5d6e7f8-int-2, etc.
```
## Rollback (If Needed)
If you need to rollback to the old architecture:
1. **Checkout previous commit** (before hash-based migration):
```bash
git checkout <commit-before-migration>
pnpm install
pnpm build
```
2. **Restore old config**:
```bash
# Add back to agent-orchestrator.yaml
dataDir: ~/.ao-sessions
worktreeDir: ~/.ao-worktrees
```
3. **Restore old metadata** (if archived):
```bash
mv ~/.ao-sessions-backup-20260217 ~/.ao-sessions
```
4. **Kill new hash-based sessions**:
```bash
tmux ls | grep -E '^[a-f0-9]{12}-' | cut -d: -f1 | xargs -I{} tmux kill-session -t {}
```
## FAQ
### Q: Why can't I use my old sessions?
**A**: The metadata file structure changed. Old sessions point to flat directories (`~/.ao-sessions/int-1`) but the new code expects hash-based paths (`~/.agent-orchestrator/a3b4c5d6e7f8-integrator/sessions/int-1`). You must kill old sessions and spawn new ones.
### Q: Will my PRs be lost?
**A**: No! PRs are on GitHub, not in local sessions. You can:
1. Check `gh pr list` to see all open PRs
2. Spawn new sessions for PRs that need work: `ao spawn integrator --branch feat/existing-branch`
### Q: What about in-progress work?
**A**: Git worktrees contain your code changes. Before killing sessions:
1. Commit or stash changes in each worktree
2. Note which issues/branches were being worked on
3. After migration, spawn new sessions and continue work
### Q: Can I migrate metadata files manually?
**A**: Yes, but **not recommended**. The manual process:
```bash
# For each project
OLD_DIR=~/.ao-sessions
NEW_DIR=~/.agent-orchestrator/$(python3 -c "import hashlib; print(hashlib.sha256(b'/Users/you/path/to/config/dir').hexdigest()[:12])")-integrator/sessions
mkdir -p "$NEW_DIR"
# Copy metadata files
cp "$OLD_DIR"/int-* "$NEW_DIR/"
# Update worktree paths in each file (required!)
for file in "$NEW_DIR"/*; do
sed -i '' 's|worktree=~/.ao-worktrees/integrator/|worktree=~/.agent-orchestrator/HASH-integrator/worktrees/|g' "$file"
done
```
This is error-prone. **Recommended**: Kill old sessions and spawn fresh ones.
### Q: What happens if I have multiple config files?
**A**: Each config gets a unique hash! This is the **main benefit** of the new architecture:
```bash
# Config 1: ~/projects/acme/agent-orchestrator.yaml
# Hash: a3b4c5d6e7f8
# Sessions: ~/.agent-orchestrator/a3b4c5d6e7f8-my-app/
# Config 2: ~/experiments/test/agent-orchestrator.yaml
# Hash: 1f2e3d4c5b6a
# Sessions: ~/.agent-orchestrator/1f2e3d4c5b6a-my-app/
```
No conflicts, complete isolation!
### Q: How do I find the hash for my config?
**A**:
```bash
# Calculate hash for your config directory
echo -n "/path/to/your/config/dir" | sha256sum | cut -c1-12
# Or let ao print it
ao status
# Output shows: Config: /path/to/config.yaml
# Hash will be in directory names: ~/.agent-orchestrator/{hash}-{project}/
```
### Q: What if two configs have the same hash (collision)?
**A**: The `.origin` file detects this and throws an error with instructions:
```
Hash collision detected!
Directory: ~/.agent-orchestrator/a3b4c5d6e7f8-my-app
Expected config: /Users/you/config1/agent-orchestrator.yaml
Actual config: /Users/you/config2/agent-orchestrator.yaml
This is a rare hash collision. Please move one of the configs to a different directory.
```
**Solution**: Move one config to a different directory. Collision probability is ~1 in 16 billion with 12-character hashes.
## Support
If you encounter issues during migration:
1. Check existing sessions: `tmux ls`
2. Check new directory structure: `ls -la ~/.agent-orchestrator/`
3. Check config validation: `ao status`
4. Review git worktrees: `git worktree list` (from project directory)
5. Check logs: `journalctl -u ao-orchestrator` or tmux session output
For bugs or questions, file an issue: https://github.com/composiohq/agent-orchestrator/issues
## Summary
**Action Required**:
1. ✅ Remove `dataDir` and `worktreeDir` from config
2. ✅ Kill all existing sessions (`tmux kill-server`)
3. ✅ Clean up old git worktrees (`git worktree remove --force`)
4. ✅ Remove old directories (`~/.ao-sessions`, `~/.ao-worktrees`)
5. ✅ Update to latest version (`pnpm install && pnpm build`)
6. ✅ Start fresh (`ao start`, `ao spawn`)
**Expected Downtime**: ~10 minutes (time to kill sessions, clean worktrees, respawn)
**Risk Level**: Low (PRs are safe, code is in git, only local sessions affected)
**Benefit**: Cleaner architecture, zero config, collision-free multi-instance support