Skip to content

feat(tool): search_code — dedup + rank find_code matches (Issue #10)#20

Merged
kellenff merged 1 commit into
mainfrom
feat/issue-10-search-code
Jul 6, 2026
Merged

feat(tool): search_code — dedup + rank find_code matches (Issue #10)#20
kellenff merged 1 commit into
mainfrom
feat/issue-10-search-code

Conversation

@kellenff

@kellenff kellenff commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

Implements issue #10, part 1: a new `search_code` MCP tool that wraps `find_code` matches into their containing functions, dedupes by NodeID, and ranks by structural importance.

Semantic search (part 2) deferred per the YAGNI note in the issue — embeddings cost disk, RAM, and a build dep; ship dedup+rank first, add when a real consumer asks.

What it does

Same args as `find_code` (pattern, pattern_kind, scope, file_filter, limit). Output is an array of `groups`:

```
{
groups: [
{
nodeId, kind, summary, file, enclosingRange,
matchCount, matches: [{line, snippet}],
bucket: "definition" | "popular" | "test"
}
],
provenance: { tool: "yactt", version, fetchedAt }
}
```

Ranking: bucket tier → matchCount desc → fanIn desc → nodeId asc, stable.

Files

  • new `internal/tool/searchcode.go` — handler factory, args, schemas, group + rank logic. ~190 lines.
  • new `internal/tool/searchcode_test.go` — dedup, bucketing, tree-sitter path, limit cap, provenance, regex validation, length cap, stable sort.
  • new `tests/acceptance/searchcode_test.go` — dedup against fixture (3 `err` refs in `Login` collapse to one group), test-bucket assertion (`login_test.go` references land in `test`), provenance stamp.
  • mod `cmd/yactt/main.go` — registers `search_code` in both the `tools` slice and the `persisted_query` `toolFuncs` map.
  • mod `internal/tool/wire_shape_test.go` — adds the contract-test row.
  • mod `README.md` + `plugins/yactt/README.md` — bumps tool counts (19→20 / 10→11), adds the `search_code` row + mention.

Reuse

Heavy lifting already lives in `internal/tool/findcode.go`:

  • `findCodeRegex(repo, scope, fileFilter, rx, true, limit)` — regex scan with enclosing-symbol context per match
  • `findCodeTreeSitter(repo, scope, fileFilter, pattern, true, limit)` — tree-sitter scan with same context
  • `enclosingContext(repo, path, line)` — already wired to the in-memory symbol index

`search_code` calls these with `withContext=true` and adds only the group + rank layer on top. No re-parsing, no duplicated logic.

Verification

  • `go vet ./...` clean
  • `go test ./...` green (full suite, ~6 min)
  • New unit tests: 8 cases
  • New acceptance tests: 3 cases (dedup, test-bucket, provenance)
  • `wire_shape_test` exercises the new tool via the JSON-RPC server

Closes #10 (part 1).

🤖 Generated with Claude Code

… symbol

Issue #10 part 1: wraps find_code matches into their containing
functions, dedupes by NodeID, ranks by structural importance
(definitions first, popular next, tests last). Mirrors
codebase-memory-mcp's search_code. Embeddings (semantic_query)
deferred per the YAGNI note in the issue.

Reuses findCodeRegex / findCodeTreeSitter with withContext=true;
adds a group + rank layer on top. Stamps Provenance.Tool like every
other answer.
@kellenff
kellenff merged commit cbcaecf into main Jul 6, 2026
5 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.

search_code dedup+rank; optional semantic/vector layer

1 participant