record D-79: workspace content search is pure-Dart, outside pql

Find-in-files / replace (T-52/T-53) run as an in-process isolate-pool
grep engine behind an engine-agnostic search.grep verb — not pql (its
search is a ranked document index, with no line numbers, regex, or
glob) and not a ripgrep shell-out (unvendored, not guaranteed
cross-platform). ripgrep is kept as a future optional accelerator
behind the same verb. Clarifies the D-3 wrap-pql boundary: content
grep is a code-navigation primitive pql does not offer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 20:08:25 +02:00
co-authored by Claude Opus 4.8
parent b6eef3fc2b
commit 7e76455775
5 changed files with 115 additions and 0 deletions
+1
View File
@@ -120,6 +120,7 @@ You might also want, project-permitting:
- [D-76: ClaudeConfig — Claude's config surface is clide's app settings (builtin-owned, watched, probe-cached per version)](decisions/architecture.md#d-76-claudeconfig--claudes-config-surface-is-clides-app-settings-builtin-owned-watched-probe-cached-per-version) — _architecture_
- [D-77: Drive Claude via the stream-json control protocol; teams become a clide-owned coordination layer](decisions/architecture.md#d-77-drive-claude-via-the-stream-json-control-protocol-teams-become-a-clide-owned-coordination-layer) — _architecture_
- [D-78: Claude permission/prompt transport is the stdio control channel](decisions/architecture.md#d-78-claude-permissionprompt-transport-is-the-stdio-control-channel) — _architecture_
- [D-79: Workspace content search is a pure-Dart in-process engine, outside pql](decisions/architecture.md#d-79-workspace-content-search-is-a-pure-dart-in-process-engine-outside-pql) — _architecture_
## Open questions
+13
View File
@@ -344,3 +344,16 @@ Core, rendering, IPC, kernel, panel manager.
- **Raised by:** 2026-05-25 — during T-165/T-166 work, an empirical spike against claude 2.1.150 (driving the real CLI + reading the shipped binary's zod schemas) nailed the control-protocol shapes. User weighed stdio vs MCP for permissions, chose stdio for directness, and asked that the brittleness and researched alternatives be documented so a future Anthropic change doesn't leave clide without options.
---
### D-79: Workspace content search is a pure-Dart in-process engine, outside pql
- **Date:** 2026-05-31
- **Status:** accepted
- **Decision:** Find-in-files / search-and-replace (T-52/T-53) run as a **pure-Dart, in-process grep engine** — an isolate worker pool fans non-ignored files out across cores, matches with `RegExp` (with a literal `indexOf` fast-path when the regex toggle is off), and **streams** matches back over a single engine-agnostic IPC verb (`search.grep`) with cancellation when the query changes. It does **not** shell out to `ripgrep`/`grep`, and it does **not** route through pql.
- **Rationale / D-3 boundary:** D-3 says clide *wraps pql for query surfaces* — but `pql search` is a **ranked full-text *document* index** (returns `path`/`score`/`connections`, no line numbers, snippets, regex, case, or glob). Content-grep ("match-in-context, click-to-line, regex/case/glob") is a **code-navigation primitive pql does not offer**, so it is explicitly outside pql's query surface and is clide's to own (consistent with the "own the rendering/tooling stack" guardrail). A shell-out to `ripgrep` was rejected as the default: it adds an unvendored external binary that isn't guaranteed present (esp. cross-platform), against prefer-zero-deps and single-process.
- **Performance:** the I/O floor (walk + read) is shared by every engine. ripgrep's edge is multithreading + SIMD literal prefilters + a non-backtracking DFA; the Dart engine recovers the dominant win (parallelism) via an **isolate pool**, sidesteps the regex-engine gap for the common case via the **literal fast-path**, and hides the rest behind **streaming + cancellation**. Net: interactive (sub-second) on realistic repos including this one; ripgrep only pulls visibly ahead at monorepo scale clide is not targeting.
- **Escape hatch (de-risk):** the `search.grep` request/result contract is **engine-agnostic**. If a giant-repo benchmark ever demands it, an optional "use `rg` when on PATH, else the built-in engine" accelerator can slot in behind the same verb with **no caller changes** — recorded as future work on T-52, not built now.
- **Distinct from structural search:** this is *text* grep. *Structural/semantic* search ("find usages", "go to definition") is tree-sitter's job (clide already vendors `libtree-sitter.so` for highlighting) and is a separate future feature, not part of T-52.
- **Cross-reference:** clarifies [D-3](#) (pql wrap boundary) and the "own the stack" guardrail; relates to [D-4](#d-4-ignore-file-strategy) (the engine honors the full `ignore_files:` layering — see T-52, which closes the never-filed ignore-layering placeholder, a `(to be recorded)` comment in `files_commands.dart`). Implemented by T-52 (engine + find-in-files) and T-53 (replace).
- **Raised by:** 2026-05-31 — during /whats-next refinement of the search/nav batch (T-51/T-52/T-53). Refinement surfaced that `pql search` structurally can't satisfy find-in-files; the user probed tree-sitter (ruled out — it's a parser, not a grepper) and the performance ceiling, then chose the fastest *reasonable* Dart option (isolate pool + literal fast-path + streaming) over a ripgrep dependency.
---