o-family ochazuke
お茶漬け ochazuke — tea poured over rice
A modal TUI framework for Go, built on Bubble Tea v2: Vim-style modes and an extensible command model, so every action in your app can be bound to a key, run from the palette or scripted from the shell.
libraryv0.55.0pre-1.0Go 1.26 or newer
The CSV example: moving through 3,000 rows, a palette command on a whole column, a filter, a sort and an edit with undo
overview
What it is
Ochazuke is a modal TUI framework for Go. It builds on Charmbracelet's Bubble Tea v2 (with Lip Gloss v2 and Bubbles v2) and adds what a keyboard-first app needs: Vim-style modes and editing, pages and a stack of modals that keep their state, lists, tables and trees, a command palette, forms and a Settings page, all styled out of the box.
Underneath is a generic command model. Every action is a named command with typed arguments, and the same command runs from a key, the palette, the command line or the Go API. Keys, settings and commands are data: users rebind and extend them in JSON files, and apps and extensions add their own without forking the framework. Every command lands in the action history, so undo and dot-repeat work across the whole app.
install
go get github.com/unixsuperhero/ochazuke@latest
go run ./cmd/ochazuke run # from a checkout
[
{ noun: "directory", mode: "normal", keys: "U",
request: { verb: "undo", noun: "input", args: { steps: 3 } } },
{ noun: "editor", mode: "insert", keys: "esc", request: null }, // unbind a default
{ instance: "notes", mode: "normal", keys: "g s",
request: { verb: "summarize", noun: "workspace" } }
]
features
What it does
01 / 12 · modal editing
Vim-style modes
Normal, insert, visual and any mode your app registers. Counts, operators and key sequences are pending modes of their own, and the mode badge and cursor shape always show where you are.
02 / 12 · modal editing
Vim's editing grammar
Each input owns its editing state and a branching undo tree. Yanks, registers and macros are shared, so a yank from notes pastes into a path field or a modal editor.
03 / 12 · modal editing
A stack of stateful modals
Modals are kept, not rebuilt. Each one holds its mode, focused field, drafts, cursor, selection and scroll, so closing a modal gives you back exactly what you left.
04 / 12 · layout and components
Pages that remember
Pages keep their focus, mode, drafts, undo history and scroll across navigation. Partial-screen modals leave the screen behind them visible, and themes (adaptive, dark, light, mono or your own) restyle everything at once.
05 / 12 · layout and components
Lists, tables and trees
Lists with marks, a
/filter and visual selection; tables with a cell cursor, pinned and resizable columns; editable outline trees. A command on a marked set runs once per row, with one confirm.06 / 12 · layout and components
A command palette and forms
:opens a command line with completion that takes either word order (edit taskortask edit). A command missing an argument opens a form with a field per parameter, and choices and paths come from type-to-filter pickers.07 / 12 · layout and components
Settings and a Settings page
Apps declare typed settings with defaults and sections; a generated Settings page edits them, and
config exportwrites a full reference.08 / 12 · extensibility
A command model
Every action is a named command with typed, validated arguments. A key, the palette, the CLI and the Go API all run the same command the same way, so nothing is reachable from only one of them.
09 / 12 · extensibility
Keys and settings are data
Default keys are JSON rows. Your
bindings.jsonrebinds, adds or unbinds them per component and mode, with sequences, guards and timed ambiguous keys (g,g g,g g g). The footer hints come from the same rows, so they never name an unbound key.10 / 12 · extensibility
Your own commands
actions.jsonadds commands that run external programs. They are ordinary commands: bindable, in the palette, on the CLI and in?help.11 / 12 · extensibility
Live CLI control and extensions
A local Unix socket drives a running app from another terminal:
ochazuke page open,input undo,state get. Any tool that answerscatalogmounts into a host app as pages, keys and palette commands, andcatalog inspectbrowses all of it as HTML.12 / 12 · testing
Stories
UI behaviour is tested with monogatari stories: JSON keystroke scripts played headless against the app's real model, with expectations on what the screen shows. Ochazuke's own stories run in
make test.
read more