Tutorial
From a stock Atuin database to a customized keyboard-first history workspace.
1. First run
cargo build --release
./target/release/cmdscope
./target/release/cmdscope --db "$HOME/.local/share/atuin/history.db"
./target/release/cmdscope --db ./history.db --print-first
./target/release/cmdscope --config ./examples.config.toml --db ./history.dbUse the smoke command before entering the TUI when diagnosing a database. It exercises loading and prints the newest command without opening a full-screen terminal.
2. Search
Type normally for fuzzy matching. Quotes make a literal stage, /pattern/ makes a regex stage, and # narrows the next stage to the current candidate stream.
cargo#test
"git status"
/ssh.*config/
Mid-string edits stay incremental. Home/End, Left/Right, Delete, Ctrl-W, Ctrl-U and bracketed paste work directly in the search field.
3. Scopes
| Mode | Meaning | Typical use |
|---|---|---|
| Global | All history | Find an old command regardless of project. |
| PWD exact | Only the current logical directory | Recall commands for the current folder. |
| PWD subdirs | Current directory and descendants | Work within a project tree. |
| Git root | All history below the repository root | Search an entire checkout while moving between subdirectories. |
4. Context review
Open context around the selected command with the configured context key. The active fuzzy query is suspended while you inspect time-neighbors. Expand or shrink the radius, then return to search by typing or changing scope.
5. Nested menus
[ui.menus.actions]
[[ui.menus.actions.items]]
label = "Inspect →"
action = "menu:inspect"
[ui.menus.inspect]
[[ui.menus.inspect.items]]
label = "Location"
action = "window:location"
[[ui.menus.inspect.items]]
label = "Timeline"
action = "window:timeline"The first action opens a second menu; the second menu opens a dedicated inspection window. Each modal layer owns its local navigation keys, and Escape closes only the innermost layer.
6. Lifecycle hooks
[ui.menus.actions]
on_open = ["window:preview"]
on_leave = []
[[ui.menus.actions.items]]
label = "Compose"
action = "menu:wrap"
on_select = []
on_leave = []Hooks are ordinary validated actions. They can open another menu or window; unknown targets are rejected at startup. Keep hooks short and deterministic.
7. Wrap without execution
[ui.wraps.stderr]
template = "{command} 2>&1"
[ui.menus.wrap]
[[ui.menus.wrap.items]]
label = "stderr"
action = "wrap:stderr"Wrapping produces shell text only. cmdscope never evaluates it. This preserves the boundary between selecting text and executing it.
8. Live refresh
When launched against a real SQLite history file, cmdscope detects metadata changes during idle periods and reloads a complete snapshot. The current query is reapplied and the selected identity is retained when it still exists. If the selected row disappears, selection falls back deterministically.
9. Shell integration
# stdout contains the selected command; the TUI uses stderr
cmdscope --null
# Bash widget pattern
IFS= read -r -d '' selected < <(cmdscope --null)
READLINE_LINE="$selected"
READLINE_POINT=${#READLINE_LINE}Use the NUL form when history commands can contain trailing newlines. See the main README for Bash, Zsh, and Fish widget implementations.