Snapshot Manager Usage
The Snapshot Manager captures comprehensive state before and after long-running Claude sessions, ena
Snapshot Manager Usage Guide
The Snapshot Manager captures comprehensive state before and after long-running Claude sessions, enabling detailed analysis of what changed during 6-8 hour external agent loops.
Overview
The Snapshot Manager provides three core capabilities:
1. Pre-Session Snapshots - Capture initial state before Claude session starts 2. Post-Session Snapshots - Capture final state after Claude session completes 3. Diff Calculation - Compare snapshots to determine what changed
Basic Usage
import { SnapshotManager } from './snapshot-manager.mjs';
const projectRoot = '/path/to/project';
const iterationDir = '/path/to/iteration/001';
const snapshotMgr = new SnapshotManager(projectRoot);
// Before session starts
const preSnapshot = snapshotMgr.capturePreSnapshot(projectRoot, iterationDir);
// ... long-running Claude session ...
// After session completes
const postSnapshot = snapshotMgr.capturePostSnapshot(projectRoot, iterationDir);
// Calculate what changed
const diff = snapshotMgr.calculateDiff(preSnapshot, postSnapshot);
console.log(`Session duration: ${diff.duration}`);
console.log(`Files added: ${diff.filesAdded.length}`);
console.log(`Files modified: ${diff.filesModified.length}`);
console.log(`Commits made: ${diff.commitCount}`);
console.log(`AIWG artifacts created: ${diff.aiwgArtifactsCreated.length}`);
Pre-Session Snapshot
Captures the starting state including:
- Git Status: Current branch, commit hash, staged/unstaged/untracked files
- Key Files: Hashes of package.json, CLAUDE.md, CHANGELOG.md, etc.
- AIWG State: All files in `.aiwg/` directory with modification times and hashes
- Internal Ralph State: Current loop state if exists in `.aiwg/ralph/current-loop.json`
Example Output
{
"timestamp": "2026-01-18T12:00:00.000Z",
"git": {
"branch": "main",
"commit": "abc123def456...",
"staged": [],
"unstaged": ["src/module.ts"],
"untracked": [".aiwg/working/notes.md"]
},
"keyFiles": [
{
"path": "package.json",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"size": 1024,
"mtime": "2026-01-18T11:30:00.000Z"
}
],
"aiwg": {
"files": [
{
"path": ".aiwg/requirements/user-stories.md",
"hash": "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
"size": 2048,
"mtime": "2026-01-18T10:00:00.000Z"
}
],
"ralphState": {
"currentPhase": "elaboration",
"iteration": 2
}
}
}
Post-Session Snapshot
Captures the final state including:
- Git Status: Updated branch, commit, file states
- File Diffs: All files added, modified, or deleted since pre-snapshot
- Commits: All commits made during the session
- AIWG Updates: Updated `.aiwg/` directory state
- Test Results: Parsed test output if available
Example Output
{
"timestamp": "2026-01-18T18:00:00.000Z",
"git": {
"branch": "main",
"commit": "xyz789abc123...",
"staged": [],
"unstaged": [],
"untracked": []
},
"fileDiffs": [
{
"path": "src/new-feature.ts",
"status": "added"
},
{
"path": "src/module.ts",
"status": "modified",
"diff": "@@ -10,6 +10,8 @@\
+ // New implementation\
..."
}
],
"commits": [
"xyz789 feat: implement new feature",
"def456 refactor: improve module structure",
"abc789 test: add comprehensive test suite"
],
"aiwg": {
"files": [
{
"path": ".aiwg/architecture/sad.md",
"hash": "new-hash-value",
"size": 4096,
"mtime": "2026-01-18T17:45:00.000Z"
}
],
"ralphState": {
"currentPhase": "construction",
"iteration": 5
}
},
"tests": {
"found": true,
"file": "test-results.json",
"summary": {
"type": "jest",
"total": 45,
"passed": 43,
"failed": 2,
"skipped": 0
}
}
}
Snapshot Diff
The diff calculation provides a structured summary of all changes:
{
"duration": "6h 0m",
"durationMs": 21600000,
"filesAdded": ["src/new-feature.ts", "test/new-feature.test.ts"],
"filesModified": ["src/module.ts", "package.json"],
"filesDeleted": [],
"aiwgArtifactsCreated": [".aiwg/architecture/component-diagram.md"],
"aiwgArtifactsUpdated": [".aiwg/architecture/sad.md", ".aiwg/requirements/user-stories.md"],
"commitCount": 3,
"commits": [
"xyz789 feat: implement new feature",
"def456 refactor: improve module structure",
"abc789 test: add comprehensive test suite"
],
"hasTests": true,
"testSummary": {
"type": "jest",
"total": 45,
"passed": 43,
"failed": 2,
"skipped": 0
}
}
Integration with Orchestrator
The Snapshot Manager is designed to integrate with the External Agent Loop orchestrator:
// In orchestrator's iteration loop
// Before launching Claude session
const iterationDir = stateManager.getIterationDir(iteration);
const preSnapshot = snapshotManager.capturePreSnapshot(projectRoot, iterationDir);
// Launch Claude session
await sessionLauncher.launch(/* ... */);
// After session completes
const postSnapshot = snapshotManager.capturePostSnapshot(projectRoot, iterationDir);
const diff = snapshotManager.calculateDiff(preSnapshot, postSnapshot);
// Use diff for analysis
const report = `
## Session ${iteration} Summary
Duration: ${diff.duration}
Files Changed: ${diff.filesAdded.length + diff.filesModified.length}
AIWG Artifacts: ${diff.aiwgArtifactsCreated.length} created, ${diff.aiwgArtifactsUpdated.length} updated
Commits: ${diff.commitCount}
Tests: ${diff.hasTests ? `${diff.testSummary.passed}/${diff.testSummary.total} passed` : 'Not run'}
`;
Test Result Detection
The Snapshot Manager automatically searches for test results in common locations:
1. Iteration output logs - Parses stdout/stderr for test patterns 2. test-results.json - Jest/Vitest JSON output 3. .aiwg/testing/* - SDLC test artifacts 4. coverage/ - Coverage reports
Supported Test Formats
- Jest/Vitest JSON: Full test statistics
- Text patterns: "Tests: X passed, X total"
- Mocha: "X passing"
- TAP: "# tests X"
Error Handling
Pre-Snapshot Errors
try {
const preSnapshot = snapshotManager.capturePreSnapshot(projectRoot, iterationDir);
} catch (error) {
// Non-fatal - snapshot may be incomplete but should not crash
console.error('Pre-snapshot failed:', error.message);
}
Post-Snapshot Errors
try {
const postSnapshot = snapshotManager.capturePostSnapshot(projectRoot, iterationDir);
} catch (error) {
if (error.message.includes('Pre-snapshot not found')) {
// Fatal - cannot compare without baseline
throw error;
}
// Other errors may be non-fatal
console.error('Post-snapshot incomplete:', error.message);
}
Performance Considerations
- Large .aiwg directories: Snapshot capture time scales with file count
- Large git diffs: Diff generation can be slow for massive changes
- Nested directories: Deep directory structures increase traversal time
Optimization Tips
1. Exclude working files: Don't track `.aiwg/working/` in snapshots 2. Limit diff context: For large files, consider limiting git diff context lines 3. Async operations: Use Promise.all() for parallel file hashing when possible
Snapshot Storage
Snapshots are stored in the iteration directory:
.aiwg/ralph-external/iterations/
└── 001/
├── pre-snapshot.json # Captured before session
└── post-snapshot.json # Captured after session
Each snapshot file is ~1-10KB depending on project size.
Examples
Example 1: Simple Session Tracking
const snapshotMgr = new SnapshotManager('/path/to/project');
const iterDir = '.aiwg/ralph-external/iterations/001';
// Before
snapshotMgr.capturePreSnapshot('/path/to/project', iterDir);
// ... work happens ...
// After
const postSnap = snapshotMgr.capturePostSnapshot('/path/to/project', iterDir);
if (postSnap.tests.found) {
console.log('Tests ran:', postSnap.tests.summary);
}
Example 2: Progress Tracking
const preSnap = JSON.parse(
readFileSync('.aiwg/ralph-external/iterations/001/pre-snapshot.json')
);
const postSnap = JSON.parse(
readFileSync('.aiwg/ralph-external/iterations/001/post-snapshot.json')
);
const diff = snapshotMgr.calculateDiff(preSnap, postSnap);
console.log(`
Progress Report:
- Duration: ${diff.duration}
- New features: ${diff.filesAdded.filter(f => f.startsWith('src/')).length}
- Tests added: ${diff.filesAdded.filter(f => f.includes('.test.')).length}
- Documentation: ${diff.aiwgArtifactsCreated.length} artifacts created
`);
Example 3: Test Coverage Tracking
function analyzeTestCoverage(diff) {
if (!diff.hasTests) {
return 'No tests run';
}
const { passed, failed, total } = diff.testSummary;
const passRate = (passed / total * 100).toFixed(1);
return `${passRate}% pass rate (${passed}/${total} tests passed)`;
}
const diff = snapshotMgr.calculateDiff(preSnap, postSnap);
console.log(analyzeTestCoverage(diff));
Troubleshooting
"Pre-snapshot not found"
Ensure you called `capturePreSnapshot()` before attempting `capturePostSnapshot()`.
Git commands failing
If not in a git repository, git fields will show "unknown" but snapshot still works.
Missing test results
Check that: 1. Tests actually ran during the session 2. Output is in a recognized format 3. Test files are in expected locations
Large snapshot files
If snapshots exceed 100KB: 1. Check for large binary files in `.aiwg/` 2. Consider excluding large generated files 3. Verify git diff output isn't enormous
References
- `@.aiwg/requirements/design-ralph-external.md` - External Agent Loop design
- @tools/ralph-external/state-manager.mjs - Session state management
- @tools/ralph-external/output-analyzer.mjs - Output analysis patterns