`fx` automates the `[LEARN] ... Enter a fix:` prompt in `f()` by gathering
candidate fixes from a directory of small, pluggable scripts and letting
you pick one (or auto-picking) before it's piped into `f`'s stdin.
**Zero changes to `../../src/f.sh`.**`f()`'s `read -r n` already doesn't
care whether that line comes from a human or a program — `fx` just
decides what to type there.
## Usage
```sh
. ../../src/f.sh
. fx.sh
fx some-command --that --might --fail
```
Set `FX_AUTO=1` to skip the picker and take the top-ranked candidate
automatically. Without it, `fx` uses `fzf` if installed, or a plain
numbered prompt otherwise.
## Default sources (`sources.d/`, run in filename order)
| File | What it offers |
|---|---|
| `10-known.sh` | Fixes already taught for a command that *starts* the same way, since `f()`'s own lookup only matches the exact string. |
| `20-history.sh` | The closest-looking command you've actually run before, read from `$HISTFILE`. |
| `30-selfdiag.sh` | Re-runs the command once, and if the tool's own error output suggests a corrected invocation (git's `--set-upstream` hint, etc.), emits a **function that re-derives the suggestion live on every future call** — not a frozen snapshot. This distinction matters: an earlier version of this source cached the literal suggested line and it silently broke on the second branch it saw (`git ls-remote` showed the second branch never got pushed). Re-diagnosing on every call is what makes one taught fix generalize correctly. |
| `40-pathfuzzy.sh` | If the first word isn't a real command, offers a **function** (not an alias — aliases don't expand in non-interactive shells without `shopt -s expand_aliases`) wrapping the closest-spelled real command, using transposition-aware edit distance so `gti` scores closer to `git` than to unrelated same-length commands like `ftp`. |
| `50-thefuck.sh` | Bridges to `thefuck --yes`, if installed, as one more opinion. Note `--yes` executes its own suggestion, so this candidate is often already-applied by the time you see it. Wrapped in `timeout 5` — fuzz-testing found it hanging past 3s on a majority of unmatched inputs with no fast-fail path of its own. |
| `70-local-llm.sh` | Off by default (no-ops unless a local Ollama or LM Studio server responds on its usual port). The one source with real reasoning capability, for failures none of the deterministic sources above can characterize — see "Known gaps" below for a concrete real-world case. |
| `80-remote-api.sh` | Off by default (no-ops unless `FX_REMOTE_API_URL`/`KEY`/`MODEL` are all set). Same reasoning capability as `70-local-llm.sh`, over a paid remote API instead — the last-resort tier, both in cost and in filename order. |