GitHunt
LU

lukoshkin/impeccable-history

Impeccable History

history-scraper is an executable file of a small program written in Rust.
Built on my system, it might not work on yours. If this is the case, you will
have to compile it from source, first installing Rust and Cargo. Later, there
will be added an easier way of compilation with Docker.

You can find more about hist-scraper's CLI by calling it with -h option. In
case you want to amend or adjust the plugin to your needs, please, see the
source code (hist-scraper.rs,
hist-scraper.plugin.zsh), then contribute.

The plugin works by remembering failed commands in a
/tmp/hist-scraper-nzcmds.txt during a Zsh session (a hook in
precmd_functions) and removing them on exit from $HISTFILE (a hook in
zshexit_functions). You can find info about errors occurred during the plugin
operation at /tmp/hist-scraper-error.log.

Note: you can not remove with impeccable-history commands in
$HISTFILE that failed before the installation. Also, editing HISTFILE
manually will result in assigning a wrong value to HIST_SCRAPER_SKIP_ROWS
for the next shell session. However, you can adjust it or set it to zero from
the command line.

More About

On top of removing failed commands, impeccable-history plugin sets
these Zsh options: histignorespace, histreduceblanks, histignorealldups,
histnostore, and interactivecomments (needed for # keep marker) - for a
sharper management of a user history.

Even more granular control over the lifetime of trivial commands is possible
with HIST_SCRAPER_IGNORE, HIST_SCRAPER_KEEP, and HISTORY_IGNORE variables.
One can incorporate the adaptations of the following into their .zshrc.

ignore_list=('.{1,3}' echo clear tmux )
## Don't append the following patterns to the $history array.
HIST_SCRAPER_IGNORE="(^$(join_by '$|^' ${ignore_list[@]})$)"
unset ignore_list

## Keep these commands in history even if they fail (e.g., test runners).
HIST_SCRAPER_KEEP="^(pytest|make|cargo test|npm test|go test)"

## Remove these patterns from $HISTFILE on shell logout.
HISTORY_IGNORE="(mv *|mkdir *|man *|math *|type *|which *|whence *)"

The HIST_SCRAPER_KEEP variable is a regex pattern matching commands that
should never be removed from history, regardless of their exit code. This is
useful for test runners and build tools that frequently return non-zero exit
codes as part of normal workflow.

Per-Command History Preservation

For one-off commands that may fail but should stay in history, you have two
options:

Option 1: # keep marker

pytest tests/test_api.py # keep

The command is preserved in history without the # keep suffix. The marker
must be standalone at the end of the line (e.g., # keep this value won't
trigger preservation).

Option 2: Force success exit code

pytest tests/test_api.py || true

The || true makes the exit code always 0, so the command won't be marked for
removal. The || true part remains in the saved command.

Installation

For instance, with zcomet:

zcomet load lukoshkin/impeccable-history

## The command below pulls from the 'develop' branch.
# zcomet load lukoshkin/impeccable-history@develop

I guess, most of the popular plugin managers will work as well.
Just add the corresponding entry to your .zshrc.

Known issues

Zsh history file is saved in metafied format. Currently, hist-scraper reads it
directly, without transforming it back to a standard encoding. That is, the
plugin will not work for failed commands containing non-ASCII characters. This
will be fixed in the next patch.

Possible solutions:

  • metafying strings of failed commands and comparing them with
    the lines
    of the history file read as Vec<char> (see, e.g.,
    this).
  • feeding the last few commands of $HISTFILE converted with Zsh's history to

    hist-scraper and obtaining the indices of the lines to delete. Then
    doing something like
    awk 'FNR==NR{a[$0];next} !(FNR in a)' indices.txt $HISTFILE
    

Languages

Rust53.3%Shell46.7%

Contributors

MIT License
Created November 22, 2022
Updated March 14, 2026