# pikl-menu: Development Plan Implementation order, phase definitions, and the running list of ideas. The DESIGN.md is the source of truth for *what* pikl-menu is. This doc is the plan for *how and when* we build it. ## Principles - Get a working vertical slice before going wide on features - pikl-core stays rendering-agnostic. No GUI or TUI deps in the library. - Every feature gets tests in pikl-core before frontend work - Ship something usable early, iterate from real usage - Don't optimize until there's a reason to ## Phase 1: Core Loop (TUI) The minimum thing that works end-to-end. **Deliverables:** - pikl-core: Item store (accepts JSON lines on stdin, plain text fallback) - pikl-core: Basic fuzzy filter on label - pikl-core: Single selection, Enter to confirm, Escape to cancel - pikl-core: Event bus with on-select and on-cancel hooks (shell commands) - pikl-tui: ratatui list renderer - pikl (CLI): Reads stdin, opens TUI, emits selected item as JSON on stdout - Exit codes: 0 = selected, 1 = cancelled, 2 = error - CI: Strict clippy, fmt, tests on Linux + macOS **Done when:** `ls | pikl` works and prints the selected item. ## Phase 1.5: Action-fd (Headless Mode) Scriptable, non-interactive mode for integration tests and automation. Small enough to slot in before phase 2. It's about 100 lines of new code plus the binary orchestration for `show-ui`. **Deliverables:** - `--action-fd `: read action script from file descriptor N - Action protocol: plain text, one action per line (filter, move-up/down, confirm, cancel, etc.) - `show-ui` / `show-tui` / `show-gui` actions for headless-to-interactive handoff - Upfront validation pass: reject unknown actions, malformed args, actions after show-ui - `--stdin-timeout `: default 30s in action-fd mode, 0 in interactive mode - Default viewport height of 50 in headless mode - Binary integration tests: spawn pikl with piped stdin + action-fd, assert stdout **Done when:** `echo -e "hello\nworld" | pikl --action-fd 3` with `confirm` on fd 3 prints `"hello"` to stdout. ## Phase 2: Navigation & Filtering Make it feel like home for a vim user. The filter system is the real star here: strategy prefixes, pipeline chaining, incremental caching. **Implementation order:** 1. Mode system in core (Insert/Normal, Ctrl+N/Ctrl+E to switch) 2. Normal mode vim nav (j/k/gg/G/Ctrl+D/U/Ctrl+F/B) 3. `/` in normal mode enters insert mode with filter focused 4. Filter strategy engine (prefix parsing: `'`, `!`, `!'`, `/pattern/`, `!/pattern/`) 5. `fancy-regex` integration for the regex strategy 6. Filter pipeline (`|` chaining between stages, incremental caching) **Deliverables:** - Insert mode / normal mode (Ctrl+N to normal, Ctrl+E to insert) - Escape always cancels and exits, in any mode - Normal mode: j/k, gg, G, Ctrl+D/U, Ctrl+F/B - `/` in normal mode enters filter (insert) mode - `--start-mode normal` flag - Filter strategies via inline prefixes: fuzzy (default), exact (`'term`), inverse (`!term`, `!'term`), regex (`/pattern/`, `!/pattern/`) - fancy-regex integration (unlimited capture groups, lookaround) - Filter pipeline with `|`: each stage narrows the previous stage's output - Incremental filter caching: each stage caches item indices, only recomputes from the edited stage forward - Arrow keys to navigate within the filter text and edit earlier pipeline segments - `\|` escapes a literal pipe in the query - Case rules: fuzzy = smart case, exact = case-insensitive, regex = case-sensitive (use `(?i)` for insensitive) **Deferred to later:** - H/M/L (viewport-relative jumps): nice-to-have, not essential - Filter syntax highlighting in the input field: deferred to theming work **Done when:** You can navigate and filter a large list with vim muscle memory. `'log | !temp | /[0-9]+/` works as a pipeline. ## Phase 3: Structured I/O & Hooks The structured data pipeline. **Deliverables:** - JSON line input parsing (label, sublabel, meta, icon, group) - JSON output with action context - Full hook lifecycle: on-open, on-close, on-hover, on-select, on-cancel, on-filter - Hook debouncing - Bidirectional hooks (hook stdout modifies menu state) - `--format` template strings for display - Field filters (`meta.res:3840`) - Filter scoping (`--filter-fields`) **Done when:** The wallpaper picker use case works entirely through hooks and structured I/O. ## Phase 4: Multi-Select & Registers Power selection features. **Deliverables:** - Space to toggle select, V for visual line mode - Multi-select output (multiple JSON lines) - Named registers (`"a` through `"z`) - Marks (`m{a-z}`, `'{a-z}`) - `--multi` flag to enable multi-select mode **Done when:** You can select multiple items, store them in registers, and get them all in the output. ## Phase 5: Table Mode & CSV Columnar data display. **Deliverables:** - `--columns` flag for table layout - Auto-alignment - Column sorting keybinds - `--input-format csv` and `--input-format tsv` - Column-specific filtering **Done when:** `ps aux | pikl --input-format tsv --columns 1,10,2` renders a clean table. ## Phase 6: Sessions & IPC Persistence and external control. **Deliverables:** - `--session name` for state persistence - Session state: filter, scroll position, selections, marks, registers - Session history log file - Unix socket IPC while running - IPC commands: push/remove/update items, set filter, read selection, close - Protocol: newline-delimited JSON **Done when:** You can close and reopen a session and find your state intact. External scripts can push items into a running pikl instance. ## Phase 7: Streaming & Watched Sources Live, dynamic menus. **Deliverables:** - Async/streaming stdin (items arrive over time, list updates progressively) - Streaming output (on-hover events emitted to stdout) - `--watch path` for file/directory watching - `--watch-extensions` filter - notify crate integration (inotify on Linux, FSEvents on macOS) **Done when:** `find / -name '*.log' | pikl` populates progressively. A watched directory updates the list live. ## Phase 8: GUI Frontend (Wayland + X11) The graphical overlay. **Deliverables:** - pikl-gui crate with iced - Wayland: layer-shell overlay via iced_layershell - X11: override-redirect window or EWMH hints - Auto-detection of Wayland vs X11 vs fallback to TUI - `--mode gui` / `--mode tui` override - Theming (TOML-based, a few built-in themes) - Image/icon rendering in item list - Preview pane (text + images) **Done when:** pikl looks and feels like a native Wayland overlay with keyboard-first interaction. ## Phase 9: Drill-Down & Groups Hierarchical navigation. **Deliverables:** - `on-select` hook returning `{"action": "replace", "items": [...]}` for drill-down - Backspace / `h` in normal mode to go back - Navigation history stack - Item groups with headers - Tab to cycle groups - `za` to collapse/expand groups **Done when:** A file browser built on pikl-menu can navigate directories without spawning new processes. ## Open Design Notes - **Viewport cursor preservation on filter change.** When the filter narrows and the highlighted item is still in the result set, keep it highlighted (like fzf/rofi). When it's gone, fall back to the top. Needs the filter to report whether a specific original index survived the query, or the viewport to do a lookup after each filter pass. ## Future Ideas (Unscheduled) These are things we've talked about or thought of. No commitment, no order. - Lua scripting frontend (mlua + LuaJIT): stateful/ conditional automation, natural follow-on to action-fd and IPC. Lua runtime is just another frontend pushing Actions and subscribing to MenuEvents. Deliberately deferred until after IPC (phase 6) so the event/action API is battle-tested before exposing it to a scripting language. See "Scripting Ladder" in DESIGN.md. - WASM plugin system for custom filter strategies - `pcre2` feature flag for JIT-compiled regex - Frecency sorting (track selection frequency, boost common picks) - Manifest file format for reusable pikl configurations - Sixel / kitty graphics protocol support in TUI mode - Custom action keybinds (Ctrl+1 through Ctrl+9) with distinct exit codes - Accessibility / screen reader support - Sections as a first-class concept separate from groups - Network input sources (HTTP, WebSocket) - Shell completion generation (bash, zsh, fish) - Man page generation - Homebrew formula + AUR PKGBUILD - App launcher use case: global hotkey opens pikl as GUI overlay, fuzzy-filters PATH binaries, launches selection (optionally into a tmux session). Needs GUI frontend (phase 8) and frecency sorting. See `docs/use-cases/app-launcher.md`.