AI CLI Framework Pairing
AI CLI applications inherit their cursor control patterns from TUI frameworks.Pattern Inheritance Model
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ HOW AI CLIs GET THEIR RENDERING PATTERN │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ AI CLI applications do not implement cursor control directly. │
│ They inherit escape sequence emission from their TUI framework. │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ TUI Framework AI CLI Application │ │
│ │ ────────────── ────────────────── │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌────────────────────┐ │ │
│ │ │ │ │ │ │ │
│ │ │ Cursor Control │───────-->│ Inherits pattern │ │ │
│ │ │ Implementation │ │ automatically │ │ │
│ │ │ │ │ │ │ │
│ │ └─────────────────┘ └────────────────────┘ │ │
│ │ │ │
│ │ Framework handles: CLI focuses on: │ │
│ │ - Cursor hide/show - LLM API calls │ │
│ │ - Screen clearing - User interaction │ │
│ │ - Text rendering - Business logic │ │
│ │ - Color output - Response streaming │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ Result: AI CLI gets cursor pattern "for free" via framework. │
│ │
└───────────────────────────────────────────────────────────────────────┘
Ecosystem Mapping
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ LANGUAGE ECOSYSTEM PAIRINGS │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ TypeScript Ecosystem │
│ ════════════════════ │
│ │
│ ┌────────────────┐ │
│ │ Ink │ │
│ │ (React for CLI)│ │
│ └───────┬────────┘ │
│ │ │
│ ├─────────> Claude Code (Anthropic) │
│ │ │
│ └─────────> Gemini CLI (Google, Ink fork) │
│ │
│ Python Ecosystem │
│ ════════════════ │
│ │
│ ┌────────────────┐ │
│ │ Rich │ │
│ │ (Console lib) │ │
│ └───────┬────────┘ │
│ │ │
│ ├─────────> Aider (paul-gauthier) │
│ │ │
│ └─────────> Open Interpreter (+ yaspin) │
│ │
│ Rust Ecosystem │
│ ══════════════ │
│ │
│ ┌────────────────┐ <── Low-level backend │
│ │ Crossterm │ │
│ │ (Terminal API) │ │
│ └───────┬────────┘ │
│ │ │
│ ┌───────┴────────┐ <── High-level TUI │
│ │ Ratatui │ │
│ │ (TUI widgets) │ │
│ └───────┬────────┘ │
│ │ │
│ ├─────────> Codex CLI (OpenAI) - Uses BSU/ESU │
│ │ │
│ └─────────> Kiro CLI (AWS) - Cursor only │
│ │
│ Go Ecosystem │
│ ════════════ │
│ │
│ ┌────────────────┐ │
│ │ BubbleTea │ │
│ │ (Elm-style TUI)│ │
│ └───────┬────────┘ │
│ │ │
│ └─────────> (Future AI CLIs) │
│ Cursor pattern ready │
│ │
└───────────────────────────────────────────────────────────────────────┘
TypeScript: Ink Framework
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ INK: REACT FOR THE COMMAND LINE │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ Ink uses React's component model for terminal UIs. │
│ Cursor control is handled via cli-cursor package. │
│ │
│ Render Cycle: │
│ ───────────── │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1. render() called │ │
│ │ │ │ │
│ │ v │ │
│ │ 2. cli-cursor.hide() --> cursor hide escape │ │
│ │ │ │ │
│ │ v │ │
│ │ 3. Build output string │ │
│ │ │ │ │
│ │ v │ │
│ │ 4. Write to stdout │ │
│ │ │ │ │
│ │ v │ │
│ │ 5. cli-cursor.show() --> cursor show escape │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ AI CLIs using Ink: │
│ ────────────────── │
│ │
│ - Claude Code: Standard Ink usage │
│ + Also adds conditional BSU/ESU via terminal capability check │
│ + Dual-mode: cursor always, BSU/ESU when supported │
│ │
│ - Gemini CLI: Forked Ink with modifications │
│ + Uses alternate screen buffer │
│ + Cursor pattern still present from Ink base │
│ │
└───────────────────────────────────────────────────────────────────────┘
Python: Rich Framework
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ RICH: PYTHON CONSOLE LIBRARY │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ Rich provides Live display context for dynamic content. │
│ Cursor is hidden during Live context to prevent flicker. │
│ │
│ Live Context Pattern: │
│ ───────────────────── │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ with Live(renderable) as live: │ │
│ │ │ │ │
│ │ ├── __enter__() │ │
│ │ │ │ │ │
│ │ │ └── hide_cursor() --> cursor hide │ │
│ │ │ │ │
│ │ ├── live.update(new_content) │ │
│ │ │ │ │ │
│ │ │ └── refresh() --> clear + write │ │
│ │ │ │ │
│ │ └── __exit__() │ │
│ │ │ │ │
│ │ └── show_cursor() --> cursor show │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ AI CLIs using Rich: │
│ ─────────────────── │
│ │
│ - Aider: Uses Rich Console and Live for streaming │
│ + Markdown rendering via Rich │
│ + Progress bars via Rich │
│ │
│ - Open Interpreter: Uses Rich + yaspin │
│ + Rich for output formatting │
│ + yaspin for spinner (also emits cursor hide/show) │
│ + Dual source, same pattern │
│ │
└───────────────────────────────────────────────────────────────────────┘
Rust: Ratatui/Crossterm
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ RUST ECOSYSTEM: TWO-LAYER ARCHITECTURE │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ Rust terminal apps typically use two layers: │
│ - Crossterm: Low-level terminal backend │
│ - Ratatui: High-level TUI framework │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ Crossterm (Terminal Backend) │ │ │
│ │ │ ───────────────────────────────── │ │ │
│ │ │ │ │ │
│ │ │ Cursor hide/show (cursor::Hide, cursor::Show) │ │ │
│ │ │ BSU/ESU Mode 2026 (begin_synchronized_update) │ │ │
│ │ │ Terminal modes (alternate screen, raw mode) │ │ │
│ │ │ Event handling (keyboard, mouse) │ │ │
│ │ │ │ │ │
│ │ │ BSU/ESU API available but NOT emitted by default │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ │ ^ │ │
│ │ │ uses │ │
│ │ ┌──────────────────────┴───────────────────────────────┐ │ │
│ │ │ Ratatui (TUI Framework) │ │ │
│ │ │ ─────────────────────────── │ │ │
│ │ │ │ │ │
│ │ │ Widgets (list, table, paragraph, etc.) │ │ │
│ │ │ Layout system │ │ │
│ │ │ Double buffering │ │ │
│ │ │ Cursor hide on enter, show on exit │ │ │
│ │ │ │ │ │
│ │ │ Does NOT emit BSU/ESU by default │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ Critical Finding: Support != Usage │
│ ─────────────────────────────────── │
│ │
│ Crossterm PROVIDES BSU/ESU API. │
│ Ratatui does NOT EMIT BSU/ESU by default. │
│ Application must explicitly wrap draw() calls. │
│ │
└───────────────────────────────────────────────────────────────────────┘
Rust AI CLIs: Divergent Behavior
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ CODEX CLI VS KIRO CLI: SAME FRAMEWORK, DIFFERENT CHOICES │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ Both use Ratatui + Crossterm. Different BSU/ESU decisions. │
│ │
│ Codex CLI (OpenAI): │
│ ═══════════════════ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ // Explicit BSU/ESU wrapper │ │
│ │ │ │
│ │ draw_frame() { │ │
│ │ begin_synchronized_update // BSU │ │
│ │ terminal.draw(frame) // Ratatui rendering │ │
│ │ end_synchronized_update // ESU │ │
│ │ } │ │
│ │ │ │
│ │ Result: Emits both BSU/ESU AND cursor pattern │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ Kiro CLI (AWS): │
│ ═══════════════ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ // Standard Ratatui usage, no BSU/ESU wrapper │ │
│ │ │ │
│ │ draw_frame() { │ │
│ │ terminal.draw(frame) // Ratatui rendering │ │
│ │ } │ │
│ │ │ │
│ │ Result: Emits cursor pattern only (via Ratatui default) │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ Lesson: Framework capability does not guarantee application usage. │
│ MonoTerm must detect actual output, not assume. │
│ │
└───────────────────────────────────────────────────────────────────────┘
Go: BubbleTea Framework
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ BUBBLETEA: ELM ARCHITECTURE FOR TERMINAL │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ BubbleTea uses Elm-style Model-Update-View architecture. │
│ Rendering is framerate-based (60 FPS default). │
│ │
│ Render Cycle: │
│ ───────────── │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Model --> Update --> View --> Render │ │
│ │ │ │ │ │ │
│ │ │ │ ├── hideCursor() │ │
│ │ │ │ ├── write content │ │
│ │ │ │ └── showCursor() │ │
│ │ │ │ │ │
│ │ <───────────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ BSU/ESU Status: │
│ ─────────────── │
│ │
│ BubbleTea does NOT implement BSU/ESU. │
│ Relies on framerate control + cursor pattern for smooth output. │
│ │
│ AI CLI Potential: │
│ ───────────────── │
│ │
│ No major AI CLIs currently use BubbleTea. │
│ Charm ecosystem (glow, mods) are candidates for future AI tools. │
│ When they emerge, cursor pattern will provide MonoTerm compat. │
│ │
└───────────────────────────────────────────────────────────────────────┘
Pairing Summary
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ COMPLETE PAIRING MATRIX │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┬───────────────┬───────────────┬───────┬───────┐ │
│ │ AI CLI │ Framework │ Language │ Cursor│ BSU/ESU │
│ ├───────────────┼───────────────┼───────────────┼───────┼───────┤ │
│ │ Claude Code │ Ink │ TypeScript │ YES │ Dual │ │
│ │ Gemini CLI │ Ink (fork) │ TypeScript │ YES │ NO │ │
│ │ Aider │ Rich │ Python │ YES │ NO │ │
│ │ Open Interp. │ Rich + yaspin │ Python │ YES │ NO │ │
│ │ Codex CLI │ Ratatui │ Rust │ YES │ YES │ │
│ │ Kiro CLI │ Crossterm │ Rust │ YES │ NO │ │
│ └───────────────┴───────────────┴───────────────┴───────┴───────┘ │
│ │
│ Statistics: │
│ ─────────── │
│ - Cursor pattern: 6/6 (100%) │
│ - BSU/ESU native: 1/6 (17%) │
│ - BSU/ESU dual: 1/6 (17%) │
│ │
│ MonoTerm Compatibility: │
│ ─────────────────────── │
│ - Via cursor pattern: 6/6 (100%) │
│ - Via BSU/ESU: 2/6 (33%) │
│ - Total: 6/6 (100%) │
│ │
└───────────────────────────────────────────────────────────────────────┘
Key Insight
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ AI CLI FRAMEWORK PAIRING │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ Key Finding: AI CLIs inherit cursor pattern from TUI frameworks. │
│ │
│ Ink --> Claude Code, Gemini CLI │
│ Rich --> Aider, Open Interpreter │
│ Ratatui --> Codex CLI, Kiro CLI │
│ BubbleTea --> Future AI CLIs │
│ │
│ All frameworks emit cursor hide/show during render. │
│ MonoTerm detects this pattern for atomic frame boundaries. │
│ │
│ ─────────────────────────────────────────────────────────────── │
│ │
│ Critical Insight: │
│ │
│ "Support != Usage" │
│ │
│ Crossterm supports BSU/ESU, but Kiro CLI doesn't use it. │
│ Framework capability does not guarantee application behavior. │
│ MonoTerm must detect actual output patterns. │
│ │
└───────────────────────────────────────────────────────────────────────┘
Related Research
- Prior Art - What we learned from 6 terminals
- Terminal Analysis - Architecture comparison
- Success Factors - Why the architecture works