search_bodies
Find patterns in compiled C/C++ definition bodies—calls, declarations, members—and get matching symbols with exact line numbers for citation.
Instructions
Find patterns in the TEXT OF A DEFINITION — the code inside its extent.
Searches ifdef-filtered text — only the code that compiles for the
current build. A line of an inactive #if branch holds nothing, thus
a pattern that lives only in a dead branch gives no result here. That
empty answer is the correct one: the code does not compile.
Searches the stored text of every definition (is_definition=1), and
a definition is not only a callable. Measured on one project of 60,877
symbols, the text covers:
Callables —
function,method,constructor,destructor. Call patterns (.attach(,.rise(,callback(&), ISR registration, onecaselabel of a longswitch.Types —
class,struct,union,enum,namespace. An enum constant, a bit field, a member declaration such asInterruptIn _pin;— all inside the body of the type that holds them.Definitions of data —
varglobal,varlocal,typedef. A table with a multi-line initializer is found by its content.
A match on a type reports the type as the result, thus a query for one
enum constant answers with the enum, and match_lines gives the line
of the constant itself.
Only the text matches. The query is bound to the stored body: a
hit in the NAME, the signature, the docstring or the llm_analysis
of a symbol is not a hit here. Measured on one project, sensor
used to give 36 results of which 22 matched only through a summary that
a model wrote — untrusted text that cannot be cited, and a
_match_snippet with no match in it. Use search_code to reach a
name or a concept. A column filter you write yourself
(summary : sensor) overrides the binding.
When to use search_bodies and when search_code:
search_bodies— patterns in the code (what the code DOES or DECLARES):self test,attach,SELF_TEST.search_code— symbols by NAME (what the code IS):modem init,interrupt handler.
The query goes to FTS5 as you wrote it. This tool alone adds no wildcard, and that is what keeps a pattern precise:
A space is an AND of two exact tokens, NOT an OR.
CommandType NUManswers with the definitions that hold both.No prefix is implied.
SELF_TESTmatches the tokensself testand missesSelf tester; writeSELF_TEST*to reach the second. Measured on one project, the wildcard added the one caller that the bare query missed.Punctuation is not searchable. FTS5 cannot parse
.attach(at all, thus the query is repaired into the phrase".attach("— and the tokenizer inside a phrase drops the punctuation too, so what runs is the wordattach. Such a result carries_fallback: "sanitized"and_query_used. The hits whose body really holds.attach(are the ones withmatch_lines.search_codeandsearch_contentbehave the OTHER way: each of their terms gets a trailing*and the terms are OR-joined.
Limitation — the extent of a definition is the boundary. Text that belongs to no definition is out of reach:
#include,#define,#ifdef— preprocessor directives.search_codecovers a macro name and value.search_contentcovers the directive as text.extern "C"— a linkage specifier is no symbol.A comment or a declaration at file scope, outside every definition.
For those, use search_content, which indexes the full file text.
Set project_only=True for a question about YOUR code ("where do we register interrupt handlers?"). Leave it False (default) when the
vendor SDK code — the framework or OS code that your team did not write
— is also relevant.
Results include _match_snippet — a highlighted excerpt that shows
each match in context (e.g. _timeout.<b>attach</b>(callback(...))) —
and match_lines, the line numbers of the matches inside the
definition. line is where the definition starts, which for a large
function is far from the match. Cite from match_lines instead.
Project code sorts before vendor code in the output.
Read-only: yes. Requires the FTS5 index. May auto-reindex stale files
(non-blocking) — see search_code.
Args:
query: FTS5 search terms, 1-3 words. A bare multi-word query is an
AND of exact tokens, and no wildcard is added — see the query
rules above. A single word is the broadest form: 'attach'
reaches every .attach(...) pattern. Add * for a prefix
('attach*'), and double quotes for a phrase
('"attach callback"').
project_root: Project root. Auto-detected if omitted.
project: Project name or project_id — call list_projects to get them. Use
it to ask about a project that is not the project of the current
directory. It is an alternative to project_root, which takes a root
path. Give one of the two, not both.
kind: Optional filter to return only symbols of this kind.
limit: Maximum results of one page (default 20, max 100).
offset: Skip this many results. Reads the next page of a pattern
with many hits; the page notice names the offset to use.
project_only: When True, exclude vendor SDK directories and return only
application code. Default False.
variant: Build variant (multi-build project). Omit to use
default_variant. One query answers for ONE build.
image: Sysbuild image within the variant. Required when the
variant holds several: each image is a separate program.
Returns:
list of dicts. The page notice leads the answer — total,
offset, shown, more — and each that follows holds:
name, qualified_name, kind, file, line (first line of the
definition), is_definition, signature, _match_snippet (excerpt
around the match), source (the text of the definition).
Also, when they carry an answer:
* ``match_lines`` (list[int]) — absolute line numbers of the
matches, up to 20. Computed from the full text, thus a match
after the cut below still has a number. Use these to cite
``file:line``, and not the ``line`` of the definition. The name
carries no leading underscore for a reason: a field the caller
must cite is an answer, while ``_``-prefixed fields
(``_match_snippet``, ``_fallback``, ``_source_truncated``) tell
where the answer came from.
* ``_source_truncated`` (True) — ``source`` is cut. A callable
keeps 2000 characters, any other kind 500, because the body of a
type is mostly members that the match has nothing to do with.
``get_source`` gives the whole text.
* ``_fallback`` (``"sanitized"``) with ``_query_used`` — FTS5 could
not parse the query as written, thus a repaired one ran. The
repair drops punctuation, so the answer is wider than the text
that was asked for. Every query FTS5 accepts runs untouched and
carries neither field.
``source`` here is bare text with no line-number prefix. Only
``get_source`` numbers its lines.
No match gives ``[]``. A dict with ``error`` means the query
failed. A stale index prepends a dict with ``warning`` + ``hint``,
and so does a query that FTS5 refuses to parse — an empty list
always means "no such code", never "bad query".
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Optional kind filter: function, method, class, etc. | |
| image | No | Sysbuild image within the variant. Required when the variant holds several: each image is a separate program. | |
| limit | No | Maximum results of one page (default 20, max 100). | |
| query | Yes | FTS5 search terms for the body of a definition. 1-3 words. E.g. 'attach', 'callback', 'rise'. | |
| offset | No | Skip this many results. Reads the next page of a pattern with many hits. | |
| project | No | Project name or project_id — call list_projects to get them. Use it to ask about a project that is not the project of the current directory. It is an alternative to project_root, which takes a root path. Give one of the two, not both. | |
| variant | No | Build variant (multi-build project). Omit to use default_variant. One query answers for ONE build. | |
| project_only | No | Exclude vendor SDK code. When True, only application code. Default False. | |
| project_root | No | Project root. Auto-detected if omitted. This field also accepts a project name or a project_id, but project is the clear field for those. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |