Shell history search. A background daemon records every command you run across all terminals; a CLI lets you search and replay them instantly.
Made by Niche-Knack — Smart Tools. Sharp Solutions.
Linux, amd64 or arm64. Each release has two static binaries — steno (the CLI)
and stenographerd (the daemon) — that only need to be put on your PATH. Then
steno install sets up the systemd user service and the shell hooks and prints
the one source command to run:
arch=amd64 # or arm64
base=https://github.com/Niche-Knack-Apps/stenographer/releases/latest/download
curl -LO $base/steno_linux_$arch -LO $base/stenographerd_linux_$arch -LO $base/SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMS
install -m 0755 steno_linux_$arch ~/.local/bin/steno
install -m 0755 stenographerd_linux_$arch ~/.local/bin/stenographerd
steno installFrom source:
make install # build release + install + print source command
source ~/.zshrc # activate in current shell (or restart terminal)make install compiles both binaries, copies them to ~/.local/bin/, installs the systemd user service, and adds shell integration to your RC files. It prints the exact source command to run at the end. Make runs in a subprocess so it cannot source your shell itself — you need to run that one command.
To upgrade: make install && source ~/.zshrc — the hook files are regenerated on every install.
Open history search from anywhere:
steno # search all recorded commands (default)
steno history # same as above
steno here # search commands run in the current directory
Or press Ctrl-R from any prompt.
Select a command and press:
- Enter — place it at your prompt, ready to edit or run
- Alt-Enter — execute it immediately in your current shell
| Key | Action |
|---|---|
| Type | Filter by substring (all tokens must match) |
↑ / ↓ |
Navigate |
Enter |
Place selected command at prompt |
Alt-Enter |
Execute selected command immediately |
Esc |
Cancel |
The right pane shows the full command, working directory, exit code, duration, git branch, and surrounding context.
By default the picker loads the 500 most recent commands. Raise it for a single search with --limit, or change the default permanently in config:
steno --limit 5000 # load up to 5000 this time
steno --limit 0 # load everything (0 or -1 = unlimited)
steno here --limit -1 # same, scoped to the current directoryTo make it permanent, set history_limit in ~/.config/stenographer/config.toml (0 or -1 = unlimited):
history_limit = 0The pool is still bounded by retention_days — unlimited means "everything still retained," not "forever."
| Command | Description |
|---|---|
steno / steno history |
Search all recorded commands |
steno here |
Search commands run in the current directory |
steno prime |
Import existing shell history into the database |
steno install |
First-time setup: binaries, service, shell hooks |
steno hook install |
Re-install / refresh shell hooks |
steno hook uninstall |
Remove shell hooks |
steno hook status |
Show hook installation status |
steno daemon start|stop|restart|logs |
Control the background daemon |
steno version / steno -v |
Print version |
steno completions <shell> |
Print shell completions |
Import your existing shell history on first setup:
steno prime # auto-detect shell (zsh/bash/fish)
steno prime --shell zsh # specify shell explicitly
steno prime --limit 50000 # raise the import limit (default: 10 000)
steno prime --dry-run # preview without importingNoise commands (ls, clear, cd .., etc.) are filtered out. Duplicates are deduplicated before import. After priming, steno shows results immediately without waiting for new history to accumulate.
# zsh
steno completions zsh > ~/.zfunc/_steno
# add to ~/.zshrc: fpath=(~/.zfunc $fpath) && autoload -U compinit && compinit
# bash
steno completions bash >> ~/.bash_completion
# fish
steno completions fish > ~/.config/fish/completions/steno.fishTwo binaries: stenographerd (background daemon, SQLite, Unix socket) and steno (CLI client). Shell hooks write pre/post-exec events to a spool file; the daemon picks them up via inotify and stores them in SQLite. The CLI queries the daemon over a Unix socket.
Shell integration uses a temp-file pattern (same as atuin): the binary writes the selected command to STENO_RESULT_FILE; the shell wrapper reads it and either calls print -z (place at prompt) or eval (execute immediately). This means cd, export, and other builtins work correctly.
Absolute paths. When the daemon records a command it rewrites relative path arguments to absolute paths rooted at the command's working directory (e.g. cat zarf/x/setup.sh → cat /home/me/proj/zarf/x/setup.sh), so replaying from a different directory still works. A one-time backfill rewrites existing history on the next upgrade. This is a whitespace-token heuristic gated on the file actually existing — not a full shell parser: quoted paths with spaces, punctuation-adjacent paths, globs, and command substitution are left untouched, and bare words without a slash or extension (cargo test, make build) are never rewritten. The backfill resolves against the current filesystem, so history whose files have since moved stays as-is.
If the daemon isn't running:
✗ Daemon is not running.
First-time setup: steno install
Start the daemon: steno daemon start
Check the logs: steno daemon logs
Add to ~/.profile:
if ! pgrep -u "$USER" stenographerd >/dev/null 2>&1; then
nohup stenographerd >> ~/.local/share/com.niche-knack.stenographer/logs/daemon.log 2>&1 &
fimake dev # debug build + start daemon
make build # release build → dist/
make install # build + install + print source command
make verify # clippy + tests + fmt checkEvery merge to main runs formatting, clippy and the tests. When the merge carries
a new version in VERSION (kept equal to Cargo.toml), the release workflow builds
static amd64 and arm64 Linux binaries of steno and stenographerd, tags vX.Y.Z,
and publishes them with SHA256SUMS as a GitHub release. A pull request that does
not bump VERSION fails its check, so every merge ships.
Stenographer is free and open. Niche-Knack also makes small, sharp, offline-first apps — see them at nk.tools.
Really believe in this project's potential and want to contribute to its development? Buy Me a Coffee.
Apache License 2.0. See NOTICE.