get_active_build
Check index health and get active build metadata: status, compile commands, defines, memory, and reindex reasons before querying C/C++ symbols.
Instructions
MANDATORY FIRST CALL for C/C++ projects. Return metadata about the most recently indexed build configuration — check index health before using any other fw-context tools.
Read-only, and it spawns no subprocess — the startup daemon thread and the file watcher own the background reindex.
Act on status:
"ready"— up to date. Continue."reindexing"— background reindex running; queries stay accurate. Continue.reindex_progressholds its last log line."reindex_needed"— schema mismatch, an old row format, changed compile_commands.json, or a source file that compile_commands.json does not cover. Queries still work on existing data. Readreindex_reasons: a missing source file needsfw-context index --build, the others need onlyfw-context index.Read
bg_reindex_runningbefore you name any command here. A run already under way does the work, thus a second one only waits on the same lock, andindex_messageand the branch reason both say so. That field covers a run of the daemon AND a run the operator started — the arguments of neither are readable, thus a reason that needs--buildcan outlive a run without it. This status wins over"reindexing"deliberately: the answers of this moment come from the rows of the last FINISHED run."no_index"— initialized, never indexed. Runfw-context index."not_initialized"— runfw-context init.
A failure sets NO status. DB corruption, or no access to the
index, gives a dict that holds error alone. Read that key first:
a reader that waits for status == "error" waits for a value this
tool does not produce.
Four conditions set reindex_needed: an outdated schema, an outdated
ROW FORMAT, a changed compile_commands.json, and a source file that is
on disk but absent from compile_commands.json. The last one needs a
build, because only the build system writes that file — a plain reindex
has no translation unit for the file and skips it without a word.
Modified source files are something else: they are handled per-query,
and never set it.
row_format_mismatch means that the same columns hold text with an
older meaning. Take it seriously: an index written before
fw-context-rows/1 keeps every inactive #ifdef branch, thus a
body or a file from it can show code that the compiler never sees. An
index written before fw-context-rows/3 is wrong the other way: it
ANSWERS LESS than it should. A definition that begins and ends on one
line has no stored body there, thus search_bodies cannot reach an
inline accessor; no macro is marked function-like; and no instance links
to its template, thus get_template_instances gives an empty list for
every template. Each of those looks like a legitimate empty answer.
The value of a macro there also holds its parameter list glued to
its replacement text, thus neither can be read out of it.
client_restart_required is the OPPOSITE case, and no command repairs
it. The index carries a NEWER row format than this server process
reads, thus the index is the correct one and this process is the old
reader. A reindex makes it worse than useless: the indexer writes the
same new format again, and the message comes back over an index that had
nothing wrong with it. status therefore stays "ready" and
reindex_needed stays False — every query keeps working.
Do NOT run a reindex for this field. Tell the operator to restart the
LLM client — Claude Code, opencode, or whichever one is in use. The MCP
server is a child process of that client, thus nobody can restart the
server by itself. client_restart_reason holds the wording, and
index_message opens with it.
indexed_at and first_indexed_at are UTC; file mtimes are local
time. Never compare the two directly — in UTC+2 a correctly indexed
file looks 2 hours newer than indexed_at. Call with fast=False
to find modified files.
analysis splits the LLM-analysis coverage into project and vendor
symbols:
model— the model of the analysis, or None. One model only, even when several were used.analyze_vendor— the value at index time, not the current config.project/vendor—{analyzed, skipped, total}.skipped= tried, but not analyzable (body larger than the model context, an unparseable answer, or a body that was not readable).complete— no work left: every project symbol is analyzed or skipped. True exactly whenreindex_reasonsholds no "unanalyzed symbols" entry. Vendor symbols excluded byanalyze_vendor=Falsenever block it, thusvendor.totallarge withvendor.analyzed=0is expected, not a defect.
Args:
project_root: Project root directory. Auto-detected from CWD 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.
fast: When True (default), the header check reuses the cached
manifest hashes. Both modes run the per-file scan, thus
modified_files_count is accurate either way — a tool that
reported "ready" while the search tools warned about the same
file gave the caller two readings and no way to choose.
False recomputes the header hashes and costs several times more.
Returns:
dict: {config_hash, project_id, project_root, build_system,
compile_commands, indexed_at (str — "YYYY-MM-DD HH:MM:SS" in UTC,
the completion time of the last full index), symbol_count, file_count,
reference_count, modified_files_count (int — files whose content no
longer matches the index; counted in both modes),
header_affected_tus (int — number of TUs with stale header
dependencies), manifest_verification (str —
"full" when manifest.json exists, "none" otherwise),
analysis (dict — LLM-analysis coverage split by project/vendor:
{model, analyze_vendor, project: {analyzed, skipped, total},
vendor: {analyzed, skipped, total}, complete}),
description (str), first_indexed_at (str — UTC, same format as
indexed_at),
vendor_paths (list[str] — config index.vendor_paths),
project_paths (list[str] — config index.project_paths),
effective_vendor_patterns (list[str] — the SQL LIKE patterns that
this build really used to mark vendor code, for example
["mbed-os/%"]; empty when the manifest cannot be read. The two
lists above hold what the config asks for, this one what the index
did),
bg_reindex_running (bool),
reindex_progress (str or None — last log line when reindex is running),
schema_version (int — DB schema version),
current_schema (int — code expects), status (str — "ready"|"reindexing"|
"reindex_needed"|"no_index"|"not_initialized"; a failure sets no
status and gives error alone), reindex_needed (bool —
structural mismatch requiring a full reindex),
reindex_reasons (list[str] — why reindex is needed, empty when False.
One of them asks for fw-context index --build rather than a plain
reindex: when the tree is on a different branch than the index,
compile_commands.json belongs to the OLD branch and carries its file
list and its compiler flags, so only a build regenerates it. Read
the reason text — it names the command it needs),
stale (bool — True when reindex_needed or header_affected_tus > 0),
_warning (str, optional — when manifest verification is not "full"),
vec_available (bool), vec_error (str, optional),
index_message (str — human-readable summary of index state),
multi (bool — True for a multi-variant project),
variants (list[dict] — {name, description, board}),
images (list[dict] — {name, description, dir, type}),
variant_images (dict — variant name to its image names),
active_variant (str or None — [build] default_variant),
active_image (str or None — [build] default_image),
entry_point (str — the ENTRY() of the linker script of the build
that the other fields describe, empty when no script names one),
memory (list[dict] — the MEMORY regions of that build:
{name, attributes, origin, length, origin_value, length_value,
file_path, line})}
About ``memory``: ``origin`` and ``length`` hold the expression the
script writes, thus they differ by platform — an mbed script writes
`0xefe00` and a Zephyr script writes `((673792) - 0xe6)`.
``origin_value`` and ``length_value`` hold the number, and both are
None for an expression that names a symbol, such as
`ORIGIN(RAM) + LENGTH(RAM)`. The end of a region is
``origin_value + length_value``.
``memory`` and ``entry_point`` describe ONE build. For a
multi-variant project they follow ``config_hash``, which is the
build named by ``[build] default_variant``, and both are empty when
the config names no default. Use ``list_variants`` for the map of
every build.
``memory`` is empty for a build system that records no linker
script. A PlatformIO project is the measured case: SCons writes no
ninja file and no link command the index can read, and the map file
never names the script. An empty list means "not recorded", never
"no memory".
``defines`` (dict — the `-D` flags of that build) and
``defines_varying`` (int). ``defines`` holds only the names that
EVERY translation unit of the build carries with the same value, so
the tool never shows the defines of one file as the defines of the
build. ``defines_varying`` counts the names left out, thus a name
absent from ``defines`` is either not defined at all or not defined
everywhere — measured on the Mbed project: 27 names in all 881 units, 59
in only some, where the three assembly files get a shorter set.
This is the configuration the BUILD states, not every macro the
preprocessor saw. The second is three orders of magnitude larger —
27800 distinct names on the STM32 project — and almost all of it comes from the
headers and the compiler. A Zephyr build keeps its real
configuration in ``autoconf.h`` (740 `CONFIG_*` names) and passes
few `-D` flags, so ``defines`` says little there and a great deal on
an mbed build, where it holds `APPLICATION_ADDR`,
`APPLICATION_SIZE`, and `CMSIS_VECTAB_VIRTUAL`.
For a project that is not initialized, the result holds only
``status``, ``project_root``, and ``index_message``. When no index
exists, the result adds ``project_id``.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| fast | No | When True (default), reuse the cached manifest hashes for the header check. Both modes count modified files. Pass False to recompute the header hashes, which is far slower. | |
| 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. | |
| project_root | No | Project root directory. Auto-detected from CWD if omitted. This field also accepts a project name or a project_id, but project is the clear field for those. |