API Reference¶
The agentgrep.ui subpackage holds the streaming Textual explorer.
Textual is imported lazily inside
build_streaming_ui_app() via
importlib.import_module, so bare import agentgrep does not pull
Textual into the importing process; the import error is deferred to
the moment the factory is called.
The subpackage’s __init__ re-exports run_ui()
and build_streaming_ui_app() at the
agentgrep.ui namespace for convenience, and the top-level
agentgrep package provides matching lazy wrappers so callers can
use agentgrep.run_ui() without reaching into agentgrep.ui.app.
Argument type¶
Entry points¶
-
agentgrep.ui.app.run_ui(home, query, *, control, initial_search_text=None)¶agentgrep.ui.app.run_ui(home, query, *, control, initial_search_text=None)¶
Launch the streaming Textual explorer for
query.Thin wrapper that builds the app via
build_streaming_ui_app()and callsapp.run(). The factory split lets tests construct the app for a TextualPilotsmoke test without entering the blocking run loop.- Parameters:
home (
pathlib.Path) – User home directory, passed through torun_search_query().query (
SearchQuery) – Search to run. Emptytermsmeans “all records” (browse mode).control (
SearchControl) – Shared cooperative-cancel flag;Esc/Ctrl-Ccallrequest_answer_nowto nudge the worker to wrap up.initial_search_text (
str|None) – Initial value of the TUI search box. WhenNone, defaults to the space-joinedquery.terms. The CLI passes the raw positional string here so a launch likeagentgrep search --ui agent:codex blissopens with the full query in the box (not just the text terms).
- Return type:
-
agentgrep.ui.app.build_streaming_ui_app(home, query, *, control, initial_search_text=None)¶agentgrep.ui.app.build_streaming_ui_app(home, query, *, control, initial_search_text=None)¶
Construct the streaming Textual app without entering its run loop.
Returns the constructed
AgentGrepAppinstance (typedobjectbecause the actual class is defined dynamically inside this factory). Callers can invoke.run()for a real session or.run_test()for a Pilot smoke test. The full app body — message subclasses,SpinnerWidget,FilterInput,AgentGrepApp— lives here so the Textual imports stay lazy.- Parameters:
home (
pathlib.Path) – User home directory, passed through torun_search_query().query (
SearchQuery) – Search to run. Emptytermsmeans “all records” (browse mode).control (
SearchControl) – Shared cooperative-cancel flag;Esc/Ctrl-Ccallrequest_answer_nowto nudge the worker to wrap up.
- Return type:
Filter and display helpers¶
-
agentgrep.cached_haystack(record)¶agentgrep.cached_haystack(record)¶
Return the casefolded haystack for
record, memoized byid.The filter worker scans every loaded record on every keystroke; recomputing
build_search_haystack(...).casefold()per record per pass dominates filter latency once the result set grows past a few thousand records. Memoizing byidis safe because the app retains every record inAgentGrepApp.all_recordsfor the lifetime of one search, so Python cannot recycle a collected record’s id while its entry sits in_HAYSTACK_CACHE.Callers that need to invalidate (because a new search will allocate new records) should call
clear_haystack_cache().- Parameters:
record (
SearchRecord)- Return type:
-
agentgrep.clear_haystack_cache()¶agentgrep.clear_haystack_cache()¶
Drop every memoized haystack — call before allocating a new record set.
- Return type:
-
agentgrep.compute_filter_matches(records, text)¶agentgrep.compute_filter_matches(records, text)¶
Return the subset of
recordswhose haystack containstext(case-fold).Used by the TUI’s filter worker. Pure function so the filter logic is directly unit-testable without spinning up a Textual app.
- Parameters:
records (
Sequence[SearchRecord]) – Records to test.text (
str) – Filter text. Whitespace-trimmed and case-folded before matching. An empty (or whitespace-only)textreturns all records.
- Returns:
Matching records in input order.
- Return type:
tuple[SearchRecord, ...]
-
agentgrep.format_timestamp_tig(value)¶agentgrep.format_timestamp_tig(value)¶
Render an ISO-8601 timestamp as
YYYY-MM-DD HH:MM ±HHMM(tig style).Localizes to the system timezone before formatting so the displayed time matches what the user expects to see — tig’s main view does the same. Returns
""forNone/ empty input and a clipped raw string for unparseable input so callers can pad consistently.Examples
>>> format_timestamp_tig(None) '' >>> format_timestamp_tig("") '' >>> # An ISO timestamp with explicit timezone — formatted result keeps >>> # the offset for the system's local timezone (whose exact value >>> # varies by host, so we just check shape here). >>> sample = format_timestamp_tig("2026-05-17T11:59:12+00:00") >>> len(sample) 22 >>> sample[4], sample[7], sample[10], sample[13], sample[16] ('-', '-', ' ', ':', ' ') >>> format_timestamp_tig("not-a-real-timestamp") 'not-a-real-timestamp'
-
agentgrep.ui.app.scroll_percent(scroll_y, max_scroll_y)¶agentgrep.ui.app.scroll_percent(scroll_y, max_scroll_y)¶
Return an integer scroll percent clamped to
[0, 100].Returns
100when there is no scrollable region (everything fits) and0when scrolled to the very top. Mirrors tig’s bottom-status convention where a fully visible view reads as100%.