본문으로 건너뛰기

© 2026 Molayo

GH Trending릴리즈2026. 06. 02. 00:21

dmtrKovalenko/fff: 인간과 AI 에이전트를 위한 초고속 파일 검색 툴킷

요약

인간과 AI 에이전트를 위한 초고속 파일 검색 툴킷인 fff를 소개합니다. Frecency 기반 검색, 오타 교정, Git 인식 기능을 통해 Claude Code, Cursor 등 MCP 지원 클라이언트에서 더 빠르고 효율적인 파일 탐색을 지원합니다.

핵심 포인트

  • Frecency 기반의 파일 액세스 및 빈도-최신성 메모리 지원
  • Claude Code, Cursor 등 MCP 지원 클라이언트와 완벽 호환
  • Rust 기반의 빠른 검색 및 토큰 효율적인 컨텍스트 관리
  • Git 상태(수정됨, 추적 안 됨 등)를 인식하는 스마트 어노테이션 제공

인간과 AI 에이전트를 위한 파일 검색 툴킷. 정말 빠릅니다.

오타에 강한 경로 및 내용 검색, 빈도-최신성 (frecency) 기반 파일 액세스, 백그라운드 감시자(watcher), 그리고 가벼운 인메모리 (in-memory) 내용 인덱스를 제공합니다. 한 번 이상 검색을 수행하는 모든 장기 실행 프로세스에서 ripgrep이나 fzf와 같은 CLI보다 훨씬 빠릅니다.

원래는 사람들이 좋아하는 Neovim 플러그인으로 시작되었으나, 수많은 AI 하네스 (harnesses)와 코드 에디터들이 라이브러리로서 정확하고 빠른 파일 검색을 필요로 한다는 것이 밝혀졌습니다. 그것이 바로 fff입니다.

관심 있는 항목을 선택하세요:

Claude Code, Codex, OpenCode, Cursor, Cline 및 모든 MCP 지원 클라이언트와 함께 작동합니다. grep 왕복 횟수가 줄어들고, 낭비되는 컨텍스트가 감소하며, 더 빠른 답변을 얻을 수 있습니다.

Linux / macOS:

curl -L https://dmtrkovalenko.dev/install-fff-mcp.sh | bash

Windows (PowerShell):

irm https://raw.githubusercontent.com/dmtrKovalenko/fff.nvim/main/install-mcp.ps1 | iex

스크립트를 먼저 읽어보고 싶다면 install-mcp.shinstall-mcp.ps1에 위치해 있습니다.

사용 중인 클라이언트를 위한 정확한 연결 지침을 출력합니다. 서버가 연결되면 에이전트에게 "fff를 사용해줘"라고 요청하세요. 그러면 에이전트가 ffgrep, fffind, fff-multi-grep 도구를 가져옵니다.

프로젝트의 CLAUDE.md 또는 그에 상응하는 파일에 다음 내용을 추가하세요:

현재 git 인덱스된 디렉토리 내의 모든 파일 검색 또는 grep 작업에는 fff 도구를 사용하라.

  • 빈도-최신성 (Frecency) 메모리: 실제로 여는 파일이 다음번에 더 높은 순위로 나타납니다. git touch 히스토리를 통한 워밍업 (warm-up)이 자동으로 실행됩니다.
  • 정의 우선 힌팅 (Definition-first hinting): 코드 정의처럼 보이는 라인들은 Rust 측에서 분류되므로, 프롬프트 내에서 정규 표현식 (regex) 오버헤드가 발생하지 않습니다.
  • 자동 퍼지 (fuzzy) 폴백이 포함된 스마트 케이스 (Smart-case): IsOffTheRecord는 snake_case 변형을 찾아냅니다. 일치하는 결과가 없는 쿼리는 퍼지 검색으로 재시도하여 가장 근사한 검색 결과를 보여줍니다.
  • Git 인식 어노테이션 (Git-aware annotations): 수정됨 (modified), 추적되지 않음 (untracked), 스테이징됨 (staged) 파일에 태그가 붙어 에이전트가 사용자가 활발히 변경 중인 파일에 접근할 수 있게 합니다.

소스: crates/fff-mcp/.

MCP 서버는 모든 에이전트에게 내장된 도구보다 더 빠르고 토큰 효율적인 파일 검색 도구를 제공합니다.

pi install npm:@ff-labs/pi-fff

세 가지 동작 모드가 있으며, /fff-mode를 통해 런타임에 전환할 수 있습니다.

모드기능
tools-and-ui (기본값)ffgrepfffind 도구를 추가하고, @ 멘션 자동 완성(autocomplete)을 FFF로 교체합니다.
tools-only도구 주입(tool injection)만 수행합니다. pi의 기본 에디터 자동 완성을 유지합니다.
overridepi의 내장 grep, find, multi_grep을 FFF 구현체로 교체합니다.

환경 변수(Env vars): PI_FFF_MODE, FFF_FRECENCY_DB, FFF_HISTORY_DB. 플래그(Flags): --fff-mode, --fff-frecency-db, --fff-history-db.

ffgrep. 콘텐츠 검색. path, exclude (쉼표, 공백 또는 배열; 앞부분에 ! 선택적 사용), caseSensitive, context 및 커서 페이지네이션(cursor pagination)을 지원합니다. 정규 표현식(regex)을 자동 감지하며, 정확한 일치 항목이 없을 경우 퍼지(fuzzy) 검색으로 전환합니다. .* 스타일의 와일드카드 전용 패턴은 사전에 거부합니다. fffind. 경로 및 파일명 검색. 파일명뿐만 아니라 저장소 상대 경로 전체를 매칭합니다. 빈도-최신성(Frecency)을 인식합니다. 약한 매칭 감지기(weak-match detector)는 에이전트의 컨텍스트를 압도하기 전에 흩어져 있는 퍼지 노이즈를 표시합니다.

/fff-mode [tools-and-ui | tools-only | override]. 모드를 표시하거나 전환합니다. /fff-health. 피커(Picker), 빈도-최신성(frecency), Git 통합 상태를 표시합니다. /fff-rescan. 강제로 재스캔(rescan)을 수행합니다.

소스: packages/pi-fff/.

Pi 확장 프로그램은 pi의 기본 도구를 FFF 구현체로 교체하고, 대화형 에디터의 @ 멘션 자동 완성을 빈도-최신성 순위가 매겨진 인덱스로부터 제공합니다.

Linux 커널 저장소(파일 10만 개, 8GB) 데모:

fff_nvim_demo.mp4

{
'dmtrKovalenko/fff.nvim',
build = function()
...
vim.pack.add({ 'https://github.com/dmtrKovalenko/fff.nvim' })
vim.api.nvim_create_autocmd('PackChanged', {
callback = function(ev)
...
require('fff').find_files() -- 현재 저장소에서 파일 찾기
require('fff').live_grep() -- 실시간 콘텐츠 grep
require('fff').scan_files() -- 강제 재스캔
...

구조화된 결과 { items, scores, total_matched, total_files?, total_dirs?, location? }를 반환합니다. 각 항목은 type 필드("file" 또는 "directory")를 가집니다.

) and name

/ relative_path

. 파일 항목은 또한 size,
modified,
git_status,
is_binary
및 frecency 점수를 노출합니다.

local r = require('fff').file_search('button', {
mode = 'mixed', -- 'files' (기본값) | 'directories' | 'mixed'
max_results = 50,
...

GrepResult를 반환합니다.
{ items, total_matched, total_files_searched, total_files, filtered_file_count, next_file_offset, regex_fallback_error? }

. 각 매치 항목은 relative_path,
name,
line_number,
col,
line_content,
match_ranges
file_search와 동일한 파일 메타데이터를 가집니다.

local r = require('fff').content_search('TODO', {
mode = 'plain', -- 'plain' (기본값) | 'regex' | 'fuzzy'
max_file_size = 10 * 1024 * 1024,
...

두 함수 모두 UI 피커와 동일한 제약 조건 구문(예: git:modified,
*.rs,
!test/,
glob 패턴)을 허용합니다.

file_searchcontent_search 둘 다 선택적 cwd 필드를 존중합니다. 두 함수 중 첫 번째 호출은 피커를 config.base_path (기본값인 Neovim의 cwd)에서 지연 초기화합니다.

  • 만약 cwd가 현재 인덱싱된 루트와 일치하면, 해당 호출은 기존 인덱스를 대상으로 즉시 반환됩니다.
  • 만약 cwd가 다르면, 피커는 새 루트에서 재인덱싱되고 호출은 새로운 피커가 설치되고 초기 스캔이 완료될 때까지 차단(기본값 최대 10초)됩니다. — 따라서 호출자는 항상 올바른 트리로부터 결과를 얻습니다.
  • 만약 change_indexing_directory 이후에도 인덱스가 아직 워밍업 중이라면, cwd가 스왑을 유발했는지 여부와 관계없이 최대 Nms 동안 차단하려면 wait_for_index_ms = N을 전달할 수 있습니다. 부분 결과가 허용되는 fire-and-forget 호출에는 완전히 기다리는 것을 건너뛰려면 0을 전달하세요. - 유효하지 않거나 존재하지 않는 cwd 경로는 빈 결과를 반환하고 vim.notify를 통해 오류를 발생시킵니다.

:FFFScan
. 파일을 재스캔합니다.:FFFRefreshGit
. git 상태를 새로 고칩니다.:FFFClearCache [all|frecency|files]
. 캐시를 지웁니다.:FFFHealth
. 상태 확인(Health check)을 수행합니다.:FFFDebug [on|off|toggle]

. 점수 표시를 토글합니다.:FFFOpenLog

. ~/.local/state/nvim/log/fff.log를 엽니다.

.

기본 설정은 합리적입니다. 필요한 부분만 재정의(Override)하세요.

require('fff').setup({
base_path = vim.fn.getcwd(),
prompt = '> ',
...

<S-Tab>

plain, regex, fuzzy 사이를 순환합니다. 목록은 grep.modes를 통해 구성할 수 있으며, 단일 모드 설정 시 인디케이터(indicator)가 완전히 숨겨집니다.

호출 시 재정의(Per-call override):

require('fff').live_grep({ grep = { modes = { 'fuzzy', 'plain' } } })
require('fff').live_grep({ query = 'search term' }) -- 미리 채우기(pre-fill)

findgrep 모두 쿼리를 정교화하기 위해 다음 토큰을 허용합니다:

git:modified

modified, staged, deleted, renamed, untracked, ignored 중 하나.

test/

test/의 모든 깊게 중첩된 하위 항목.

!something, !test/, !git:modified

제외(Exclusion).

./**/*.{rs,lua}

zlob을 기반으로 하는 모든 유효한 glob.

Grep 전용:

*.md, *.{c,h}

확장자 필터(Extension filter).

src/main.rs

단일 파일 내부에서 grep 수행.

자유롭게 혼합 가능: git:modified src/**/*.rs !src/**/mod.rs user controller

.

<Tab>

선택 토글 (signcolumn에 두꺼운 표시).

<C-q>

선택된 파일들을 quickfix list로 보내고 피커(picker)를 닫습니다.

Sign-column 인디케이터는 기본적으로 켜져 있습니다. Git 상태에 따라 파일명 텍스트 색상을 지정하려면 git.status_text_color = true로 설정하고 hl.git_* 그룹을 조정하세요. 전체 목록은 :help fff.nvim을 참조하세요.

피커는 플로팅(float) 콘텐츠를 NormalFloat(hl.normal을 통해)로, 테두리를 FloatBorder로 매핑합니다. 기본 FloatBorderNormalFloat에 링크되어 있으므로, 테두리와 콘텐츠가 즉시 배경을 공유하며 피커가 하나의 팝업처럼 읽힙니다. 대신 피커를 에디터와 조화시키려면 hl.normal = 'Normal'로 재정의하세요.

더 세밀한 제어를 위해 hl.winhl을 설정하여 창별 winhighlight를 재정의할 수 있습니다. 이는 모든 피커 창에 적용되는 단일 문자열 또는 prompt, list, preview, file_info 키를 포함하는 테이블을 모두 허용합니다. 누락된 키는 hl.normal로 생성된 기본값을 사용합니다.

, hl.border,

hl.title.

-- 모든 피커(picker) 윈도우에 동일한 winhighlight 적용
hl = { winhl = 'Normal:NormalFloat,FloatBorder:FloatBorder,FloatTitle:Title' }
-- 또는 특정 윈도우만 오버라이드
...

debug.enabled = true를 통해 활성화할 수 있습니다. 패널은 미리보기(preview) 위에 위치하며 파일 메타데이터(metadata), 점수 내역(score breakdown), 타임스탬프(timestamps) 및 전체 절대 경로(full absolute path)를 보여줍니다. 패널 너비에 따라 적응합니다. 너비가 좁을 때는 섹션이 수직으로 쌓이며 (B2), 너비가 넓을 때는 섹션이 2열 그리드(H2)로 렌더링됩니다. 각 섹션은 debug.show_file_info를 통해 개별적으로 비활성화할 수 있습니다.

hl을 통해 패널을 커스텀할 수 있습니다:

키 (key)기본값 (default)용도 (used for)
file_info_sectionTitle섹션 헤더 레이블
file_info_separatorFloatBorder섹션 경계 역할을 하는 대시(dashes)
file_info_labelComment행 레이블 (Size, Type, Git, ...)
file_info_valueNormal fg일반 값
file_info_value_dimNonText흐릿한 값(dim values), 행 내부의 구분자
file_info_sizeNumber파일 크기 값
file_info_typeType파일 유형 값
file_info_pathDirectory전체 경로
file_info_total_scorebold + Number총점 (굵게)
file_info_match_typebold + Special매칭 유형 (굵게)
file_info_score_posDiagnosticOk양수 점수 요소
file_info_score_negDiagnosticError음수 점수 요소

FFF는 .gitignore를 준수합니다. Git에 영향을 주지 않는 피커 전용 무시(ignore) 설정을 원한다면, 형제 파일인 .ignore 파일을 추가하세요:

*.md
docs/archive/**/*.md

강제 재스캔을 하려면 :FFFScan을 실행하세요.

:FFFHealth는 피커 초기화, 선택적 의존성(optional dependencies), 그리고 DB 연결 상태를 확인합니다. :FFFOpenLog는 로그 파일을 엽니다.

Neovim을 위한 최고의 파일 검색 피커입니다. 마침표. 더 빠르고 직관적인 쿼리(queries), 빈도-최신성 순위(frecency ranking), 정의 분류(definition classification) 및 훨씬 더 많은 기능을 제공합니다.

npm install @ff-labs/fff-node
# 또는
bun add @ff-labs/fff-node
import { FileFinder } from "@ff-labs/fff-node";
const finder = FileFinder.create({ basePath: process.cwd(), aiMode: true });
if (!finder.ok) throw new Error(finder.error);
...

모든 메서드는 Result<T>를 반환합니다.

({ ok: true, value } | { ok: false, error })

전체 타입 참조: packages/fff-node/src/types.ts.

Node.js 및 Bun을 위한 C 라이브러리의 TypeScript 래퍼 (wrapper)입니다. FFF를 기반으로 커스텀 에이전트 도구, CLI, 또는 IDE 통합 기능을 구축하세요.

FFF는 Rust로 작성되었으므로, 이것이 이를 사용하는 가장 오버헤드가 적은 방법입니다.

[dependencies]
fff-search = "0.6"

전체 API 문서: docs.rs/fff-search.

모든 검색을 수행하는 네이티브 Rust 크레이트 (crate)입니다. 안정적이며 문서화가 잘 되어 있습니다.

# C cdylib만 빌드 (가장 빠름):
make build-c-lib
# 또는 cargo로 직접 빌드:
...

출력물은 cdylib (libfff_c.so / libfff_c.dylib / fff_c.dll)입니다. 헤더 파일은 crates/fff-c/include/fff.h에 위치합니다.

main 브랜치의 모든 커밋을 포함하여 모든 버전에 대한 사전 빌드된 바이너리 (Prebuilt binaries)가 릴리스 (releases) 페이지에 있습니다. 동일한 바이너리가 @ff-labs/fff-bin-* npm 패키지 내부에도 포함되어 제공됩니다.

# 시스템 전체 설치 (sudo 필요):
sudo make install
# 사용자 로컬 설치, sudo 불필요:
...

libfff_c.{so,dylib,dll}$(PREFIX)/lib에, 헤더를 $(PREFIX)/include/fff.h에 배치합니다. 동일한 PREFIXDESTDIR을 준수하는 make uninstall로 제거할 수 있습니다.

설치 후 다음과 같이 링크하세요:

cc my_app.c -lfff_c -o my_app

$(PREFIX)/lib가 런타임 라이브러리 검색 경로에 있는지 확인하세요 (Linux의 경우 LD_LIBRARY_PATH, macOS의 경우 DYLD_LIBRARY_PATH, 또는 /etc/ld.so.conf.d/ 내의 항목).

#include <fff.h>
#include <stdio.h>
int main(void) {
...
  • FffResult*를 반환하는 모든 함수는 Rust의 Box를 사용하여 할당합니다. fff_free_result로 해제해야 하며, mallocfree를 사용하지 마세요. 페이로드 (Payloads, 검색 결과, grep 결과, 스캔 진행 상황)는 헤더에 나열된 전용 해제 함수를 별도로 가지고 있습니다.
  • handle 필드(예: fff_get_base_path로부터 반환됨)에서 반환되는 C 문자열은...

)는 fff_free_string을 통해 해제됩니다.

소스: crates/fff-c/

안정적인 C ABI. C/C++, Zig, cgo를 통한 Go, ctypes를 통한 Python, 또는 C FFI를 지원하는 무엇이든 통해 바인딩할 수 있습니다.

FFF는 파일 검색 라이브러리이며, CLI(Command Line Interface)가 아닙니다. Ripgrep과 fzf는 훌륭한 도구들이지만, 이들은 명령줄 프로그램입니다. 즉, 호출할 때마다 새로운 프로세스를 포크(fork)하고, .gitignore를 다시 읽고, 디렉토리 상태를 다시 확인(re-stats)하며, 답변을 내놓기 전에 메모리에 필요한 모든 상태를 다시 구축해야 합니다. 쉘(shell)에서 한 번씩 grep을 수행할 때는 문제가 되지 않습니다. 하지만 에디터나 AI 에이전트가 세션당 수백 번의 검색을 수행하고자 할 때는 문제가 됩니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 GitHub Trending All (daily)의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0