From 1ed07e2e4473b91c669c062bbfef6bb499f7d2b7 Mon Sep 17 00:00:00 2001 From: t Date: Sat, 4 Jul 2026 08:46:35 -0600 Subject: docs: todos, new "tui gaps" project, AGENTS.md modification --- docs/cli-tui-gaps.md | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++ docs/todos.md | 2 +- 2 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 docs/cli-tui-gaps.md (limited to 'docs') diff --git a/docs/cli-tui-gaps.md b/docs/cli-tui-gaps.md new file mode 100644 index 0000000..6791941 --- /dev/null +++ b/docs/cli-tui-gaps.md @@ -0,0 +1,321 @@ +# panto CLI/TUI: gaps and proposals + +Survey of the current CLI/TUI surface (2026-07-03) and what to do about it. + +Framing first, because it decides everything below: panto's job is not to +do everything, it's to make everything possible. It is a minimal +interactive shell over libpanto plus a powerful Lua extension API, in the +spirit of pi (https://pi.dev) — users build their own ideal agent on top, +and that agent need not be a coding agent at all (the shipped coding tools +are themselves deny-able Lua extensions). So every "gap" lands in one of +three buckets: + +- **Core** — makes the shell itself usable and scriptable. Baseline, + not coding-specific. Ships in Zig (and should generally also be + reachable from Lua). +- **Extension API** — core shouldn't do the thing; core should make the + thing *buildable*. New API surfaces are co-designed with Travis before + building. +- **Not ours** — coding-agent conveniences. Belongs in `../panto-agent` + or other out-of-tree extensions; listed only so we stop re-proposing it. + +Priorities within a bucket: **P0** = bug or table-stakes, **P1** = next +tranche, **P2** = deliberate deferral. + +--- + +## 1. Bugs (core, P0, all small) + +Fix regardless of anything else below. + +1. **Duplicate short session IDs.** `panto sessions` shows `id[0..8]` + (`src/subcommand.zig:374`), but IDs are UUIDv7 and the first 8 hex chars + are the top 32 bits of the millisecond timestamp — no randomness until + char 15. Two sessions created within ~65 s in one project display + identical short IDs. Fix: shortest-unambiguous prefix per listing + (extend past 8 while any two collide). + +2. **`AmbiguousSessionId` exits silently.** `--resume ` matching + two files propagates the error to a bare `exit(1)` at + `src/main.zig:282-283` — no message. Only `SessionNotFound` gets a tidy + error (`main.zig:724-727`). Fix: print the candidates and exit. + +3. **`--resume` (bare) and `panto sessions` disagree on "most recent".** + `findMostRecentSession` takes the lexicographic filename max = + newest-*created* (`file_system_jsonl_store.zig:981-1010`); the listing + sorts by newest-*modified*. Fix: make `latest()` use `modified`. + +4. **`trimCreated` doesn't trim.** Promises `YYYY-MM-DD HH:MM`, returns + `iso[0..16]` with the `T` intact (`src/subcommand.zig:386-394`). + +5. **`--resume` flag peeking can't rewind.** A `-`-leading token after + `--resume` is warned-and-dropped instead of parsed as its own flag + (`main.zig:676-688`). Becomes real once a second agent flag exists (§2). + +6. **Base config template comment says `[tools]`** where the code reads + `[extensions]` (`luarocks_runtime.zig:460` vs `config_file.zig:201`). + +--- + +## 2. Core: command-line flags + +Today the entire agent-mode flag surface is `--resume []` +(`main.zig:658-697`). For an "interactive agent SDK" the bar is: launch it, +point it at a model, script it, resume it. That's about five flags. + +### P0 + +- **`-p, --print ` — one-shot non-interactive mode.** One agent + turn (tools and all), text to stdout, meaningful exit code; prompt from + the arg or stdin when piped. panto currently *requires* a tty + (`main.zig:494-503`) and cannot be scripted at all — the biggest gap in + the product. Composes with `--resume` for headless continuation. Pairs + with libpanto's "one-shot simple API" todo (`docs/todos.md:12`). +- **`-m, --model `.** Already anticipated: + `selectModel(model_override)` exists and `main.zig:227` passes `null`. + Wire it through; accept a bare alias when unambiguous. +- **`--version`.** Embed at build time; print `panto `. +- **Unknown flags error, don't warn-and-continue** (`main.zig:686,693`). + A typo silently launching a TUI is how scripts hang. + +### P1 + +- **`-c, --continue`** — ergonomic alias for bare `--resume`. +- **`--no-extensions`** — skip the Lua runtime: fast `-p` in CI, and the + escape hatch when an extension breaks startup. Given that even the + shipped tools are extensions, define semantics as "built-ins only, + policy-denied everything else". +- **`--effort `** — same pattern as `--model`. + +### Skip + +- `--config ` — the 4-layer TOML merge already covers it. +- `--output-format json` for `-p` — wait for a real consumer. +- `--cwd` — `cd && panto`. + +### `panto sessions` output (P0) + +Currently `<8-char-id> messages`, while the useful +fields (`last_user_message`, `model`, `modified`) are computed by +`buildFileInfo` and discarded. Proposal: + +``` +ID MODIFIED MSGS MODEL LAST MESSAGE +0197c2a4 2026-07-01 14:32 18 anthropic:sonnet fix the segfault in tui_engine when… +0197b1f0 2026-06-30 09:15 4 openai:gpt add a --version flag +``` + +Sort and *show* by modified; shortest-unique IDs (§1.1); truncate last +message to width; plain aligned columns, no box-drawing. Print the sessions +dir path as the last line so the storage is discoverable. Keep resume as a +flag (it composes with `-p`/`-m`; `sessions` stays list-only) — the real +contract is that listed IDs paste into `--resume` without ambiguity. + +--- + +## 3. Core: slash commands + +Current inventory: **`/compact`** (`src/compaction.zig:13`). The framework +(registry, Lua `panto.ext.register_command`, capture-to-transcript, error +rendering) is complete — and mostly-empty is correct for panto. But a shell +whose product *is* its extension points still has to be self-describing and +steerable. These are baseline and coding-agnostic, so they're core Zig; +each should also be achievable from Lua via `panto.ext.agent` (the +sufficiency audit in §7). + +### P0 + +- **`/help`** — registered commands (`Registry.list()` exists solely for + this and tab completion) plus the key bindings. Today nothing in the + product reveals that `/compact` or Ctrl+G exist. For an + extensions-first tool, discoverability of what's currently loaded is not + a convenience — it's how users see their own extensions. +- **`/quit`** — trivial; the only exit today is Ctrl+C/D. +- **`/model [provider:alias]`**, **`/reasoning [level]`** — no arg opens + the existing selector; with arg sets directly. Makes the selectors + discoverable and terminal-agnostic (see the Ctrl+M problem, §4). +- **`/new`** — fresh session in place; today you quit and relaunch. + +### P1 + +- **`/resume []`** — in-TUI session switcher; no arg opens a fuzzy + `Selector` over sessions (short-id + modified + last message rows). +- **`/status`** — provider, model, reasoning, session id, message count, + context used vs window. All already in `command.Context` or computable. + +### Completion and typeahead (P1) + +The fuzzy machinery already exists and is good — the model selector does +case-insensitive subsequence filtering with Ctrl+N/P + Enter. Extend the +same feel to the input box (`docs/todos.md:22` tracks this): + +- **Leading-`/` typeahead**: when the buffer starts with `/`, surface a + live-filtered command list (from `Registry.list()`, which exists for + exactly this) in the same selector idiom; Tab or Enter-on-selection + completes. Registered Lua commands appear automatically — this is + another discoverability channel for extensions, like `/help`. +- **Tab completes file/dir names from cwd** anywhere in the buffer: + complete the token under the cursor against the filesystem, common-prefix + first, selector on ambiguity. Coding-agnostic (paths are universal). +- Later: **per-command argument completion** declared by the command + (e.g. `/model` completing `provider:alias`, Lua commands supplying a + completion function). That's an extension API surface — §7. + +--- + +## 4. Core: key bindings + +Input box editing is solid (word motion, Ctrl+A/E/U/W, Shift+Enter +multiline, bracketed paste). Gaps: + +### P0 + +- **Input history (Up/Down recall).** Decoded and dropped today + (`tui_components.zig:1207`). Up at buffer-top / Down at buffer-bottom + navigate history so multiline arrow-editing still works; in-memory + per-run is enough to start. +- **Idle Escape clears the input buffer.** Makes Escape uniformly "cancel + the thing in progress" (it already interrupts turns and closes + selectors). +- **Fix Ctrl+M.** Ctrl+M *is* carriage return; the model-selector binding + only exists on Kitty-protocol terminals and silently vanishes on plain + xterm/tmux. With `/model` (§3) as the discoverable path, move the chord + to a legacy-safe key (Ctrl+T is free) or accept slash-only on legacy + terminals — either way `/help` documents reality. + +### P1 + +- **Ctrl+L** — clear/redraw (engine already has full-redraw machinery). +- **Buffer typed input during a turn** and restore it to the input box + after; full mid-turn steering waits on libpanto queueing + (`docs/todos.md:15`). +- **Dedup the chord dispatch**: Ctrl+O/M/R are re-implemented in both + `handleBytes` (`tui_app.zig:1801-1842`) and `pumpTurnKeys` + (`tui_app.zig:2286-2304`). One `appChord(key) -> ?Action` both call. + This is also the seam the keybinding extension API (§7) slots into. + +### Deliberate non-features + +- Kill-ring/yank, undo — already deferred in-code ("plan P2"); agreed. +- In-app transcript scrolling — engine delegates to native terminal + scrollback by design (`tui_engine.zig:36-42`); keep. + +--- + +## 5. Core: config.toml settings + +The `[defaults]`/`[compaction]`/`[extensions]`/`[providers]`/`[auth]` +sections cover the agent; the TUI itself has zero settings. A halfway +decent agent TUI supports at least: + +### P1 + +- **`[defaults] reasoning = ""`** — today reasoning comes only from + models.toml per-alias or the Ctrl+R selector; a session default belongs + next to `defaults.model`. +- **`[tui] editor = "..."`** — Ctrl+G honors only `$EDITOR`; a config + override is the conventional courtesy. +- **`[tui] tools_collapsed = true|false`** — the Ctrl+O collapse state's + starting value. +- **`[tui] theme`** — the palette is deliberately comptime-fixed today + (`tui_theme.zig:5-6` says centralization, not theming). A minimal + version: named color overrides for the existing `StyleName` slots. + P1 only if cheap; a full theming system is P2 at best. + +### Skip + +- Keymap section — subsumed by the keybinding extension API (§7). +- Footer layout config — subsumed by the footer segment API (§7). +- Anything per-command/per-tool — that's extension config, which + extensions can already read themselves (Lua reads files). + +--- + +## 6. Core: the footer + +Today the footer is one dim line: `provider:alias (reasoning)`, latest +context tokens, session tokens, session cost (`tui_components.zig:1533`, +all pushed from Zig via `setModel`/`setContextTokens`/...). Worth adding: + +### P1 + +- **Context as a fraction, not a raw count.** `12.3k ctx` is meaningless + without the window; models.toml already has `context_window`. Show + `12.3k/200k ctx` or a percentage — this is the number that tells you + when compaction looms, arguably the footer's whole job. +- **Session short-id** — pairs with `/status` and `panto sessions`; makes + "which session am I in" free. +- **Transient key-hint slot** — e.g. `esc interrupt` while a turn runs. + One hint at a time, context-dependent; not a permanent hint bar. + +### P2 / skip + +- git branch, cwd — coding/shell-flavored and knowable from the terminal; + an extension can add these once the segment API (§7) exists. Skip in + core. + +--- + +## 7. Extension API gaps (make it possible) + +The survey surfaced these as missing Lua surfaces. Per AGENTS.md, each gets +co-designed before building — this list is scope, not spec. + +- **Keybinding registration.** Wanted: extensions can bind chords to Lua + handlers (and presumably rebind/shadow core ones). Blocked on the + `appChord` central dispatch (§4) existing first. Design questions for + the co-design pass: conflict policy vs core chords, per-context bindings + (idle vs during-turn vs selector), and whether declared bindings + auto-appear in `/help`. +- **Footer segments.** The footer is entirely Zig-fed today; extensions + have no way to add a readout (git branch, active skill, queue depth). + Likely shape: register a segment that returns a short string, repainted + on demand — rhymes with the existing screen-component API. +- **Completion providers.** Per-command argument completion for Lua slash + commands (§3): a command optionally supplies a completion function. +- **Session store access** from Lua (list/resolve/load). Needed for an + extension to build its own `/resume`-like or archival behaviors; today + sessions are invisible to extensions. +- **Selector/prompt UI for extensions.** TUI screen components are done + (`docs/todos.md:31`); a fuzzy-pick-from-list primitive is the missing + interactive piece extensions keep needing (model pickers, skill pickers, + session pickers all rhyme). + +Not a gap (previously misreported here): the current agent and +conversation **are** exposed — `panto.ext.agent` wraps the live session +agent with the full method surface (`lua_runtime.zig:219-242`), and the +conversation hangs off it. What's worth auditing instead is whether that +surface is *sufficient* for §3-parity from Lua: model/config switching, +starting a fresh session, reading usage/config for a `/status`-alike. + +--- + +## 8. Not ours (so we stop re-proposing it) + +- **`/usage`, `/cost`** — buildable today-ish from the Lua usage-metrics + API + models.toml pricing; panto-agent material. +- **`/init`, `/review`, `/pr`, rules/skills injection** — coding-agent + features; panto-agent already owns this space (`agent.rules`, + `agent.skill`). +- **`/undo` / checkpointing** — real design work and coding-flavored; + out-of-tree when someone wants it. +- **User keymap config file** — subsumed by the keybinding extension API + (§7); a TOML keymap section can be revisited if non-extension users ask. + +--- + +## 9. Sequencing + +1. §1 bug fixes + `panto sessions` output + shortest-unique IDs — one PR, + pure fixes. +2. `--model`, `--version`, strict flag parsing — small PR. +3. `-p/--print` — the headline; with libpanto's one-shot todo or a thin + plain-text presenter over the existing loop. +4. Slash commands P0 (`/help`, `/quit`, `/model`, `/reasoning`, `/new`). +5. Keybindings P0 (history, idle-Escape, Ctrl+M move) + `appChord` dedup. +6. Footer P1 (context fraction, session id) + config.toml `[defaults] + reasoning` / `[tui]` basics. +7. `/resume` switcher, `/status`, completion/typeahead (§3). +8. Extension API co-design round: keybindings, footer segments, completion + providers, session store, selector primitive (§7) — then panto-agent + picks up §8. diff --git a/docs/todos.md b/docs/todos.md index 72b2d4d..96a5d86 100644 --- a/docs/todos.md +++ b/docs/todos.md @@ -25,7 +25,7 @@ - [ ] additional lua extension API - [x] Agent objects - [x] Conversation objects - - [ ] the current agent, conversation + - [x] the current agent, conversation (`panto.ext.agent`) - [x] system prompt - [x] usage metrics - [x] tui screen components -- cgit v1.3