← all lessons

llm · 2026-04-27 · bashfzfshelltui

fzf execute+reload pattern

The idea

fzf is usually thought of as a one-shot fuzzy picker — show a list, return the chosen line. But its --bind flag lets you attach actions to keys, and two of those actions — execute (run a shell command) and reload (regenerate the list) — can be chained with +. That turns fzf into a full interactive TUI: keystroke runs a command that mutates external state, then the list refreshes to reflect the new state, all without exiting fzf.

The trick is that the script becomes recursive: the fzf process calls itself (via subcommands like list and toggle) to query and mutate state. Your script is both the orchestrator and the worker.

How it shows up

The skill manager you just built uses exactly this:

"$self" list | fzf \
    --bind="enter:execute-silent($self toggle {2})+reload($self list)" \
    --preview="$self preview {2}"

{2} is fzf's field-extraction syntax — the second whitespace-delimited token of the highlighted line. execute-silent runs the toggle without taking over the terminal; reload re-runs list and replaces the visible items in place.

Read more

Exercises

  1. Inline counter — write a one-shot script that shows a list 1..5, and binds enter to execute-silent(echo {} >> /tmp/picks)+reload(cat /tmp/picks). Watch the list grow as you press enter on items. Done when: pressing enter three times leaves three lines visible in the fzf list and three matching lines in /tmp/picks.
  2. Field extraction — modify bin/manage-skills.sh to also show each skill's description on the same line (e.g. [x] name — desc). Confirm {2} still extracts the name correctly, then break it on purpose by switching to {1} and observe the failure. Done when: you can articulate why {2} works for [x] name ... but {1} does not.
  3. Reload from a different source — add a key binding ctrl-r that reloads from a different command (e.g. ls ~/.claude/skills instead of the script's list). Toggle between the two views with the change-list action. Done when: ctrl-r swaps the visible list to the raw ~/.claude/skills/ contents without restarting fzf.