···11+# pick-iter: fast candidate generation + interactive multi-select + deep inspection
22+33+A design for combining `is-tree-scan-priority` and `is-tree-fuzzel-pipeline` into a single fluid workflow: generate tree candidates quickly, interactively pick the ones you care about, then inspect those in depth.
44+55+## The problem
66+77+`is-tree --all` against a large `~/src` is slow. It scans every directory, resolves jj bookmarks, fetches commit dates, and only then prints results. For interactive use you want the opposite:
88+99+1. **Fast candidate list** — just directory names, streamed as discovered.
1010+2. **Pick what matters** — multi-select from that list via fuzzel (or any picker).
1111+3. **Deep inspect the few** — run full is-tree with all columns on just the selected paths.
1212+1313+The current tooling makes this clunky because is-tree doesn't separate "discovery" from "inspection."
1414+1515+## The dream pipeline
1616+1717+```bash
1818+is-tree --scan | fuzzel --dmenu --multi | is-tree --format all
1919+```
2020+2121+Three stages, three processes, one pipe. Let's unpack what each stage needs.
2222+2323+## Stage 1: fast candidate generation
2424+2525+```bash
2626+is-tree --scan
2727+```
2828+2929+`--scan` is a new mode. It does the minimum work to determine that a directory is a tree (git or jj) and emits its path. No commit dates, no bookmark resolution, no remote queries. Just:
3030+3131+- readdir the parent
3232+- stat `.git` / `.jj` in each child
3333+- print matching paths, one per line
3434+3535+This maps onto `is-tree-scan-priority` — but instead of "priority ordering," it's "stream immediately, skip everything expensive." The key insight: discovery is cheap, inspection is expensive. `--scan` only does discovery.
3636+3737+### Streaming
3838+3939+`--scan` should stream: print each path as it's found, don't buffer. This lets fuzzel start showing candidates before the scan finishes. A large `~/src` with hundreds of entries becomes interactive from the first few results.
4040+4141+### What about type info?
4242+4343+Emitting bare paths works, but we could optionally include the status:
4444+4545+```
4646+jj ~/src/is-tree
4747+git ~/src/compfuzor
4848+```
4949+5050+This lets fuzzel show context without slowing down discovery. The status is free — we already check `.jj`/`.git` to classify. A `--scan --format "{status} {directory}"` or `--scan -s` flag could control this. But for the pipeline use case, bare paths are the default since they pipe directly into is-tree positional args.
5151+5252+## Stage 2: interactive multi-select
5353+5454+```bash
5555+fuzzel --dmenu --multi
5656+```
5757+5858+This is existing fuzzel behavior. It reads lines from stdin, presents a searchable multi-select UI, and emits selected lines to stdout. No work for us.
5959+6060+For terminal-only environments, alternatives work identically:
6161+6262+```bash
6363+is-tree --scan | fzf --multi | is-tree --format all
6464+is-tree --scan | sk --multi | is-tree --format all
6565+```
6666+6767+The pipeline is picker-agnostic.
6868+6969+## Stage 3: deep inspection
7070+7171+```bash
7272+is-tree --format all
7373+```
7474+7575+This is where the selected paths come in as positional arguments. is-tree already supports this:
7676+7777+```bash
7878+is-tree ~/src/is-tree ~/src/compfuzor --format all
7979+```
8080+8181+For a handful of selected paths, this is fast — full column resolution on 5-10 trees instead of 500.
8282+8383+## Does is-tree need changes?
8484+8585+### What already works
8686+8787+- **Positional args**: `is-tree path1 path2 path3` already works. The pipe `fuzzel | xargs is-tree` would work today if fuzzel emitted paths.
8888+- **`--format all`**: already supported.
8989+- **Discovery**: the core detection logic exists.
9090+9191+### What doesn't work yet
9292+9393+1. **No streaming/fast-scan mode.** `is-tree --all` does full inspection on every directory before printing anything. We need `--scan` (or similar) that emits paths immediately with minimal work.
9494+9595+2. **stdin as positional input.** The pipeline `fuzzel | is-tree` doesn't work because is-tree reads positional args from argv, not stdin. We'd need either:
9696+ - `xargs` glue: `is-tree --scan | fuzzel --multi | xargs is-tree --format all` — works today but xargs breaks on paths with spaces unless you use `-d '\n'`.
9797+ - A `--stdin` flag on is-tree to read paths from stdin, one per line. This is cleaner:
9898+ ```bash
9999+ is-tree --scan | fuzzel --multi | is-tree --stdin --format all
100100+ ```
101101+ - Or: detect piped stdin automatically (if stdin is a pipe and no positional args given, read paths from stdin). This is the most ergonomic — zero extra flags.
102102+103103+3. **Recurse-on-selected.** Once you've picked trees, you might want to go deeper — per-file stats inside those trees. That's `is-tree-per-file-stats`, which would compose naturally:
104104+ ```bash
105105+ is-tree --scan | fuzzel --multi | is-tree --stdin --files --format all
106106+ ```
107107+108108+### Recommendation: `--stdin` (or auto-detect)
109109+110110+The smallest change with the biggest payoff:
111111+112112+- Add stdin reading when no positional args are given and stdin is a pipe (isatty check).
113113+- Or an explicit `--stdin` flag if implicit behavior feels too magical.
114114+115115+This turns the three-stage pipeline into a first-class workflow without adding subcommands or restructuring is-tree.
116116+117117+## The full pipeline, revised
118118+119119+With `--scan` + stdin support:
120120+121121+```bash
122122+# pick trees, inspect deeply
123123+is-tree --scan | fuzzel --dmenu --multi | is-tree --format all
124124+125125+# pick trees, see per-file staleness
126126+is-tree --scan | fuzzel --dmenu --multi | is-tree --stdin --files --older-than 30d
127127+128128+# pick trees, push them
129129+is-tree --scan | fuzzel --dmenu --multi | reforrest push
130130+131131+# scoped to a subdirectory
132132+is-tree --scan ~/src | fuzzel --dmenu --multi | is-tree --format all
133133+```
134134+135135+## Design decisions to resolve
136136+137137+### `--scan` output format
138138+139139+Default: bare paths. Optionally include status with a flag. Rationale: bare paths are universally pipeable. Anything else breaks composability.
140140+141141+```bash
142142+is-tree --scan # one path per line
143143+is-tree --scan --show-type # "jj ~/src/is-tree" — useful for visual scanning but not for piping back
144144+```
145145+146146+### `--scan` vs `--all --format "{directory}"`
147147+148148+These overlap. `--all --format "{directory}"` already emits just paths. The difference is:
149149+150150+- `--all --format "{directory}"` does full inspection on every tree, then strips output to just the path column. Slow.
151151+- `--scan` skips inspection entirely. Fast.
152152+153153+We could make `--all --format "{directory}"` fast by detecting that only `directory` is requested and short-circuiting inspection. But `--scan` is a clearer intent signal and doesn't require format parsing to optimize.
154154+155155+**Recommendation**: add `--scan` as a distinct fast-path. It's self-documenting and unambiguous.
156156+157157+### Per-file recursion after picking
158158+159159+The `--files` flag (from `is-tree-per-file-stats`) would make the final `is-tree` call recurse into each selected tree and report per-file stats. This is where the pipeline really shines: you pick 3 stale projects from hundreds, then immediately see which files in those projects are gathering dust.
160160+161161+```bash
162162+is-tree --scan | fuzzel --dmenu --multi | is-tree --format all --files --sort age-
163163+```
164164+165165+### Session state
166166+167167+Could we persist a "pick session" — e.g., a temporary file with selected paths — so you can re-inspect without re-picking?
168168+169169+```bash
170170+is-tree --scan | fuzzel --multi | tee /tmp/picked | is-tree --format all
171171+# later:
172172+is-tree --stdin --format all --files < /tmp/picked
173173+```
174174+175175+This works with plain Unix tooling. No special session mechanism needed.
176176+177177+## Summary of required is-tree changes
178178+179179+| Change | Purpose | Scope |
180180+|--------|---------|-------|
181181+| `--scan` flag | Fast path-only discovery, streamed output | New flag, reuses detection logic, skips inspection |
182182+| Stdin path reading | Accept selected paths from pipe | Auto-detect (isatty) or explicit `--stdin` flag |
183183+| (future) `--files` flag | Per-file stats on selected trees | Separate ticket (`is-tree-per-file-stats`) |
184184+185185+Two flags. That's it. The rest is Unix.