How to Troubleshoot Git Worktree Isolation in the Epic 1 Worktree Manager of aios-core
To troubleshoot Git worktree isolation issues in SynkraAI/aios-core, verify your core-config.yaml settings, run diagnostic commands via story-worktree-hooks.js, and use the WorktreeManager API to detect conflicts and clean up stale worktrees.
The Epic 1 Worktree Manager in the SynkraAI/aios-core repository provides automated Git worktree isolation for story-based development, ensuring each feature branch operates in a dedicated directory under .aios/worktrees. When developers encounter "worktree already exists" errors, stale isolation directories, or merge conflicts, systematic troubleshooting using the built-in CLI hooks and JavaScript API restores repository integrity. This guide covers diagnostic steps and resolution strategies for common Git worktree isolation failures.
Architecture of the Epic 1 Worktree Manager
The isolation system relies on four primary components that orchestrate Git worktree operations and enforce repository boundaries.
Core Components
WorktreeManager(.aios-core/infrastructure/scripts/worktree-manager.js): Low-level wrapper aroundgit worktreecommands handling creation, listing, removal, stale detection, conflict detection, and merge auditing.story-worktree-hooks.js(.aios-core/infrastructure/scripts/story-worktree-hooks.js): High-level CLI interface invoked on story state transitions (onStoryStart,onStoryDone), readingcore-config.yamlto decide auto-creation and auto-cleanup behavior.auto-worktree.yaml(.aios-core/development/workflows/auto-worktree.yaml): Declarative workflow executed by the AIOS engine that orchestrates extraction, pre-flight checks, creation, and status updates.core-config.yaml: Project-wide configuration enabling worktree features, settingmaxWorktrees(default 10), andstaleDays(default 30).
Isolation Guarantees
Each worktree receives a dedicated branch (auto-claude/<storyId>) and directory under .aios/worktrees/<storyId>. The manager records creation timestamps and uncommitted change counts, marking worktrees as stale after exceeding the staleDays threshold.
Common Git Worktree Isolation Failures and Solutions
"Worktree Already Exists" Errors
Symptom: The error Worktree already exists appears when starting a story.
Root Cause: A previous worktree was left behind from a failed run or manual interruption.
Diagnostic Steps:
- Run
node .aios-core/infrastructure/scripts/story-worktree-hooks.js status <story-file>. - Verify
hasWorktree: trueand note itspath.
Resolution:
- If the worktree is still needed, creation is skipped (the
--forceflag is ignored for existing worktrees). - If stale, run
node .aios-core/infrastructure/scripts/story-worktree-hooks.js done <story-file>and select cleanup, or use--keep-worktreeto preserve data while removing the Git worktree reference.
Maximum Worktree Limit Reached
Symptom: Error Maximum worktrees limit (10) reached prevents new story isolation.
Root Cause: The repository contains the maximum number of active worktrees (manager.getCount().total >= maxWorktrees).
Diagnostic Steps:
- Run
node .aios-core/infrastructure/scripts/story-worktree-hooks.js listor use the manager'slist()method in a Node REPL. - Identify stale or completed worktrees by checking timestamps.
Resolution:
Delete unwanted worktrees manually:
node .aios-core/infrastructure/scripts/story-worktree-hooks.js done <story-file> --keep-worktree
Then force remove via API:
const WM = require('./.aios-core/infrastructure/scripts/worktree-manager');
const mgr = new WM(process.cwd());
await mgr.remove('STORY-42', {force: true});
Alternatively, enable autoCleanup: true in .aios-core/development/workflows/auto-worktree.yaml to automatically purge stale worktrees.
Uncommitted Changes Blocking Cleanup
Symptom: Worktree has X uncommitted changes error during onStoryDone cleanup.
Root Cause: The worktree contains local edits that haven't been committed or stashed.
Diagnostic Steps:
- Run
node .aios-core/infrastructure/scripts/story-worktree-hooks.js status <story-file>to seeuncommittedChanges > 0. - Run
git statusinside the worktree directory (.aios/worktrees/<storyId>).
Resolution:
Commit or stash changes before cleanup:
cd .aios/worktrees/STORY-42
git add .
git commit -m "WIP: save before worktree cleanup"
Alternatively, use the done hook with merge option first:
node .aios-core/infrastructure/scripts/story-worktree-hooks.js done <story-file>
Select merge to integrate changes into the base branch, then proceed with cleanup.
Git Command Failures and Repository State Issues
Symptom: Raw Git errors like git worktree add … failing.
Root Cause: Repository is not a clean Git tree (detached HEAD, unresolved merge, missing .git directory).
Diagnostic Steps:
-
Run pre-flight checks manually:
git rev-parse --is-inside-work-tree git worktree list -
Check for detached HEAD:
git symbolic-ref --short HEAD
Resolution:
- Resolve any Git conflicts and ensure you are on a valid branch.
- If the repository is corrupted, reclone it and reinitialize the worktree manager.
- Ensure the workflow's pre_flight block commands pass before invoking
auto-worktree.yaml.
Stale Worktree Detection and Removal
Symptom: Dashboard shows outdated worktrees or status.json contains invalid paths.
Root Cause: Worktrees exceed the staleDays threshold (default 30 days) or were manually deleted outside the manager.
Diagnostic Steps:
- Inspect
manager.getCount()to see stale counts. - Check
.aios/status.jsonforactiveWorktreefield accuracy.
Resolution:
Force clean stale worktrees:
const WM = require('./.aios-core/infrastructure/scripts/worktree-manager');
const mgr = new WM(process.cwd());
const removed = await mgr.cleanupStale();
console.log('Cleaned up stale worktrees:', removed);
Diagnostic Commands and Debugging Techniques
Using the story-worktree-hooks.js CLI
The high-level CLI provides quick diagnostics without writing code:
# Check specific story status
node .aios-core/infrastructure/scripts/story-worktree-hooks.js status docs/stories/story-1.4.md
# List all worktrees
node .aios-core/infrastructure/scripts/story-worktree-hooks.js list
# Check effective configuration
node .aios-core/infrastructure/scripts/story-worktree-hooks.js config
Programmatic Inspection with WorktreeManager
For deeper debugging, use the Node.js API directly:
const WorktreeManager = require('./.aios-core/infrastructure/scripts/worktree-manager');
(async () => {
const mgr = new WorktreeManager(process.cwd());
// Get comprehensive counts
const counts = await mgr.getCount();
console.log(`Total: ${counts.total}, Active: ${counts.active}, Stale: ${counts.stale}`);
// List all with metadata
const worktrees = await mgr.list();
console.log(worktrees);
// Check specific worktree path
const path = mgr.getWorktreePath('STORY-42');
console.log('Worktree location:', path);
// Detect merge conflicts before attempting merge
const conflicts = await mgr.detectConflicts('STORY-42');
if (conflicts.length) {
console.warn('Conflicts detected:', conflicts);
}
})();
Enabling Verbose Logging
Set configuration flags to see detailed Git command execution:
# Environment variable
export AIOS_DEBUG=1
# Or set in auto-worktree.yaml
config:
verbose: true
With verbose mode enabled, the manager prints chalk-colored logs for each git worktree command, making it easy to spot where failures occur.
Code Examples for Troubleshooting
Run the High-Level Hook from the CLI
# When a story moves to "In Progress"
node .aios-core/infrastructure/scripts/story-worktree-hooks.js start docs/stories/story-1.4.md
# When a story is marked "Done"
node .aios-core/infrastructure/scripts/story-worktree-hooks.js done docs/stories/story-1.4.md
Add --force to bypass a manual autoCreate setting, or --keep-worktree to prevent auto-cleanup.
Detect Conflicts Before Merging a Story
const WM = require('./.aios-core/infrastructure/scripts/worktree-manager');
(async () => {
const mgr = new WM(process.cwd());
const conflicts = await mgr.detectConflicts('STORY-42');
if (conflicts.length) {
console.warn('Conflicts would arise:', conflicts);
} else {
console.log('Safe to merge.');
}
})();
Force-Clean Stale Worktrees
const WM = require('./.aios-core/infrastructure/scripts/worktree-manager');
(async () => {
const mgr = new WM(process.cwd());
const removed = await mgr.cleanupStale(); // returns array of storyIds removed
console.log('Cleaned up stale worktrees:', removed);
})();
Manually Merge a Worktree with Audit Log
const WM = require('./.aios-core/infrastructure/scripts/worktree-manager');
(async () => {
const mgr = new WM(process.cwd());
const result = await mgr.mergeToBase('STORY-42', {
squash: true,
cleanup: true,
message: 'Feature complete for STORY-42',
});
console.log('Merge result:', result);
})();
The mergeToBase method writes a JSON audit file under .aios/logs/merges/.
Summary
- Git worktree isolation in aios-core relies on the
WorktreeManagerclass in.aios-core/infrastructure/scripts/worktree-manager.js, which wraps native Git commands and enforces limits viamaxWorktrees(default 10) andstaleDays(default 30). - When troubleshooting, start with CLI diagnostics provided by
story-worktree-hooks.js(status,list,config) to quickly identify existing worktrees and configuration issues. - For "Worktree already exists" errors, verify with
statusand use thedonehook with cleanup options, or force-remove via the API withmanager.remove(storyId, {force: true}). - Resolve maximum limit errors by cleaning stale worktrees using
manager.cleanupStale()or enablingautoCleanup: trueinauto-worktree.yaml. - Address uncommitted changes by committing or stashing inside the worktree directory before invoking cleanup, or merge first using
mergeToBase(). - Use verbose logging (
AIOS_DEBUG=1orconfig.verbose: true) and the Node.js REPL to inspectgetCount(),list(), anddetectConflicts()for deep debugging.
Frequently Asked Questions
How do I check if a story already has an active worktree?
Run the status command using the story file path:
node .aios-core/infrastructure/scripts/story-worktree-hooks.js status docs/stories/story-1.4.md
This returns JSON indicating hasWorktree: true or false, along with the filesystem path and uncommitted change count. You can also programmatically verify existence using manager.getWorktreePath(storyId) to check if the directory is registered in Git's worktree list.
What is the default maximum number of worktrees allowed?
The default maximum worktree limit is 10, controlled by the maxWorktrees parameter in core-config.yaml or auto-worktree.yaml. When manager.getCount().total reaches this threshold, new worktree creation fails with a "Maximum worktrees limit reached" error. You can increase this limit in your configuration file or reduce the current count by removing stale worktrees via manager.cleanupStale().
How do I force remove a worktree that is marked as stale?
Use the WorktreeManager API with the force option to bypass safety checks:
const WM = require('./.aios-core/infrastructure/scripts/worktree-manager');
const mgr = new WM(process.cwd());
await mgr.remove('STORY-42', {force: true});
Alternatively, run cleanupStale() to automatically remove all worktrees exceeding the staleDays threshold (default 30 days). For CLI-based removal, use node story-worktree-hooks.js done <story-file> followed by selecting the cleanup option, which handles both the Git worktree removal and directory cleanup.
Why does the cleanup fail with uncommitted changes?
The onStoryDone hook and cleanupStale() methods check for uncommitted changes before removing a worktree to prevent accidental data loss. If git status detects modified or untracked files, the manager throws a "Worktree has X uncommitted changes" error and aborts the cleanup. To resolve this, navigate to the worktree directory (.aios/worktrees/<storyId>), commit or stash your changes, then retry the cleanup. Alternatively, use mergeToBase() first to integrate changes into the main branch before removing the worktree.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →