pxh 0.9.18

pxh is a fast, cross-shell history mining tool with interactive fuzzy search, secret scanning, and bidirectional sync across machines. It indexes bash and zsh history in SQLite with rich metadata for powerful recall.
Documentation

pxh

Fast, local-first shell history search and sync for bash and zsh.

Your shell history is one of the most useful things on your machine -- but it's fragile, unsearchable, and stuck on one box. pxh fixes that. It stores every command in a local SQLite database with rich metadata (directory, host, exit code, duration), gives you powerful regex search and an interactive TUI, and syncs across machines over SSH or a shared filesystem.

No cloud accounts. No servers. No networking code. No AI. Just your history, on your machines, searchable in milliseconds.

$ pxh s ffmpeg
 2022-06-04 07:54:04  ffmpeg -encoders | grep '^ V'
 2022-06-07 23:17:33  ffmpeg -y -r 30 -f concat -safe 0 -i <(sed...) -c:v libx264rgb output.mp4
 2022-08-03 10:39:11  ffmpeg -i cropped.mp4 -vf "pad=width=430:..." cropped.gif

Install

Homebrew (macOS and Linux):

brew install chipturner/tap/pxh

Prebuilt binaries (Linux x86_64/ARM64, macOS x86_64/ARM64):

curl -sSfL https://raw.githubusercontent.com/chipturner/pxhist/main/install.sh | sh

From source:

cargo install pxh        # requires Rust 1.88+

Shell setup

After installing, set up shell integration (including tab completions) and import your existing history:

pxh install bash  # or: pxh install zsh

# Import your existing history
pxh import --shellname bash --histfile ~/.bash_history
# or for zsh:
pxh import --shellname zsh --histfile ~/.zsh_history

# Activate in current session without restarting
source <(pxh shell-config bash)  # or: source <(pxh shell-config zsh)

From now on, pxh automatically records commands with directory, host, user, exit code, and duration.

Note: By default, trivial commands (ls, cd, pwd, exit, etc.) are not recorded. See Configuration to change this.

Note: fish shell is not currently supported. PRs welcome!

Usage

Interactive Browser (pxh recall)

Press Ctrl-R in your shell to open the interactive history browser. Type to filter, arrows to navigate, Enter to execute, Tab to edit before executing. Alt-1 through Alt-9 quick-select visible entries.

pxh recall           # Open history browser
pxh recall --here    # Limit to current directory
pxh recall -q "git"  # Start with a pre-filled query

Supports both emacs (default) and vim keybindings -- set keymap = "vim" in ~/.config/pxh/config.toml.

Keybindings:

  • Ctrl-Y / Alt-W -- Copy selected command to clipboard (via OSC 52)
  • Ctrl-K -- Delete selected entry from history
  • Ctrl-H -- Toggle host filter
  • Ctrl-G -- Toggle directory/global filter
  • Alt-1 through Alt-9 -- Quick-select visible entries

Searching History (pxh show)

The show command (alias: s) is the power-search interface:

pxh show ffmpeg           # Find commands containing "ffmpeg"
pxh s docker run          # Multiple patterns match in order (docker.*\s.*run)
pxh s -i CMAKE            # Case-insensitive search
pxh s --here              # Only commands from current directory
pxh s --session $PXH_SESSION_ID  # Only commands from current shell session
pxh s -v cargo build      # Verbose: show duration, session, directory
pxh s -l 100 git          # Show up to 100 results (default: 50, 0 = unlimited)
pxh s --loosen foo bar    # Match patterns in any order
pxh s -F                  # Show commands that failed (non-zero exit)
pxh s -F docker           # Failed docker commands
pxh s -H                  # Short for --here (current directory only)
pxh s -S current          # Short for --session current
pxh s --working-directory ~/project  # Filter to a specific directory

Failed commands are highlighted in red when the status column is visible (-v or -F).

Verbose output (-v):

$ pxh s -v cargo build
 Start                Duration  Session       Context      Command
 2023-02-06 22:10:20  1s        116ef63fc226  .            cargo build --release
 2023-02-07 06:32:04  37s       ee6e1989f3da  .            cargo build --release

Synchronizing History (pxh sync)

Sync history across machines via SSH or a shared directory. pxh contains no networking code itself - sync works by invoking SSH or reading/writing files from a shared filesystem.

SSH Synchronization

# Bidirectional sync (default)
pxh sync --remote myserver

# One-way sync
pxh sync --remote myserver --send-only     # Push local → remote
pxh sync --remote myserver --receive-only  # Pull remote → local

# Custom SSH options (like rsync's -e flag)
pxh sync --remote myserver -e "ssh -p 2222"
pxh sync --remote myserver -e "ssh -i ~/.ssh/special_key"

# Sync only recent history
pxh sync --remote myserver --since 30  # Last 30 days only

# Custom remote paths
pxh sync --remote myserver --remote-db /custom/path/pxh.db
pxh sync --remote myserver --remote-pxh /usr/local/bin/pxh

Note: Remote sync automatically detects whether the remote host uses XDG paths (~/.local/share/pxh/) or the legacy path (~/.pxh/). Use --remote-db to override if needed.

Shared Directory Synchronization

Use Dropbox, OneDrive, NFS, or any shared filesystem:

# On each machine, run:
pxh sync ~/Dropbox/pxh/

# Export only (don't import from others)
pxh sync ~/Dropbox/pxh/ --export-only

Each machine writes its own .db file and reads from all others.

Security: Scanning and Scrubbing

Scanning for Secrets

Detect potential secrets (API keys, passwords, tokens) in your history:

pxh scan                        # Scan with default sensitivity (critical)
pxh scan -c high                # Include high-confidence matches
pxh scan -c all                 # Show all potential matches
pxh scan -v                     # Verbose: show which pattern matched
pxh scan --json                 # Output as JSON for scripting
pxh scan --histfile ~/.bash_history  # Scan a histfile directly
pxh scan --dir ~/Dropbox/pxh/   # Scan all databases in a sync directory

Confidence levels: critical (default), high, low, all

Removing Secrets

Remove sensitive commands from your history:

pxh scrub                       # Interactive: prompts for the secret to remove
pxh scrub "my-api-key"          # Remove commands containing this string
pxh scrub --scan                # Remove all secrets found by scan
pxh scrub --scan -c high        # Remove critical and high-confidence secrets
pxh scrub -n                    # Dry-run: show what would be removed
pxh scrub -y                    # Skip confirmation prompt

# Scrub from multiple locations
pxh scrub --histfile ~/.bash_history "secret"  # Also scrub from histfile
pxh scrub --dir ~/Dropbox/pxh/ "secret"        # Scrub from sync directory
pxh scrub --remote myserver "secret"           # Scrub from remote machine

Other Commands

Import

Import history from existing shell history files:

pxh import --shellname zsh                # defaults to ~/.zsh_history
pxh import --shellname bash               # defaults to ~/.bash_history
pxh import --shellname zsh -n             # dry-run: show count without importing

# Import from another machine
pxh import --shellname zsh --histfile <(ssh server cat ~/.zsh_history) \
    --hostname server --username root

# Import from Atuin
contrib/atuin-to-pxh | pxh import --shellname json --histfile /dev/stdin

Export

Export your entire history as JSON:

pxh export > history.json
pxh export | jq '.[] | select(.exit_status != 0)'  # Filter failed commands

Maintenance

Optimize database performance and reclaim space:

pxh maintenance           # ANALYZE and VACUUM the database
pxh maintenance other.db  # Operate on a specific database file

Shell Completions

Generate tab-completion scripts for your shell:

pxh completions bash    # also: zsh, fish, elvish, powershell

pxh install sets up completions automatically. For manual setup:

# bash (add to ~/.bashrc)
eval "$(pxh completions bash)"

# zsh (add to ~/.zshrc)
eval "$(pxh completions zsh)"

Diagnostics

Check for common issues or view history statistics:

pxh doctor                # Diagnose common issues
pxh doctor --fix          # Attempt automatic fixes
pxh doctor --report       # Generate a diagnostic report for bug reports
pxh stats                 # Show history statistics

Configuration

pxh reads configuration from ~/.config/pxh/config.toml. All settings are optional with sensible defaults.

Note: If ~/.pxh exists from a previous installation, pxh uses it as a fallback for both config and data. New installations use XDG paths by default (~/.config/pxh/ for config, ~/.local/share/pxh/ for data). Override with XDG_CONFIG_HOME and XDG_DATA_HOME.

Example configuration:

[recall]
# Keymap mode: "emacs" (default) or "vim"
keymap = "emacs"

# Show the preview pane with command details
show_preview = true

# Maximum results to load (default: 5000)
result_limit = 5000

[recall.preview]
# Which fields to show in the preview pane
show_directory = true
show_timestamp = true
show_exit_status = true
show_duration = true
show_hostname = false  # Useful if syncing across machines

[host]
# Override the detected hostname
hostname = "my-laptop"
# Previous hostnames for this machine (history from these is treated as local)
aliases = ["old-laptop", "work-mac"]

[shell]
# Disable Ctrl-R binding (use pxh recall directly instead)
disable_ctrl_r = false

[history]
# Regex patterns for commands to skip recording.
# Default patterns ignore trivial commands (ls, cd, pwd, exit, etc.)
# Set to [] to disable.
ignore_patterns = [
    "^ls$",
    "^cd( .)?$",
    "^pwd$",
    "^exit$",
    "^clear$",
    "^fg$",
    "^bg$",
    "^jobs$",
    "^history$",
    "^true$",
    "^false$",
]

Tips and Tricks

Quick Search Alias

Create a symlink named pxhs pointing to pxh, and it will automatically run pxh show:

ln -s $(which pxh) ~/.local/bin/pxhs
pxhs ffmpeg  # Equivalent to: pxh show ffmpeg

Useful Patterns

# Commands that failed
pxh s -F  # Show commands that exited with non-zero status

# What did I do in this project last week?
pxh s --here -l 0

# How did I use that obscure tool?
pxh s -v ansible-playbook

# Commands from a specific session
pxh s --session $PXH_SESSION_ID  # Current session

Sync Strategies

  • Real-time sync: Run pxh sync --remote server periodically via cron
  • Shared folder: Just run pxh sync ~/Dropbox/pxh/ occasionally on each machine
  • Backup: The database is a single SQLite file - cp ~/.local/share/pxh/pxh.db backup/

zsh-autosuggestions

If you use zsh-autosuggestions, pxh automatically registers itself as a suggestion strategy. Suggestions come from your full cross-machine history database, not just the local zsh history file.

Privacy

  • Commands starting with a space are ignored (like bash's HISTCONTROL=ignorespace)
  • Use pxh scan regularly to detect accidentally committed secrets
  • Use --no-secret-filter with sync if you want to disable automatic secret filtering during import

Disabling Ctrl-R

If you prefer to keep your shell's default Ctrl-R behavior:

Option 1: CLI flag

# When sourcing manually:
source <(pxh shell-config zsh --no-ctrl-r)

Option 2: Config file (~/.config/pxh/config.toml)

[shell]
disable_ctrl_r = true

You can still use pxh recall directly or bind it to a different key.

Credits

Inspired by bash-history-sqlite, zsh-histdb, mcfly, and atuin. Embeds bash-preexec and secrets-patterns-db.

How it Works

pxh contains zero networking code. Sync works by invoking your SSH client or reading/writing files on a shared filesystem. No accounts, no cloud services, no ports, no attack surface. Your history stays on machines you control.

All data lives in a local SQLite database (~/.local/share/pxh/pxh.db). There's no central server. The binary is statically linked with no runtime dependencies beyond libc -- consistent behavior across bash and zsh, proper handling of edge cases (quoting, binary data, concurrent access), and fast enough that you never notice it.

pxh hooks into your shell via preexec/precmd functions to capture each command with its start/end time, working directory, exit status, session ID, hostname, and username. For bash, it embeds bash-preexec; for zsh, it uses native hooks.

Commands are stored as BLOBs (to handle non-UTF8 data) in SQLite with WAL mode and a 5-second busy timeout, so multiple shells can record simultaneously. A unique index prevents duplicates. Secret scanning uses patterns from secrets-patterns-db, categorized by confidence level.

Database location: ~/.local/share/pxh/pxh.db (override with --db or PXH_DB_PATH)

sqlite3 ~/.local/share/pxh/pxh.db "SELECT * FROM command_history LIMIT 10"