Skip to content

feat: expose follow_symlinks for SDK/MCP/python paths#628

Merged
dmtrKovalenko merged 2 commits into
mainfrom
triage-bot/issue-627
Jun 26, 2026
Merged

feat: expose follow_symlinks for SDK/MCP/python paths#628
dmtrKovalenko merged 2 commits into
mainfrom
triage-bot/issue-627

Conversation

@gustav-fff

@gustav-fff gustav-fff commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Closes #627

Root cause

follow_symlinks was hardcoded to false on every non-nvim entry point: crates/fff-c/src/lib.rs:295 and :1047, crates/fff-mcp/src/main.rs:265, crates/fff-python/src/finder.rs:246 and :775. Reporter's stowed config layout (~/.pi/agent~/.dotfiles/...) is invisible to fff-node / fff-mcp / fff-python because of this.

Fix

  • Bump FFF_CREATE_OPTIONS_VERSION to 2 and append follow_symlinks: bool to FffCreateOptions (append-only, ABI layout test extended to assert the new offset 82). Old v1 callers continue to work — when opts.version < 2 the field is ignored and follow_symlinks defaults to false.
  • fff-mcp: add --follow-symlinks CLI flag.
  • fff-python: add follow_symlinks=False kwarg to FileFinder.__init__; preserved across reindex.
  • @ff-labs/fff-node: add followSymlinks?: boolean to InitOptions, threaded through ffiCreate and the FFI struct.
  • fff-c: preserve follow_symlinks across fff_change_directory (was being dropped to false).
  • Regenerate crates/fff-c/include/fff.h via cbindgen.

Default stays false everywhere. Watcher cycle detection is unchanged — caller is responsible for ensuring the indexed tree has no symlink loops. Documented in the option doc comments.

Steps to reproduce

# python
cd crates/fff-python && maturin develop --release
python -c "
import fff_python, tempfile, os, pathlib
src = tempfile.mkdtemp(); link = tempfile.mkdtemp()
pathlib.Path(src, 'real.txt').write_text('hi')
os.symlink(src, os.path.join(link, 'linked'))
f = fff_python.FileFinder(link, follow_symlinks=True)
f.wait_for_scan_blocking(5000)
print([r.relative_path for r in f.search('real').items])
"
# expected: ['linked/real.txt']  (without follow_symlinks=True: [])

# mcp
cargo run -p fff-mcp -- --follow-symlinks /path/to/stowed/tree

# node
const { FileFinder } = require('@ff-labs/fff-node')
FileFinder.create({ basePath: '/stowed/tree', followSymlinks: true })

How verified

  • cargo test -p fff-c — 9 passed including the ABI layout test (size_of == 88, new field at offset 82).
  • cargo build -p fff-c -p fff-mcp -p fff-python — clean.

Holding on watcher loop guards per maintainer call — flag exposure only as discussed in #627.

Automated triage via Gustav. Honk-Honk 🪿

@dmtrKovalenko

Copy link
Copy Markdown
Owner

@gustav-fff fix the issues and triple check if it doesn't create ABI compatibiltiy issue

@gustav-fff

Copy link
Copy Markdown
Collaborator Author

[triage-bot] DIRECTED: pushed 54bc368.

ABI issue found and fixed: fff_create_instance_with was reading opts.follow_symlinks unconditionally. For v1 callers the byte at offset 82 lives in what was previously trailing padding and is uninitialized — reading it as bool is UB and could silently enable symlink-following. Now gated on opts.version >= 2.

Triple-checked the rest:

  • Struct size unchanged at 88, alignment 8, all prior offsets stable. cargo test -p fff-c options_layout green.
  • fff_create_instance2 (deprecated) builds opts via defaults() which sets version = FFF_CREATE_OPTIONS_VERSION and follow_symlinks = false — fine.
  • fff_create_instance_with_value delegates to the pointer variant, picks up the same gate.
  • fff_restart_index sources follow_symlinks from the live picker (follows_symlinks()), defaults to false when no picker — no uninit read.
  • No public symbol signatures changed; no field reorders; v2 is purely an append.

Honk-Honk 🪿

Closes #627

Bumps FFF_CREATE_OPTIONS_VERSION to 2 (append-only).
Adds --follow-symlinks flag to fff-mcp, follow_symlinks kwarg to the
pyo3 finder, and followSymlinks option to @ff-labs/fff-node. Default
stays false everywhere; follow_symlinks is preserved across reindex
in C and Python.

Watcher cycle handling is unchanged — caller must ensure the indexed
tree has no symlink loops.
@dmtrKovalenko dmtrKovalenko force-pushed the triage-bot/issue-627 branch from 54bc368 to 39c05f2 Compare June 22, 2026 23:59
@gustav-fff gustav-fff changed the title feat: expose follow_symlinks in SDK/MCP/Python paths feat: expose follow_symlinks for SDK/MCP/python paths Jun 23, 2026
@dmtrKovalenko dmtrKovalenko merged commit 03e1a1a into main Jun 26, 2026
51 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Suggestion]: Expose follow_symlinks for agent/SDK search paths

2 participants