Repository navigation
Unified workspace search on fff, content search, and a tabbed cmd+K palette - #856
Merged
Merged
Conversation
…ce-search-implementation # Conflicts: # Cargo.lock
…ce-search-implementation
…ch-fff # Conflicts: # crates/ui/src/shell/files_panel.rs
Engine - Drop content matches reached through a symlink, and name results through a symlinked folder (ReadWorkspaceFile's rule); fff's watcher follows links created after the first scan. - @ and file-tree name searches wait up to 2 s for a fresh index, since their answers can't report that it is still building. - Evict the LRU index only after its replacement is created, and report "indexing" (not a final empty answer) when an index is released mid-search. - File-name search accepts an empty query (not with "show ignored"), listing the workspace's files by the index's recency. - Home folder results are spelled from the session's home, not its canonical path, so a symlinked home doesn't duplicate projects. Palette - The Files tab and All's Recent Files list opened files, then the workspace's recency list, when there is no query. - Arrowing onto a section's first row scrolls its header into view. - Tabs use the shared tab chip; shortcut legends are plain sidebar-style text set in the system font (the UI font lacks ⇧ ↵); footer keys keep their caps, with icon glyphs for arrows and return. - Leaving for the PR board releases the new-project home index. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wingleeio
approved these changes
Oct 10, 2026
wingleeio
left a comment
Contributor
There was a problem hiding this comment.
Security-audited: the fff-search dependency tree is crates.io-only with no network/telemetry, and the new search RPCs resolve roots through the same chat/space entitlement as ReadWorkspaceFile. Pushed review fixes (8e53b29): symlink confinement for search results, safer index eviction, a longer first-scan wait for @/file-tree, the palette's default Files list, and palette polish. CI green. Thanks José!
hoangvu12
added a commit
to hoangvu12/roboco
that referenced
this pull request
Oct 11, 2026
…acklog window Source: .scratch/upstream-drift/2026-10-11.md. Tickets 01-18 actionable (quick ports, chips supersedes wave-6 03, the sidebar series 06-09, the older missed fixes 13-16, parity verification 17-18); 19 is the GPUI pin sync gating 20 (zeronsh#856) and 22 (zeronsh#813 Windows browser); 21 (zeronsh#484 PR board) PARKED on a product decision.
hoangvu12
added a commit
to hoangvu12/roboco
that referenced
this pull request
Oct 22, 2026
…me is never indexed Upstream 1bc74d5 (zeronsh#876): workspace search indexed the home folder for projectless chats, and fff's post-scan opens every file up to 10 MB to sniff binaries — downloading every OneDrive cloud-only file under home on Windows (iCloud/ File Provider on macOS). Two halves, one hygiene fix: - New projectless chats run in their own folder, <data dir>/scratch/<date>-<id> (~/.roboco/scratch/… for the default data dir), as t3code does under ~/.t3/scratch. The cwd is stored home-relative (proto::projectless: SCRATCH_ROOT, scratch_cwd, is_home_cwd/is_scratch_cwd/is_projectless_cwd); the host expands and CREATES the folder where the run spawns (sessions dispatch), the terminal opens (resolve_open_terminal_cwd + resolve_chat_cwd), and the file browser (workspace_files resolve_target). createChat and claim_chat mint the scratch folder (workspace_host new_projectless_cwd/hosts_scratch_folders — this engine always hosts them; a peer must advertise projectless-scratch-v1, now in capabilities and regenerated wire constants). Chats from before keep `~`, so their harness sessions still resume; runs from older clients that send `~` follow the chat's row (doc_host redirect after claim_chat). view::project_label/chat_location treat scratch cwds as "No project". - home_index.rs: names-only walk of the host's home for the chats that still run in `~` and the new-project folder search — cloud roots (OneDrive*, iCloud Drive, Dropbox, Google Drive, Box, …), machine folders (Library, AppData, Applications), hidden and dependency folders, and cloud placeholder folders are skipped; no content search there. Held for wave-7 ticket 20 (zeronsh#856 workspace search): the upstream workspace_search.rs hunks (+183) that CONSUME HomeIndex — roboco doesn't hold the file yet. home_index.rs ships with its tests and the shared name-search vocabulary (NameKinds/NameMatch/ normalize_name_query) defined locally, with an allow(dead_code) transitional note: ticket 20's port should unify them into workspace_search. Excluded upstream hunks: crates/client (cloud client library — roboco has no counterpart); crates/ui (composer/files/shell/state — UI lane); crates/mcp tools.rs (out of this engine ticket's scope — MCP-created chats send no cwd, so the engine's createChat/claim already mints the folder, and MCP runs send `~`, which the doc_host redirect follows); docs/performance-workspace-search.md (documents the workspace-search path roboco doesn't hold yet). The upstream device_routing relay test (+23) is adapted engine-locally as projectless_terminal_runs_in_the_chats_scratch_folder. Tests: projectless.rs reworked (CreateFirst/CommandFirst/Legacy modes, expected_cwd, terminal scratch resolution); workspace_files + rich_composer_delivery scratch assertions; proto projectless/view/ workspace suites; wiregen --check green (constants regenerated).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Workspace search had two unrelated engines, and neither scaled:
@mentions (SearchFiles) re-walked the whole checkout whenever its 10-second cache expired, then ranked withnucleo-matcher.SearchWorkspaceFiles) walked the disk on every keystroke: ~28 ms in this repo, 210–410 ms in a 28k-file monorepo.This PR puts all three surfaces on one engine-side index built on
fff-search(=0.11.0). The index is kept current by a file watcher and bounded in memory. On top of it, the cmd+K palette is redesigned with tabs and sections, and it can now search file names and file contents in the focused chat's workspace.@(SearchFiles)nucleo-matcherSearchWorkspaceFiles)SearchWorkspaceContentRPCSearchHomeFolders)SearchFilesandSearchWorkspaceFileskeep their wire shapes, so the iOS@gets the new ranking with no app changes.nucleo-matcheris removed.The cmd+K palette
Captured under Xvfb, so without the backdrop blur. The fixture has no engine, so it shows no file results.
Visual design is unchanged. It keeps the same card, rows, chat rows, highlight, fade and footer. The palette adds structure only:
mod-1…4switch tabs while the palette is open.Tab/Shift+Tabcycle them, and the palette always opens on All.mod-1…4are also the session jumps. The tab bindings live in aCommandPalettekey context, so they win only while the palette is open. With the palette closed,mod-2still jumps to session 2 (covered by GPUI tests).CommandPalette > PaletteSearchas well asCommandPalette.shell/thread_search.rs) is modeled on the mobile client's scorer:éor emoji.Engine:
WorkspaceSearchcrates/engine/src/workspace_search.rsholds one fff file picker per working folder: repository, worktree or plain folder. It is keyed by the canonical root thatWorkspaceFiles::resolve_targetreturns.fff options
SharedDb::noop()fff's own tracing and panic hooks are not installed.
New RPCs. All are forwardable through the relay, so remote chats search on their host.
WarmWorkspaceSearchbuilding/ready.SearchWorkspaceContentpath,line,column,preview, byteranges,truncatedandindexing. Default 100 matches, max 200, 3 per file; 2 s time budget.SearchHomeFoldersReleaseHomeFolderSearchContent queries are literal. The query goes through fff's raw-pattern API, which keeps whitespace,
!, and backslashes verbatim.Older hosts answer
UnknownMethod:Performance
Measured with
crates/engine/examples/workspace_search_bench.rs(release build, Linux x86_64, glibc). Medians.@(SearchFiles, 8 results)¹ The old
@index was a 10-second cache rebuilt by a full walk on expiry; these numbers are cache hits only.indexing.Full numbers and reproduction steps are in
docs/performance-workspace-search.md.Memory: how it scales
An index's memory is roughly proportional to the number of indexed paths. The first index also pays a one-time cost for fff's global search and scan thread pools. All figures are process RSS on Linux.
$HOME)Upper bound. At most 7 indexes, each with a content cache capped at 16 MB. The worst case is about seven indexes of your largest workspaces alive at once. For example, seven t3code-sized monorepos would be roughly 0.5 GB. Typical use (a few chats in one or two repos) stays in the tens of MB.
The residual after eviction is not an index that stayed alive.
malloc_trim(0)to hand freed pages back.How the index memory compares to before. The old
@cache was 3.6 MB for comet and 12 MB for t3code. But it was rebuilt by a full walk every 10 seconds, and the tree search had no index at all.Cleanup mechanisms and index lifecycle
Creation
WarmWorkspaceSearchonce when a chat gains focus. There is no heartbeat and no pinning, so refocusing a chat warms it again.@, the tree, the palette, or the home picker.While scanning
SCAN_WAIT= 300 ms, then answers from what is indexed and reportsindexing.WarmWorkspaceSearchas a readiness probe, becauseSearchWorkspaceFilesis list-shaped and has noindexingflag. Once a probe answersreadyfor that workspace, later keystrokes in the same palette session skip the probe, which saves a round trip per keystroke on remote hosts.Idle eviction
REAPER_INTERVAL= 60 s and drops indexes unused forIDLE_EVICT= 15 min, so an index lives 15–16 minutes after its last use.WorkspaceSearchis dropped.Capacity eviction
MAX_LIVE= 7 indexes are alive at once.Explicit release
ReleaseHomeFolderSearchdrops the home index when the new-project picker leaves Home or closes.What eviction does
malloc_trim(0).workspace search index evictedwith the reason (idle,capacity,released), file count and arena bytes.Creation and the end of the first scan are logged too, with root, files, scan time and arena bytes.
Freshness
.gitignore/.ignorechanges, or when a burst is too large to apply incrementally.UI-side state
Platform compatibility
notify9)ReadDirectoryChangesWmax_user_instances, often 128 per user, shared by every appmalloc_trimafter evictionLinux
Windows
\in a name or path query is treated as/when the host is Windows. On POSIX hosts a backslash stays a literal filename character.\\?\C:\…,\\?\UNC\server\share\…):dunce, only when that is lossless.NUL,COM1), trailing dots and long paths.c:=C:).fsutil setCaseSensitiveInfo./-separated relative paths everywhere, and canonicalizes base paths withdunce, so no\\?\prefix leaks into results.macOS
mod-1…4map to⌘1…4.Builds
fff-searchpulls C builds oflibgit2-sys,libz-sysandlmdb-master-sys. A C compiler is required on every platform; the existing macOS and Windows CI workflows cover this PR.notify 9.0.0-rccoexists with the engine'snotify 7.Behavior changes worth knowing
@query lists the chat's featured paths first, then recently changed files. It used to list the shallowest paths..gitis never indexed. "Show ignored" in the tree keeps a direct disk walk with a plain substring match.Known limitations / follow-ups
cafédoes not findCAFÉ. A workaround is to send the case variants of non-ASCII letters as extra patterns; this is also worth reporting upstream.is_watcher_ready()and rescan on the next search.FsWatchHuband the file tree's watcher. Feeding fff from the hub (watch: false+handle_create_or_modify/remove_file_by_path) would watch each folder once.mod-1…4precedence on macOS, Windows and Wayland. It is covered by GPUI tests on Linux.Testing
cargo check --workspace --all-targets --lockedpasses.cargo test -p zeron-engine --lib: 488 passed.device_routing(11),m5_repos_diffs_terminals(37) andworkspace_files(8) pass.device_routingexercisesSearchWorkspaceFiles,WarmWorkspaceSearchandSearchWorkspaceContentthrough the relay.cargo test -p zeron-proto -p zeron-rpcpasses.cargo test -p zeron-ui --lib: 1760/1762. The two failures are the pre-existing layout-dependent markdown tests, which are flaky under parallel load; all 106 markdown tests pass with--test-threads=1.New coverage
WorkspaceSearch: creation; directory-only search; the watcher picks up new files; idle and LRU eviction; a warmed index survives release; content search skips binaries and caps per file; blank queries.!and backslashes; smart case; UTF-8 byte ranges; query validation.mod-1…4versus session jumps;é, emoji, tabs and combining marks.Manual checks
Commits (37)
build: add fff-searchtest(engine): add a workspace search benchmarkfeat(engine): add WorkspaceSearch on top of ffffeat(engine): serve SearchFiles (@) from ffffeat(engine): serve SearchWorkspaceFiles (file tree) from fffchore: drop nucleo-matcherfeat(rpc): add WarmWorkspaceSearchtest(ui): add the missing images field to a ToolItem fixturefeat(ui): warm workspace search on chat focusfeat(rpc): add SearchWorkspaceContentfeat(ui): scored thread search for the command paletterefactor(ui): split the command palette into sections and tabsfeat(ui): command palette tabs with mod-1…4feat(ui): empty-state sections in the command palettefeat(ui): ranked thread search in the command palettefeat(ui): search file names from the command palettefeat(ui): search file contents from the command paletteperf(engine): return an evicted index's memory to the allocatorperf(engine): cap each search index's content cache at 16 MBdocs: workspace search on ffffeat(rpc): add SearchHomeFoldersfeat(ui): search folders under home when adding a projectperf(engine): index workspace paths only, grep contents without a bigram indexperf(engine): keep idle search indexes 15 min, up to 7, warmed once on focusfix(ui): refresh palette content search while indexingfix(engine): preserve literal workspace content queriesfix(ui): refresh palette file search while indexingfix(ui): refresh home folder search while indexingfix: handle extended Windows and UNC paths in home folder pickerfix(ui): convert content search byte columns for editor navigationfix(engine): normalize Windows separators in name searchesfix(ui): back off palette content refreshes while indexingperf(ui): skip the palette's index probe once the workspace is readyfix(ui): match Windows folder paths regardless of drive letter casedocs(ui): describe the home index release without pinsmain(Add a repository-scoped PR board and native inspection #484, Queue polish, and drag a chat from the sidebar to mention it #855)Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.