Skip to content

feat(runtime): code_search workspace regex search tool (#6295)#6307

Merged
houko merged 3 commits into
mainfrom
feat/code-search-tool
Jun 24, 2026
Merged

feat(runtime): code_search workspace regex search tool (#6295)#6307
houko merged 3 commits into
mainfrom
feat/code-search-tool

Conversation

@houko

@houko houko commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What

First slice of the #6295 workspace code-intelligence layer: a code_search agent tool that regex-searches the workspace in one call.

Coding agents currently locate code by looping file_list + file_read — there is no grep-equivalent built-in. code_search closes that gap: one call returns relpath:line: content rows for every match under a workspace-relative path.

Scope (deliberately minimal)

Lexical / regex search only. Structural symbol indexing, repo maps, reference graphs, and LSP / vector backends from @pavver's proposal are out of scope for this slice and tracked as later stages of #6295. Starting with lexical search follows the discussion's "FTS / repo maps before LSP and vectors" ordering and keeps the first slice small and reviewable.

Behaviour

  • Input: query (regex, required), path (workspace-relative, default root), case_sensitive (default false), max_results (default 100, hard cap 1000).
  • Skips .git / .hg / .svn / target / node_modules, hidden dirs, symlinks (not followed), binary files (NUL-byte sniff), and files larger than 2 MB. Caps total files scanned at 20k.
  • Output sorted by path then line (deterministic, Enforce deterministic ordering for LLM-bound registries to stabilize prompt cache #3298); per-line output clipped to 400 chars on a char boundary; truncation is flagged in the output.

Design decisions

  • No new dependency: hand-rolled iterative tokio::fs::read_dir DFS + the already-vendored regex crate. No walkdir, no tree-sitter.
  • Lives in librefang-runtime/src/tool_runner/search.rs, wired like any other built-in tool — no new crate (the crate-boundary question from Workspace Code Intelligence Layer for Coding Agents #6295 is left for the structural-index stage).
  • Read-only, always-native: added to ALWAYS_NATIVE_TOOLS (eager, no lazy-load round-trip) and to the guest read-only allowlist in kernel/auth.rs, so it needs no approval gate — same treatment as file_list. Path access goes through the existing resolve_file_path_ext sandbox.

Wiring

  • tool_runner/search.rs — handler tool_code_search + 5 unit tests.
  • tool_runner/definitions.rstool_name::CODE_SEARCH, ToolDefinition (JSON schema), ALWAYS_NATIVE_TOOLS.
  • tool_runner/dispatch.rs"code_search" match arm (named-workspace + download-dir read allowlist, like file_list).
  • tool_runner/mod.rsmod search; + handler import.
  • kernel/auth.rs — guest READ_ONLY_TOOLS allowlist.
  • prompt_builder.rstool_category (Files) + tool_hint.

Tests (in search.rs)

  • missing_query_is_missing_parameter
  • invalid_regex_is_invalid_parameter
  • finds_matches_with_line_numbers
  • is_case_insensitive_by_default_and_respects_flag
  • skips_git_dir_and_binary_files
  • no_matches_returns_friendly_message

Verification

This box has no native Rust toolchain and Docker was unavailable in this session, so cargo check / cargo fmt could not be run locally (the pre-commit fmt hook took its documented no-rustfmt soft-skip). CI is the authoritative check — the runtime unit lane compiles + runs the new tests, and the fmt lane validates formatting. Types were cross-checked against the file_list handler template (ToolError / ToolResult / resolve_file_path_ext signatures) and the existing drift tests (no_duplicate_tool_names, tools.len() at least 40) cover the new registration.

refs #6295

Coding agents previously located code by looping file_list + file_read, spending tool calls and context rediscovering structure. code_search regex-searches every text file under a workspace-relative path in one call and returns relpath:line: content rows. It skips .git/target/node_modules, hidden, binary, and >2MB files; sorts results by path then line for deterministic output (#3298); and bounds the response with max_results (default 100, hard cap 1000).

Read-only, always-native (no approval gate, like file_list), zero new dependencies — a hand-rolled tokio::fs DFS plus the existing regex crate.

First lexical-only slice of the #6295 workspace code-intelligence layer; structural symbol indexing, repo maps, and LSP/vector backends are out of scope here and tracked as later stages.

Wiring: tool_name const + ToolDefinition + ALWAYS_NATIVE_TOOLS (definitions.rs), dispatch match arm (dispatch.rs), handler + tests (search.rs), guest read-only allowlist (kernel/auth.rs), and tool category/hint (prompt_builder.rs).
@github-actions github-actions Bot added size/L 250-999 lines changed area/docs Documentation and guides area/runtime Agent loop, LLM drivers, WASM sandbox area/kernel Core kernel (scheduling, RBAC, workflows) labels Jun 24, 2026
@houko
houko enabled auto-merge (squash) June 24, 2026 04:55
@houko
houko merged commit caf6948 into main Jun 24, 2026
32 checks passed
@houko
houko deleted the feat/code-search-tool branch June 24, 2026 05:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation and guides area/kernel Core kernel (scheduling, RBAC, workflows) area/runtime Agent loop, LLM drivers, WASM sandbox size/L 250-999 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants