Repository navigation
Description
Description
OpenCode V2's FFF index fails to honor valid anchored, directory-only wildcard rules such as **/target/ from a repository's root .gitignore.
Git correctly excludes matching paths, but OpenCode/FFF still indexes and returns them from /api/fs/find. On Linux, FFF consequently registers inotify watches throughout the excluded tree, causing unnecessary watch and memory usage.
Expected: Files and directories matching **/target/ are absent from FFF search results and are not watched.
Actual: In one reproduction, FFF indexed at least 11,160 files and 864 directories under rust/target. The server's FFF inotify descriptor contained 1,164 directory watches, including 867 under that excluded tree.
OpenCode currently pins both FFF packages to 0.10.1:
opencode/packages/core/package.json
Lines 116 to 117 in b3d6063
| "@ff-labs/fff-bun": "0.10.1", | |
| "@ff-labs/fff-node": "0.10.1", |
FFF is initialized for eligible Git-backed locations with content indexing disabled and live watching left enabled:
opencode/packages/core/src/filesystem/search.ts
Lines 112 to 134 in b3d6063
| export const fffLayer = Layer.effect( | |
| Service, | |
| Effect.gen(function* () { | |
| const location = yield* Location.Service | |
| const result = yield* Effect.try({ | |
| try: () => | |
| Fff.create({ | |
| basePath: location.directory, | |
| aiMode: true, | |
| disableMmapCache: true, | |
| disableContentIndexing: true, | |
| }), | |
| catch: (cause) => cause, | |
| }).pipe( | |
| Effect.catch((error) => Effect.logWarning("failed to initialize fff", { error }).pipe(Effect.as(undefined))), | |
| ) | |
| if (!result?.ok) { | |
| if (result) yield* Effect.logWarning("failed to initialize fff", { error: result.error }) | |
| return Service.of({ | |
| find: () => Effect.succeed([]), | |
| }) | |
| } | |
| yield* Effect.addFinalizer(() => Effect.sync(() => result.value.destroy()).pipe(Effect.ignore)) |
opencode/packages/core/src/filesystem/search.ts
Lines 180 to 188 in b3d6063
| export const layer = (options?: Options) => | |
| Layer.unwrap( | |
| Effect.gen(function* () { | |
| if (options?.fff === false || (options?.fff === undefined && process.platform === "win32") || !Fff.available()) | |
| return ripgrepLayer | |
| const location = yield* Location.Service | |
| // Non-VCS locations can contain many repositories, so avoid eagerly content-indexing the entire aggregate tree. | |
| return location.vcs && !Protected.isHome(location.directory) ? fffLayer : ripgrepLayer | |
| }), |
Root cause: FFF 0.10.1 uses zlob 1.6.1. Its fast matcher treats the anchored, directory-only **/target/ pattern as a literal prefix comparison and returns before wildcard segment matching. zlob 1.6.2 fixes this, and FFF 0.10.3 is the first stable FFF release containing that upgrade. FFF 0.10.4 and 0.10.5 retain the fix.
- [Bug]: .gitignore regression in 0.10.x dmtrKovalenko/fff#723
- fix: Ignore compatiblitiy issues with git dmtrKovalenko/zlob#26
- fix: Gitignore incompatbility dmtrKovalenko/fff#744
FFF PR #742 concerns separate global/info-exclude parity work and is not the cause of this root .gitignore failure.
Proposed resolution: Upgrade @ff-labs/fff-bun and @ff-labs/fff-node together to at least 0.10.3, preferably the selected current stable compatible release. Add a regression test proving nested files and directories matching **/target/ are absent from FFF results, and verify that a fresh V2 server does not watch the excluded tree. The upstream release lineage is established, but the upgrade has not yet been smoke-tested in OpenCode.
Workaround: OPENCODE_DISABLE_FFF=1 selects ripgrep behavior, but loses FFF incremental search performance. Post-filtering results would not remove the underlying scanning, index memory, or watch overhead.
Plugins
None required.
OpenCode version
V2 at commit b3d60633293d14310084dbb9abd919c1243319ba.
Steps to reproduce
-
On Linux, create or use a Git repository containing a nested
targetdirectory, such asrust/target/debug/deps. -
Add this rule to the root
.gitignore:**/target/
-
Confirm Git applies the rule:
git check-ignore -v rust/target rust/target/debug rust/target/debug/deps
-
Launch OpenCode V2 with
--standalone. This is only to isolate the server process being measured. -
Query that server's
/api/fs/findendpoint for paths beneathrust/target. -
Observe that excluded files and directories are returned.
-
Inspect the server's inotify descriptor and observe watches beneath
rust/target.
Screenshot and/or share link
Not applicable. This is reproducible through filesystem search results and the server's inotify descriptors.
Operating System
Linux.
Terminal
Terminal-independent.
Activity
github-actions commentedon Aug 21, 2026
This issue might be a duplicate of existing issues. Please check:
watcher.ignorenot reaching the fff engine; shares the symptom of excessive watches under gitignored trees, though the root cause there is that embedder-supplied ignore patterns never reach fff at all, rather than a pattern-matching bug in zlob..gitignoreis silently dropped in Jujutsu workspaces (no.git); same family of fff gitignore-bypass bugs but a different mechanism.These are distinct bugs with different root causes, so this issue may still warrant its own fix (upgrading fff to pick up the zlob 1.6.2 fix), but the linked issues share context and the inotify watch overhead symptom.
altendky commentedon Aug 21, 2026
i just verified the excessive watches are gone. thanks!