Repository navigation
Description
Summary
When running opencode serve as a long-lived process whose working directory is $HOME, CPU climbs to ~1047% (≈10.5 cores) and stays high for 45+ minutes without converging. CPU sampling shows 100% of the load is the bundled fff file-search/index engine (@ff-labs/fff-bun) doing full-tree directory walks + per-file content indexing over the entire home directory — not just the project directory — because fffLayer enables enableHomeDirScanning + enableFsRootScanning. Setting OPENCODE_DISABLE_FFF=1 is a confirmed workaround.
Related issues: #31831 (same symptom — sustained high CPU on macOS ARM — but no root-cause), #31682 (closed; same fff+home root cause, but manifested as fff scan timed out crash rather than sustained CPU), #27082 / #27071 (earlier "large $HOME" analyses), #30086 (general high-CPU regression thread). This report adds the missing piece: a CPU sample stack + lsof that pin the load to fff content-indexing of $HOME, with the exact source location.
Environment
| opencode | 1.17.7 (Homebrew) |
| source commit | 5d0f86606 (dev) — fix(mcp): stop idle OAuth callback server (#32245) |
@ff-labs/fff-bun |
0.9.4 (with patch @ff-labs/[email protected]) |
| Bun | 1.3.14 |
| Node | v26.3.0 |
| OS | macOS 26.5.1 (25F80), Darwin 25.5.0 / xnu-12377.121.6 |
| Hardware | MacBook Pro (Mac17,9), Apple M5 Pro, 15 cores, 48 GB RAM, arm64 |
| Command | opencode serve --hostname 0.0.0.0 --port 4096 (launchd, WorkingDirectory = /Users/<me>) |
Observed behavior
- CPU peaks at 1047%, oscillating 56%–1047% in a "scan a round, pause, scan again" pattern.
- Physical memory footprint 3.3 GB and growing (RSS 1.4G → 1.8G during observation).
- Runs 45+ min with no convergence; process stays
R(running).
CPU time series:
13:46:18 1047.3% <- peak
13:46:19 1045.0%
13:46:21 955.8%
13:46:25 372.5%
Root cause
1. CPU sample (30s) — load is entirely fff scan/index threads
Hot functions, all in fff's Rust scan/index threads (fff-scan, fff-bg-0..14):
428 fff_search::bigram_filter::BigramIndexBuilder::add_file_content (reads each file's content -> bigram index)
76 fff_search::file_picker::FileSync::walk_filesystem (full-tree walk)
28 fff_search::scan::ScanJob::run
22 fff_search::types::FileItem::detect_binary_per_byte (per-byte binary detection)
14 fff_search::background_watcher::handle_debounced_events
5 fff_search::scan::rescubscribe_watcher_post_scan (re-subscribe watcher after scan)
Representative stack:
fff_search::scan::ScanJob::run
-> ignore::walk::WalkParallel::visit (rayon parallel dir walk)
-> openat / read / close (open each file)
-> fff_search::bigram_filter::BigramIndexBuilder::add_file_content
2. lsof proves the scan scope is the whole user directory (not the project)
102 directory handles, including paths far outside any project:
/Users/<me> (home)
/Users (parent of home, toward fs root)
/Users/<me>/.local
/Users/<me>/Library
/Users/<me>/Downloads
/Users/<me>/Library/Android/sdk/.../drawable/*.xml (even Android SDK assets)
3. Source location
packages/core/src/filesystem/search.ts (fffLayer):
Fff.create({
basePath: location.directory,
aiMode: true,
enableFsRootScanning: true, // <-- scans toward filesystem root
enableHomeDirScanning: true, // <-- scans the entire home directory
})Note: the project's own benchmark packages/opencode/script/bench-search.ts creates the picker without these flags (Fff.create({ basePath: dir, aiMode: true })). So the fast numbers measured during development reflect project-scoped scanning, while the production fffLayer enables full home/root scanning. For a long-lived serve process — especially one whose WorkingDirectory is $HOME — this turns "index the project" into "full-content-index the entire home directory" (bigram index + per-byte binary detection over node_modules, caches, SDKs…), saturating all cores and producing multi-GB index memory.
4. Watcher duplication (amplifier — flagged as a hypothesis)
The sample shows 6 concurrent watcher thread groups:
fff-watcher-own x6
notify-rs fsevents loop x6
notify-rs debouncer loop x6
Combined with rescubscribe_watcher_post_scan (re-subscribe after each scan) and a session that opened several projects over time, each scanned root appears to spawn its own fsevents watcher and re-subscribe after each scan. I have not confirmed a definitive leak, but the duplication is consistent with one.
Reproduction
- Run
opencode servewithWorkingDirectory/cwd set to$HOME(or simply run from a home directory that contains many files — node_modules, SDKs, caches). - Leave it running.
- Observe CPU climb to several hundred–thousand percent.
sample <pid>showsfff_search::scan/BigramIndexBuilder::add_file_content;lsof <pid>shows directory handles all over$HOME.
Workaround (confirmed)
OPENCODE_DISABLE_FFF=1 opencode serve ...Routes through ripgrepLayer (see search.ts defaultLayer and flag.ts OPENCODE_DISABLE_FFF) and skips full content indexing. Search still works (falls back to ripgrep), losing only fff's frecency/realtime features.
Suggested fix
For the serve path, set enableFsRootScanning / enableHomeDirScanning to false so fff only indexes location.directory. If home/root scanning backs a real feature (cross-project navigation, frecency history), bound it instead — exclusion rules, scan throttling, or lazy/on-demand triggering — and ensure watchers are deduplicated and torn down per project. A guard against location.directory === os.homedir() would also prevent the worst case.
I have full sample output (10s + 30s), lsof, vmmap, the CPU time series, and server logs captured locally and can attach any of them on request.
Activity
github-actions commentedon Jun 16, 2026
This issue might be a duplicate of existing issues. Please check:
If your issue is distinct (specifically the fff
enableHomeDirScanning/enableFsRootScanningroot cause when CWD is $HOME), it may still be worth keeping open as a separate actionable report with the specific source location and fix suggestion. Please cross-reference these threads so maintainers can triage effectively.opencode: disable fff in systemd unit
vcode11 commentedon Jul 15, 2026
+1 disabled fff with OPENCODE_DISABLE_FFF=1
jjangga0214 commentedon Aug 22, 2026
Additional reproduction/data point on the current release.
Environment:
Observed behavior:
Potentially important home-scan amplifier:
I do not have a preserved CPU profile from the transient idle spike yet, and have not yet compared the same workload with OPENCODE_DISABLE_FFF=1. I will capture a macOS sample and run that A/B test if it reproduces.
neriousy commentedon Oct 19, 2026
This is fixed in v2: home directories and non-VCS locations use ripgrep instead of fff, so starting OpenCode in your home directory no longer triggers fff content-indexing of that tree. The fallback scan is capped at 100,000 entries and excludes protected home-directory folders. To upgrade, run
npm i -g @opencode/cli@latest. If you still see this on v2, please open a new issue with the details.