↑ ↓ to move · Enter to open · Esc to close Something not working? Troubleshooting
    On this page

    Search

    The suv search command opens an interactive search TUI that lets you find, filter, and reuse commands from your recorded shell history. It supports literal-word matching with ranked results, a view of every run or of identical commands grouped, a directory-aware Smart mode, a detail preview pane, and a rich set of keyboard shortcuts.

    Search for docker logs and return the selected command to the prompt without running it. Recorded in v0.5.0 with fictional data.

    Basic Usage

    Launch the interactive search TUI:

    suv search

    Start typing to filter your history. Use the arrow keys to navigate, and press Enter (labelled Use) to put the selected command on your prompt for review when you opened search with Ctrl+R, or to print it when you ran suv search directly. Enter never runs anything.

    How Matching Works

    Each word you type must appear as a literal substring in the searched field (in any order) — so results always contain what you typed. Matching is case-insensitive. terms and fuzzy fold non-ASCII case too (fuzzy since 0.5.0; before that it folded ASCII only, so --match fuzzy ÉCHO missed écho); literal and prefix are answered by SQLite's LIKE, which folds ASCII only. Results are ranked by match quality: the query as a prefix first, then as a contiguous phrase, then your words in order, then in any order. Recall and search show your own (human-typed) commands by default; press Ctrl+A to include AI-agent commands. See How results are ranked for the full ordering.

    Since 0.4.0, database-level substring queries on the command field use an FTS5 trigram index. Since 0.4.2, text you type or edit inside the open TUI takes the same path: every matching mode narrows candidates in the database, over your whole eligible history, so how old a match is never decides whether it is found. The query passed with -q/--query (which the Ctrl+R widget uses for any text already on your prompt) now goes through that same pipeline instead of a separate one.

    Matching Modes and Scopes

    Matching decides which commands are eligible, scope decides where to look, and ranking decides only the order. They are three separate controls, and changing one never changes what another does.

    Matching — --match, or Ctrl+X in the search UI: terms (the default — every whitespace-separated word must appear as a substring, in any order), literal (the whole query exactly as typed, spaces and punctuation included), prefix (the command starts with the query), and fuzzy (the query's letters appear in order, gaps allowed, so gco finds git checkout). Words are ANDed, never ORed; there is no quoting syntax and punctuation is never stripped, so git-push is one word.

    Scope — --scope, Ctrl+P to cycle, Ctrl+R to reset: all (default), directory (commands run in exactly the current directory, not its subdirectories — --here is the same thing), workspace (anywhere under the nearest enclosing Git repository; a linked worktree is its own workspace and a nested repository wins over its parent), and session (the current shell session). A scope that cannot apply here — no repository, no session — says so on stderr and falls back explicitly; it never silently widens.

    suv search --compact draws the same UI inline under your prompt instead of taking over the screen, so the output you were reading stays visible. All three have config keys — search.match_mode, search.scope and search.compact — that set the default for every recall, and all default to the behaviour of earlier releases. Since 0.5.0 you can set them on the Search tab of suv settings (Default Match Mode, Starting Scope, Compact Recall) as well as in config.toml.

    Fixed in 0.4.2: up to and including 0.4.1, typing or editing a query inside the open search TUI first loaded the newest 5,000 entries that passed your filters and matched your text against only those, so an older command could be missing from the results even though it was still stored. Matching and counting now finish in the database across your whole eligible history. At most 5,000 matches are ordered by relevance — that caps the ranking work, not how much history was searched, and not how much of it you can reach. The result count is the real number of matches and every page of it opens; pages past the ranked window come back newest first, because a relevance order computed from only part of a result set would be arbitrary there.

    Reading the Results

    Why a row matched

    The characters your query matched are underlined and emphasised in every row, over the usual syntax colours: every occurrence of each word in terms mode, the whole query in literal, the start in prefix, and the characters the subsequence rule walked in fuzzy. Highlighting applies when you search command text, the default field.

    Executions and Commands

    Search shows the same results in two views, and Ctrl+U switches between them:

    • Commands (where recall opens) — identical commands share one row, with a Last used age and a Runs count (for example 26×) of how many runs matched, so a command you ran fifty times does not push every other candidate down the list. A command is grouped only with exactly the same text: whitespace, flags and case are never normalised.
    • Executions — every recorded run, with its time, directory and outcome. On a wide terminal the columns are Time, Command, Path and Status, plus Ran by when agent commands are shown; each run's session and duration are in the detail pane.

    The results title says which view you are in, counts in its units, and names the key that switches: Executions 1-50 of 558 · ^U group, or Commands 1-50 of 139 · ^U every run. The command you had selected stays selected across the switch, on whichever page it lands, and going back to every run selects its most recent run. If that command was deleted meanwhile, a message in the footer says so instead of putting another command under the cursor.

    Since 0.5.0 recall opens in Commands unless your config.toml says otherwise: set show_unique_by_default = false in its [search] section, or turn off Start in Commands View in suv settings, to open in Executions. A value already in your config — including one suv settings wrote when you saved it — is kept. suv search -u opens in Commands either way.

    Long commands and hidden whitespace

    A row too long for the list ends in …; the selected row wraps so every character of it is on screen. Because commands are grouped only by exact text, whitespace you could not otherwise see is drawn: · for a leading or trailing space (a long run shows its first markers and how many more, such as +4), ⇥ for each tab, ↵ for each line break, and · for any other non-space whitespace. Runs of spaces inside a command are kept. The markers change only what is drawn, not what is stored, what Enter puts on your prompt, or how commands are grouped.

    Inspect the exact text

    When a command holds anything that cannot be read off its text — a tab, a line break, an edge space, or a character that draws as nothing, such as a zero-width space, a bidi override or a byte-order mark — the detail pane adds a Raw line that spells it out with escapes (for example "printf·'a\t\tb'" or \u{200b}), with every space drawn as · so none can hide at a line break.

    Press Ctrl+V to open the same raw view for the highlighted command in a scrollable overlay, however long it is: every space drawn as ·, every hidden character escaped, a line per line break, and its length in characters and bytes. Scroll with the arrow keys or PageUp / PageDown; Enter or Esc closes it without accepting the command.

    Since 0.5.0 each query runs on a background thread with its own read-only connection. A keystroke that changes the query interrupts the search still running, and results that arrive for an older query are discarded. While a slow search runs, the results title shows searching…, and an empty list says Searching… rather than explaining an earlier query's empty result. Enter, navigation, paging, and mode or scope changes first wait for the results of what is typed now, so the command you accept always matches the query on screen. Esc leaves at once.

    The row between the search box and the results shows the current Scope, Match mode, whether Agents are shown, and the Rank (Smart or Recent), followed by a badge for each active filter. An active filter always stays visible: on a narrow terminal the Rank segment gives way first. The search box holds only what you typed; whether results are grouped is shown in the results title.

    The footer keeps to the core keys at any width — use (Enter), navigate, filter (Ctrl+F), detail (Tab), mode (Ctrl+X) and scope (Ctrl+P), plus quit and help. Press ? to list every shortcut; all of them work whether or not the footer shows them.

    Command-Line Flags

    You can pre-filter results before the TUI opens by passing flags:

    Flag Description Example
    -q / --query Pre-fill the search query suv search -q "docker build"
    -u / --unique Start in the Commands view even when your config opens Executions suv search -u
    --after Show commands after a date or relative time suv search --after "3 days ago"
    --before Show commands before a date or relative time suv search --before "2024-01-01"
    --tag Filter by session tag suv search --tag deploy
    --exit-code Filter by exit code (0 = success, 1+ = failure) suv search --exit-code 1
    --executor Filter by executor (e.g., claude-code, cursor, user) suv search --executor claude-code
    --here Only show commands run in the current directory suv search --here
    --field Search one field: command, cwd, session, or executor suv search --field cwd
    --failed Show only commands that exited non-zero suv search --failed
    --include-agents Include AI-agent / CI / script commands (hidden by default) suv search --include-agents

    Keyboard Shortcuts

    These shortcuts are available inside the search TUI:

    Key Action
    Type any text Substring search / filter results
    Up / Down Navigate through results
    Tab Toggle detail preview pane
    Enter Use: put the highlighted command on your prompt (from Ctrl+R) or print it (from suv search). It never runs the command.
    Esc Exit search without selecting, at once, even while a search is running
    Ctrl+X Cycle the matching mode (terms, literal, prefix, fuzzy)
    Ctrl+P / Ctrl+R Cycle the scope / reset it to all history
    Ctrl+S Toggle Smart mode (current-directory boost for typed queries; on by default)
    Ctrl+L Toggle directory filter (show only current directory)
    Ctrl+E Toggle failed-only filter (commands that exited non-zero)
    Ctrl+A Toggle showing AI-agent / CI / script commands (hidden by default)
    Ctrl+U Switch between Executions (every run) and Commands (identical commands grouped); the selected command stays selected
    Ctrl+V Inspect the highlighted command's exact text in a scrollable raw view (see Inspect the exact text)
    Ctrl+F Open filter panel (date, exit code, executor, tag)
    Ctrl+OToggle bookmarks-only results
    PageUp / PageDownMove the selection 10 rows up / down
    Home / EndFirst / last result on the current page
    Ctrl+B Toggle bookmark on the highlighted command
    Ctrl+N Add or edit a note on the highlighted command
    Ctrl+T Tag the current session
    Ctrl+Y Copy the highlighted command to clipboard
    Ctrl+D Delete the highlighted entry
    Ctrl+G Go to a specific page number
    Left / Right Previous / next page of results
    F1 / ? Show help overlay with all shortcuts (the footer shows only the core keys)

    Smart Mode

    Smart mode is on by default (context_boost = true under [search]). Press Ctrl+S to toggle it; the status row shows the current ranking in its Rank segment (Smart or Recent), and the selected command stays selected. When Smart mode is on:

    • For a typed query, entries whose recorded directory is exactly your current working directory get the directory boost described below. Commands run in subdirectories or parent directories are not boosted.
    • The directory column is highlighted for rows recorded in the current directory.

    With an empty query, results are listed newest first in both modes. Smart mode does not weigh how often you ran a command or whether it succeeded. To see only commands from the current directory instead of boosting them, use the directory filter (Ctrl+L or --here).

    How results are ranked

    When you type a query in the TUI, each candidate entry is scored and sorted by these keys, in order:

    1. Literal-token requirement. Entries where any typed word is missing as a literal substring are dropped, even if they would match as a fuzzy subsequence (for example, gco does not match git checkout).
    2. Match tier. Query as a prefix of the field, then the query as a contiguous substring, then all words in query order, then all words in any order. A better tier always ranks first, regardless of boosts.
    3. Boosted matcher score. Within a tier, entries are ordered by a fuzzy-matcher score (from the nucleo matcher) adjusted by:
      • Long-command penalty — fields longer than length_threshold characters (default 80) have their score scaled by √(threshold ÷ length).
      • Human boost — entries from a human terminal or with an unknown executor have their score raised by human_boost_percent (default 33%).
      • Directory boost — in Smart mode only, entries from exactly the current directory have their score raised by cwd_boost_percent (default 50%).
    4. Interactive tiebreak. On an equal score, commands from a terminal, an IDE terminal, or an unknown executor rank above agent, bot, CI, and script commands.

    Remaining ties keep the database order, newest first. The three scoring values can be changed in Settings. This ranking applies only to queries typed in the TUI; see the known limitation above for which entries are considered.

    Detail Preview Pane

    Press Tab to toggle the detail preview pane. When visible, it shows full metadata for the highlighted command, leading with where it ran and how it ended, so those are what you see when the pane has only a few rows below the results:

    • Full command text
    • Raw — only when the command holds whitespace or characters that cannot be read off its text; see Inspect the exact text
    • Path, Exit and Time — the working directory, exit code, and date and time of the run. In the Commands view these are the latest matching run's, labelled Last path, Last exit and Last run, followed by Runs, the number of runs that matched
    • Duration
    • Session ID and tag
    • Executor (user, claude-code, cursor, etc.)
    • Bookmark and note status

    This is useful when multiple similar commands appear in results and you need to identify the exact one you want.

    Vim Bindings

    Enable vim-style modal navigation with vim_mode = true in your config (suv settings → Search tab), or in config.toml:

    [search]
    vim_mode = true

    When enabled, the search TUI starts in Insert mode (typing searches as usual). Press Esc to switch to Normal mode for navigation:

    Key Normal Mode
    j / k Navigate down / up
    Ctrl+D / Ctrl+U Half-page scroll down / up
    g / G Jump to first / last entry
    h / l Previous / next page
    / or i Switch to Insert mode (search)
    Enter Use: put the command on your prompt (never runs it)
    Tab Toggle detail pane
    q or Esc Quit

    The current mode is shown in the footer as NORMAL or INSERT. All Ctrl+key shortcuts (filters, bookmarks, notes, etc.) work in both modes.

    Note: Ctrl+U and Ctrl+D only remap to half-page scroll in Normal mode. In Insert mode, they keep their original behavior (switching between Executions and Commands, and delete), which is why the results title offers ^U only outside Normal mode. All other Ctrl shortcuts work in both modes.

    Examples

    Find failed commands from the last 3 days

    suv search --exit-code 1 --after "3 days ago"

    Opens the search TUI pre-filtered to show only commands that exited with code 1, from the last 3 days.

    See what an AI agent ran in the current directory

    suv search --executor claude-code --here

    Filters to commands executed by Claude Code in your current working directory. Useful for reviewing what an AI agent did in a project.

    Search with a pre-filled query

    suv search -q "git rebase"

    Opens the TUI with "git rebase" already typed into the search box. The first list comes from a database query for that phrase across all recorded history, newest first.

    Start with identical commands grouped, whatever the config says

    suv search -u

    Opens in the Commands view — each distinct command text is one row, with when it last ran and how many runs matched — even if show_unique_by_default = false makes Executions your default. Press Ctrl+U to see every run instead.

    Filter by session tag

    suv search --tag deploy

    Shows only commands from sessions tagged "deploy". Tags can be applied with suv tag associate <name> or Ctrl+T in the search TUI.