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.db

Use 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

ModeMeaningTypical use
GlobalAll historyFind an old command regardless of project.
PWD exactOnly the current logical directoryRecall commands for the current folder.
PWD subdirsCurrent directory and descendantsWork within a project tree.
Git rootAll history below the repository rootSearch 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.

[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.