Local ZSH history aggregation tool. Collect commands from multiple ZSH history files, store them in a local SQLite database, and search instantly with fuzzy matching.
- Multiple history files: Collect from several sources simultaneously
- Instant search: Query 10,000+ commands in milliseconds with SQLite FTS5
- Ctrl+X for fuzzy search: Interactive fuzzy search with fzf and preview pane
- Automatic deduplication:
(source, timestamp)primary key prevents duplicates - AI assistant history: Collect from Claude Code and OpenCode
- Collect from files or directories (recursive search)
- Search with full-text search, fuzzy matching, and time filtering
- Preview pane shows source file and timestamp while browsing
- Interactive ZSH integration (Ctrl+X)
- Batch inserts with transactions
- Metadata storage: duration, cwd, exit code
- Subsecond timestamps for duplicate deduplication
- fzf (for search functionality)
Download the latest release from GitHub releases:
# Linux (x64)
curl -L https://github.com/tchaudhry91/zist/releases/latest/download/zist-linux-x64 -o zist
chmod +x zist
sudo mv zist /usr/local/bin/
# macOS (Intel)
curl -L https://github.com/tchaudhry91/zist/releases/latest/download/zist-macos-intel -o zist
chmod +x zist
sudo mv zist /usr/local/bin/
# macOS (Apple Silicon)
curl -L https://github.com/tchaudhry91/zist/releases/latest/download/zist-macos-arm -o zist
chmod +x zist
sudo mv zist /usr/local/bin/git clone git@github.com:tchaudhry91/zist.git
cd zist
task build
task install-user# fzf (required for search)
brew install fzf # macOS
sudo apt install fzf # Ubuntu/Debian
sudo dnf install fzf # Fedora
# Add to PATH
export PATH="$HOME/go/bin:$PATH"# Collect from your ZSH history file
zist collect ~/.zsh_history
# Or collect from multiple history files at once
zist collect ~/.zsh_history ~/.claude/claude_zsh_history ~/.opencode_zsh_history
# Or collect from a directory (recursively finds all *zsh_history files)
zist collect ~/.histories/
# Search commands (requires fzf) - shows preview pane with source/timestamp
zist search docker
# Search with time filter
zist search --since 2024-01-01 git
# Interactive search (type before Ctrl+X)
docker<Ctrl+X> # opens fzf with "docker" as query
# Check version
zist --versionCollect commands from ZSH history files.
zist collect [--db PATH] [--quiet] [PATH...]- PATH: History file or directory to search (paths can be mixed)
- --db: Database path (default:
~/.zist/zist.db) - --quiet: Suppress output (useful for scripts/automation)
Directories are searched recursively for *zsh_history files.
Example - Collect from multiple sources:
zist collect ~/.zsh_history ~/.claude/claude_zsh_history ~/.opencode_zsh_historySearch command history interactively with fzf.
zist search [--db PATH] [--limit N] [--since DATE] [--until DATE] [QUERY]- QUERY: Initial search query for fzf (optional)
- --db: Database path (default:
~/.zist/zist.db) - --limit: Maximum number of results (default: 500)
- --since: Only show commands after this date (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
- --until: Only show commands before this date (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
The search displays a preview pane showing the source file and timestamp for the highlighted command.
Generate shell commands from natural language using an LLM.
zist wizard [--db PATH] [--query QUERY] [--pwd PATH] [--llm-api-url URL] [--model NAME] [--key KEY] [--timeout DURATION] [--cache QUERY] [--cache-command CMD] [--list-cache] [--clear-cache]- --query: Natural language query to convert to shell command
- --pwd: Current working directory (default: actual PWD)
- --db: Database path (default:
~/.zist/zist.db) - --llm-api-url: LLM API endpoint (overridden by
ZIST_LLM_API_URLenv var) - --model: Model name (overridden by
ZIST_MODELenv var) - --key: API key (overridden by
ZIST_LLM_API_KEYenv var) - --timeout: LLM request timeout (default: 30s)
- --cache: Cache a query→command mapping (use with --cache-command)
- --cache-command: Command to cache (use with --cache)
- --list-cache: List all cached query→command mappings
- --clear-cache: Clear all cached mappings
zist can be configured using environment variables.
| Variable | Description | Default |
|---|---|---|
ZIST_LLM_API_URL |
LLM API endpoint URL | http://localhost:11434/v1 |
ZIST_MODEL |
Model name to use | qwen2.5-coder:3b |
ZIST_LLM_API_KEY |
API key for hosted LLM providers | ollama |
Shell export (temporary):
export ZIST_LLM_API_URL=http://localhost:11434/v1
export ZIST_MODEL=qwen2.5-coder:3bAdd to ~/.zshrc or ~/.bashrc (permanent):
# For Ollama
export ZIST_LLM_API_URL=http://localhost:11434/v1
export ZIST_MODEL=qwen2.5-coder:3b
# Or for OpenRouter
export ZIST_LLM_API_URL=https://openrouter.ai/api/v1
export ZIST_LLM_API_KEY=sk-or-v1-your-key-here
export ZIST_MODEL=deepseek/deepseek-coderCommand-line flags override environment variables:
# Even with env vars set, you can override per-command
ZIST_LLM_API_URL=http://localhost:11434/v1 zist wizard --query "test"
# Or override with flags
zist wizard --query "test" --llm-api-url https://api.openai.com/v1 --model gpt-4ozist can capture commands run by your AI assistants. Here's how to enable it:
Add this to your Claude Code settings (~/.claude/settings.json):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\": \\(now | floor):0;\\(.tool_input.command)\"' >> ~/.claude/claude_zsh_history"
}
]
}
]
}
}Then collect the history:
zist collect ~/.claude/claude_zsh_historyCreate a plugin at ~/.opencode/plugins/bash-history.ts:
import { appendFileSync } from "fs"
import { homedir } from "os"
export async function BashHistoryPlugin() {
const historyFile = `${homedir()}/.opencode_zsh_history`
return {
"tool.execute.before": async (input, output) => {
if (input?.tool === "bash" && output?.args?.command) {
const timestamp = Math.floor(Date.now() / 1000)
appendFileSync(historyFile, `: ${timestamp}:0;${output.args.command}\n`)
}
},
}
}Then collect the history:
zist collect ~/.opencode_zsh_historyInstall keybindings:
zist install
source ~/.zshrcKeybindings:
- Ctrl+X - Fuzzy search history (uses what you typed as query)
- Ctrl+G - AI wizard (natural language → command)
Press Ctrl+X to search across all aggregated history with fuzzy matching:
- Uses
$LBUFFER(what you typed before Ctrl+X) as initial query - Opens fzf with all commands from database (with preview pane)
- Places selected command in buffer for editing
- precmd hook automatically collects from
~/.historiesafter each command
Press Ctrl+G to convert natural language to shell commands using an LLM.
zist works with any OpenAI-compatible API, including Ollama, OpenAI, OpenRouter, Together, Groq, and more.
Option 1: Ollama (local, free)
# Install Ollama (https://ollama.com)
curl https://ollama.com/install.sh | sh
# Pull a code model
ollama pull qwen2.5-coder:3b
# Configure zist
export ZIST_LLM_API_URL=http://localhost:11434/v1
export ZIST_MODEL=qwen2.5-coder:3bOption 2: OpenRouter (cloud, pay-per-token)
# Get an API key from https://openrouter.ai
# Configure zist
export ZIST_LLM_API_URL=https://openrouter.ai/api/v1
export ZIST_LLM_API_KEY=sk-or-v1-... # Your OpenRouter key
export ZIST_MODEL=deepseek/deepseek-coderOption 3: OpenAI
# Configure zist
export ZIST_LLM_API_URL=https://api.openai.com/v1
export ZIST_LLM_API_KEY=sk-... # Your OpenAI key
export ZIST_MODEL=gpt-4oCommand-line usage:
zist wizard --query "list all running docker containers"
zist wizard --query "find all files larger than 100MB"
zist wizard --query "compress a directory into tar.gz"Wizard features:
- Caches query→command mappings after execution to speed up repeated queries
- Learns from your command history for better suggestions
- Uses your current working directory for context
Cache management:
zist wizard --list-cache # View cached mappings
zist wizard --clear-cache # Clear all cacheUninstall:
zist uninstallCREATE TABLE commands (
source TEXT NOT NULL, -- absolute file path
timestamp REAL NOT NULL, -- Unix timestamp with subsecond
command TEXT NOT NULL, -- command text
duration INTEGER, -- execution duration in seconds
cwd TEXT, -- working directory
exit_code INTEGER, -- command exit code
PRIMARY KEY (source, timestamp)
);
CREATE INDEX idx_timestamp ON commands(timestamp DESC);
CREATE INDEX idx_source ON commands(source);
-- Full-text search index
CREATE VIRTUAL TABLE commands_fts USING fts5(
command,
content='commands',
content_rowid='rowid'
);
-- Triggers keep FTS index in sync automatically
CREATE TRIGGER commands_ai AFTER INSERT ON commands ...
CREATE TRIGGER commands_ad AFTER DELETE ON commands ...
CREATE TRIGGER commands_au AFTER UPDATE ON commands ...task build # Build binary
task check # Run fmt, vet, test
task test # Run teststask db-shell # Open SQLite shell
task db-backup # Backup database
task db-reset # Delete databasetask release # Build for: linux-x64, linux-arm64, macos-intel, macos-arm, windowsMIT
Tanmay Chaudhry