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

class agentgrep.UIArgs
class
class
class agentgrep.UIArgs

Bases: object

Typed arguments for agentgrep ui.

Entry points

agentgrep.ui.app.run_ui(home, query, *, control, initial_search_text=None)
function
function
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 calls app.run(). The factory split lets tests construct the app for a Textual Pilot smoke test without entering the blocking run loop.

Parameters:
  • home (pathlib.Path) – User home directory, passed through to run_search_query().

  • query (SearchQuery) – Search to run. Empty terms means “all records” (browse mode).

  • control (SearchControl) – Shared cooperative-cancel flag; Esc / Ctrl-C call request_answer_now to nudge the worker to wrap up.

  • initial_search_text (str | None) – Initial value of the TUI search box. When None, defaults to the space-joined query.terms. The CLI passes the raw positional string here so a launch like agentgrep search --ui agent:codex bliss opens with the full query in the box (not just the text terms).

Return type:

None

agentgrep.ui.app.build_streaming_ui_app(home, query, *, control, initial_search_text=None)
function
function
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 AgentGrepApp instance (typed object because 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 to run_search_query().

  • query (SearchQuery) – Search to run. Empty terms means “all records” (browse mode).

  • control (SearchControl) – Shared cooperative-cancel flag; Esc / Ctrl-C call request_answer_now to nudge the worker to wrap up.

  • initial_search_text (str | None)

Return type:

object

Filter and display helpers

agentgrep.cached_haystack(record)
function
function
agentgrep.cached_haystack(record)

Return the casefolded haystack for record, memoized by id.

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 by id is safe because the app retains every record in AgentGrepApp.all_records for 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:

str

agentgrep.clear_haystack_cache()
function
function
agentgrep.clear_haystack_cache()

Drop every memoized haystack — call before allocating a new record set.

Return type:

None

agentgrep.compute_filter_matches(records, text)
function
function
agentgrep.compute_filter_matches(records, text)

Return the subset of records whose haystack contains text (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) text returns all records.

Returns:

Matching records in input order.

Return type:

tuple[SearchRecord, ...]

agentgrep.format_timestamp_tig(value)
function
function
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 "" for None / 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'
Parameters:

value (str | None)

Return type:

str

agentgrep.ui.app.scroll_percent(scroll_y, max_scroll_y)
function
function
agentgrep.ui.app.scroll_percent(scroll_y, max_scroll_y)

Return an integer scroll percent clamped to [0, 100].

Returns 100 when there is no scrollable region (everything fits) and 0 when scrolled to the very top. Mirrors tig’s bottom-status convention where a fully visible view reads as 100%.

Parameters:
Return type:

int