Bug Description
Upstream issue draft: autohand startup hangs ~30s in large repos
Title: Startup hangs ~30s in large repos: three full-tree scans ignore .gitignore
Version: 0.9.7-alpha.f4775fd
Environment: macOS arm64 (Apple M4, 10 cores, 16GB), Node v26.3.0, Bun 1.4.2
Summary
In a repo with 10 GB / 218K files (.derivedData 50K files, .claude/worktrees 121K files across 6 worktrees — all gitignored), autohand blocks ~30s before the first prompt. Three independent startup scans walk the tree, and none of them respect .gitignore:
-
collectWorkspaceFiles() / walkWorkspaceFiles — only skips the hardcoded FILE_WALK_IGNORED_DIRECTORIES = {".git",".hg",".svn","node_modules","dist","build","coverage"}. It does not use the GitIgnoreParser that already exists elsewhere in the codebase. Simulating the exact algorithm in plain Node: 231,337 files, ~4.3s — and this runs inside initializeAgentManagers → workspace_files at startup.
-
FFFSearchProvider.create(workspaceRoot) — calls ffiCreate(basePath, …, aiMode: true) with no disableWatch, no disableContentIndexing, no cache budgets, then blocks on waitForScan(1e4) (10s timeout). FFF respects gitignore, but on first run it still walks/stats/content-indexes the tree and installs a watcher. The TUI shows a " Scanning <source>..." phase.
-
Skills discovery walker — skip set is {".git",".hg","node_modules","vendor","dist","build","target","coverage",".venv","venv",".next",".turbo",".vitest",".worktrees","__pycache__"} — again no .derivedData/.claude. Its descend rule accepts any ^\.[\w-]+$ top-level dir, so it descends into .derivedData and .claude (20–30K entry budgets), plus walks ~/.autohand, ~/.claude, ~/.codex at depth 9.
-
MCP connectAll — 4 servers spawned in parallel at startup (uvx, npx, remote HTTP, xcrun); measured 0.15–4.2s each, plus zombie MCP processes from prior sessions.
All of this is awaited before the first instruction (performBackgroundInit → ensureInitComplete).
Repro
# repo with a gitignored dir containing 50K+ files (e.g. .derivedData) and
# .claude/worktrees with several full checkouts
time autohand # ~30s before prompt
AUTOHAND_DEBUG=1 autohand 2>/tmp/ah-debug.log # observe Scanning phase
mv .derivedData /tmp/ && mv .claude/worktrees /tmp/ && time autohand # ~2-4s
Expected behavior
- Startup must not block on scanning gitignored directories; the first prompt should appear quickly.
- Scans should be lazy (deferred until
fff_find/find_grep/skills are actually used) or respect .gitignore.
Suggested fixes
- Make
FILE_WALK_IGNORED_DIRECTORIES gitignore-aware (reuse GitIgnoreParser) or configurable.
- Add common build/tool dirs to both walker skip sets:
.derivedData, .claude, .venv*, .opencode, .cache, .ruff_cache, .superpowers, .xcodebuildmcp, .test-batch-state, .worktrees.
- Add config to disable FFF watch/content-indexing at startup, or make FFF init lazy.
- Consider a startup budget: don't gate the first instruction on background scans.
Local evidence (XXX repo)
- Repo size: 10 GB, 218,241 files (
find . = 5.5s)
.derivedData: 4.7 GB / 50,493 files
.claude/worktrees: 2.4 GB / 121,588 files (6 worktrees)
.git: 839 MB
- Simulated
walkWorkspaceFiles (exact skip set): 231,337 files, 4.3s
- MCP cold-start measurements: npx xcodebuildmcp 1.4s, uvx memory 4.2s, xcrun mcpbridge 0.15s
- Zombie MCP processes observed: 3× xcodebuildmcp + 1× mcp-remote from prior sessions
Steps to Reproduce
.
Expected Behavior
.
Actual Behavior
.
Autohand Version
0.9.7
Operating System
macOS (Apple Silicon)
OS Version
No response
Installation Method
curl install script
LLM Model (if applicable)
No response
Error Logs
Configuration (optional)
Checklist
Bug Description
Upstream issue draft: autohand startup hangs ~30s in large repos
Title: Startup hangs ~30s in large repos: three full-tree scans ignore .gitignore
Version: 0.9.7-alpha.f4775fd
Environment: macOS arm64 (Apple M4, 10 cores, 16GB), Node v26.3.0, Bun 1.4.2
Summary
In a repo with 10 GB / 218K files (
.derivedData50K files,.claude/worktrees121K files across 6 worktrees — all gitignored),autohandblocks ~30s before the first prompt. Three independent startup scans walk the tree, and none of them respect.gitignore:collectWorkspaceFiles()/walkWorkspaceFiles— only skips the hardcodedFILE_WALK_IGNORED_DIRECTORIES = {".git",".hg",".svn","node_modules","dist","build","coverage"}. It does not use theGitIgnoreParserthat already exists elsewhere in the codebase. Simulating the exact algorithm in plain Node: 231,337 files, ~4.3s — and this runs insideinitializeAgentManagers→workspace_filesat startup.FFFSearchProvider.create(workspaceRoot)— callsffiCreate(basePath, …, aiMode: true)with nodisableWatch, nodisableContentIndexing, no cache budgets, then blocks onwaitForScan(1e4)(10s timeout). FFF respects gitignore, but on first run it still walks/stats/content-indexes the tree and installs a watcher. The TUI shows a" Scanning <source>..."phase.Skills discovery walker — skip set is
{".git",".hg","node_modules","vendor","dist","build","target","coverage",".venv","venv",".next",".turbo",".vitest",".worktrees","__pycache__"}— again no.derivedData/.claude. Its descend rule accepts any^\.[\w-]+$top-level dir, so it descends into.derivedDataand.claude(20–30K entry budgets), plus walks~/.autohand,~/.claude,~/.codexat depth 9.MCP
connectAll— 4 servers spawned in parallel at startup (uvx, npx, remote HTTP, xcrun); measured 0.15–4.2s each, plus zombie MCP processes from prior sessions.All of this is awaited before the first instruction (
performBackgroundInit→ensureInitComplete).Repro
Expected behavior
fff_find/find_grep/skills are actually used) or respect.gitignore.Suggested fixes
FILE_WALK_IGNORED_DIRECTORIESgitignore-aware (reuseGitIgnoreParser) or configurable..derivedData,.claude,.venv*,.opencode,.cache,.ruff_cache,.superpowers,.xcodebuildmcp,.test-batch-state,.worktrees.Local evidence (XXX repo)
find .= 5.5s).derivedData: 4.7 GB / 50,493 files.claude/worktrees: 2.4 GB / 121,588 files (6 worktrees).git: 839 MBwalkWorkspaceFiles(exact skip set): 231,337 files, 4.3sSteps to Reproduce
.
Expected Behavior
.
Actual Behavior
.
Autohand Version
0.9.7
Operating System
macOS (Apple Silicon)
OS Version
No response
Installation Method
curl install script
LLM Model (if applicable)
No response
Error Logs
Configuration (optional)
Checklist