Hunch predicts your next shell command from your own history. Local, statistical, zero telemetry.
It learns which commands tend to follow which, then shows the most likely next one as ghost text - accept it with a keystroke, or keep typing. No LLM, no cloud, no accounts, and it gets better the more you use it.
# Install
go install github.com/DerekCorniello/hunch@latest
# Set up shell integration (auto-detects your shell, appends to rc file)
hunch init --auto
# Restart your shell, and you're done.
# Hunch learns from every command. Predictions appear as you type.
# Start using it - predictions appear as ghost text
git clone https://github.com/user/repo.git
# ghost text: cd repo press Right or End to acceptAfter a few commands, Hunch learns your workflows:
git clone REPO -> cd STR
cargo build -> cargo run
ssh STR -> ssh STR
No Go toolchain required. Download the binary for your platform from the
latest release,
make it executable, and put it on your PATH:
# Linux (x86_64) - substitute your platform below
curl -L -o hunch https://github.com/DerekCorniello/hunch/releases/latest/download/hunch-linux-amd64
chmod +x hunch
sudo mv hunch /usr/local/bin/Available builds: hunch-linux-amd64, hunch-linux-arm64,
hunch-darwin-amd64, hunch-darwin-arm64, hunch-windows-amd64.exe,
hunch-windows-arm64.exe.
On macOS, Gatekeeper will block the binary on first run because it is
unsigned. Clear the quarantine attribute with
xattr -d com.apple.quarantine /usr/local/bin/hunch.
To upgrade later, run hunch update. It downloads the current release for
your platform and replaces the running binary in place, so no Go toolchain
is needed.
go install github.com/DerekCorniello/hunch@latestThe binary is built at ~/go/bin/hunch (or wherever $GOBIN points). Make sure it's on your PATH.
Build with a version string:
go install -ldflags "-X github.com/DerekCorniello/hunch/cli.Version=v0.1.0" github.com/DerekCorniello/hunch@latestOr from a local clone:
go install -ldflags "-X github.com/DerekCorniello/hunch/cli.Version=$(git describe --tags --always)" .Hunch requires no external runtime dependencies. The Go binary is fully static (SQLite is handled by modernc.org/sqlite, a pure-Go port - no CGO needed).
Run hunch init <shell> to print the source line to add to your rc file, or use --auto to append it automatically:
# Auto-detect shell and append source line to rc file
hunch init --auto
# Or specify shell explicitly
hunch init zsh --auto
# Without --auto, just prints the source line
hunch init zsh
# Prints: source /path/to/hunch/integrations/zsh/hunch.zsh
# bash
hunch init bash
# fish
hunch init fish
# PowerShell (add to your $PROFILE)
hunch init powershellEach shell gets the best experience it can support reliably. Inline ghost text (suggestions as you type) needs a per-keystroke prediction path and a ghost-text primitive; only zsh has both, so the other shells fall back to a dim post-command hint showing the most likely next command.
| Shell | UX | Mechanism | Accept / cycle |
|---|---|---|---|
| zsh | Inline ghost text as you type | persistent serve coprocess + POSTDISPLAY |
Right/End to accept; Alt-n / Alt-p to cycle |
| bash | Post-command hint line | client predict in PROMPT_COMMAND |
- (type or copy) |
| fish | Post-command hint line | client predict in fish_postexec |
- (fish's own autosuggestions still apply) |
| PowerShell | Post-command hint line | client predict in a wrapped prompt |
- |
Why not inline everywhere? bash has no ghost-text primitive without a large add-on like ble.sh; fish's native autosuggestion engine owns inline text and resists external injection; PowerShell's native inline predictor (PSReadLine
ICommandPredictor) requires a compiled binary module. A native PowerShell predictor module is possible future work. The post-command hint is robust everywhere and never fights the shell's own line editor.
All integrations:
- Auto-start the daemon when sourced
- Capture each command's exit code and working directory, feeding the location-affinity and outcome-weighting signals
- Send recorded commands to the daemon asynchronously (non-blocking)
- Use the
HUNCH_BINenvironment variable to locate thehunchbinary (default:hunch) - Honor
HUNCH_HINT=0(bash/fish/PowerShell) to silence the hint line - Silently degrade if the daemon is unavailable
Set up shell integration. Auto-detects shell from $SHELL if not specified. Supported shells: zsh, bash, fish, powershell.
--auto Automatically append source line to rc file
When run interactively, hunch init detects your shell history and offers to import
it to jump-start predictions. In non-interactive contexts (piped, scripted), the
prompt is skipped.
Import shell command history as training data for predictions. Supports zsh, bash,
fish, and powershell.
--path <file> History file path (defaults to the shell's standard location)
--threads <N> Number of normalize worker threads (default: CPU count)
Processes history by parsing commands, normalizing them into templates, building state transitions, and importing into the daemon as a seed.
Safe to re-run: counts combine by maximum, so importing the same history twice leaves the graph unchanged rather than doubling it. Worth doing after an upgrade that changes how transitions are recorded, since the import backfills context that older data does not have.
Measure how well hunch predicts your own history. Replays your shell history in order, predicting each command using only the commands before it, which is how the daemon sees your session as you work.
--path <file> History file path (defaults to the shell's standard location)
--warmup <n> Commands to learn from before scoring begins (default: 50)
Reports top-1, top-3, and top-5 hit rates, how often any suggestion was offered, and a baseline: the hit rate you would get by always guessing your single most frequent command. The baseline is the number worth comparing against, since a shell history dominated by one command can make a weak model look strong.
Manage the background daemon process.
| Action | Description |
|---|---|
run |
Run daemon in foreground (useful for debugging) |
start |
Detach and run daemon in background |
stop |
Stop the running daemon |
status |
Check if daemon is running (exit 0 = running) |
Send an IPC operation to the running daemon.
| Op | Description |
|---|---|
record |
Record a command transition |
predict |
Get next-command predictions |
reset |
Wipe all learned data |
export |
Export the transition graph as JSON |
normalize |
Normalize a raw command to its template |
stats |
Show daemon stats (size, half-life, alpha) |
config |
Show active daemon configuration |
import |
Import a seed JSON file |
--state <prev1,prev2> Previous 1-2 commands (comma-separated)
--next <command> The command that was run
--at <timestamp> ISO 8601 timestamp
--state <prev1,prev2> Previous 1-2 commands (comma-separated)
--prefix <text> Current buffer text for filtering
--limit <n> Max suggestions (default: 3)
Check hunch installation and daemon health. Verifies:
- Binary location and PATH
- Daemon status
- Database file
- Shell integration source line
Returns exit code 0 if all checks pass, non-zero otherwise.
Remove hunch from your system. Stops the daemon, removes all data files (database, socket, logs, integrations, config), and removes the source line from all shell rc files.
--yes, -y Skip confirmation prompt
Check for and install updates. Queries GitHub for the latest release and, if a
newer version exists, downloads the binary built for your platform, verifies it
against the release's SHA256SUMS, and replaces the running executable in
place. No Go toolchain is required. The daemon is restarted automatically
afterwards.
Verification fails closed: if the checksum file is missing or the digest does not match, the download is discarded and nothing is installed.
The new binary is downloaded next to the current one and moved into place, so
the directory holding hunch must be writable. If it is not (for example
/usr/local/bin owned by root), re-run with elevated privileges. Platforms
with no published binary are told to reinstall from source instead.
For convenience, these shortcuts wrap common hunch client operations:
| Command | Equivalent |
|---|---|
hunch stats |
hunch client stats |
hunch predict [flags] |
hunch client predict [flags] |
hunch reset |
hunch client reset |
Example:
hunch predict --state "git add,git commit" --limit 5| Variable | Field | Default |
|---|---|---|
HUNCH_BIN |
Binary path | hunch (from PATH) |
HUNCH_SOCKET |
Unix socket path | ~/.cache/hunch.sock |
HUNCH_DB_PATH |
SQLite database path | ~/.local/share/hunch.db |
HUNCH_DAEMON_BIN |
Daemon binary path | (same as hunch) |
HUNCH_HALF_LIFE_HOURS |
Decay half-life | 720 (30 days) |
HUNCH_ALPHA |
Additive smoothing | 0.5 |
HUNCH_BETA |
CWD-affinity boost strength | 0.75 |
HUNCH_GAMMA |
Failure-rate suppression strength | 0.5 |
HUNCH_DELTA |
Prior-outcome boost strength | 0.5 |
HUNCH_EPSILON |
Confirmed-acceptance boost strength | 0.5 |
HUNCH_MIN_CONFIDENCE |
Score a generalized match must reach to be shown | 0.20 |
HUNCH_MIN_COUNT |
Times a command must have been seen before it is suggested | 2 |
HUNCH_EXTRA_PARENTS |
Extra parent commands (comma-separated) | (none) |
HUNCH_IGNORE |
Extra regexes for sensitive commands to never record (comma-separated) | (none) |
HUNCH_LOG_LEVEL |
Log level | info |
HUNCH_HINT |
Set to 0 to silence the post-command hint (bash/fish/PowerShell) |
1 |
Each scoring strength (beta/gamma/delta/epsilon) is a soft,
multiplicative adjustment that is the identity when its signal is absent; set
any to 0 to disable that signal.
min_count is how many times you must have run a command in a given context
before hunch will suggest it. The default of 2 means one-off commands are
never suggested: hunch predicts habits, and a habit is repeated by definition.
This matters more than it sounds, because a command run once in a context you
never revisit is the only candidate for that state, so it scores as the most
confident suggestion possible on the least evidence possible. Set it to 1 to
be suggested everything, including things you ran once by accident.
min_confidence controls how readily hunch generalizes. An exact-context match
is always shown. When there is no exact match, hunch widens the context (drop
the directory, then drop the oldest command) and shows the result only if it
scores at least this high. Lower it to see suggestions more often at the cost
of more wrong ones; set it to 1 to suppress generalized suggestions entirely
and only ever show exact-context matches. Sensitive commands matching a built-in or
HUNCH_IGNORE pattern are never recorded (neither the transition nor the raw
command), so secrets are not persisted or suggested back.
Hunch looks for config.toml in the XDG config directory:
| OS | Config path |
|---|---|
| Linux | ~/.config/hunch/config.toml |
| macOS | ~/.config/hunch/config.toml |
| Windows | %AppData%\hunch\config.toml |
socket = "/run/user/1000/hunch.sock"
db_path = "/var/lib/hunch/hunch.db"
half_life_hours = 720
alpha = 0.5
beta = 0.75 # CWD-affinity boost
gamma = 0.5 # failure-rate suppression
delta = 0.5 # prior-outcome boost
epsilon = 0.5 # confirmed-acceptance boost
min_confidence = 0.20 # bar for suggestions from a generalized context
min_count = 2 # ignore commands you have only run once
accept_keys = ["right", "end"]
extra_parents = ["mycli", "teamtool"]
ignore = ['(?i)--api-token'] # extra sensitive-command patterns to never record
log_level = "info"Precedence (lowest to highest): built-in defaults -> config file -> env vars -> CLI flags.
shell -> integration (thin adapter) -> daemon (background service) -> core/ (logic)
|
SQLite (WAL)
- core/ - Pure logic.
normalize(two-phase: unwrap wrappers, classify tokens),graph(transition counts),predict(additive-smoothed exponential decay scoring). Deterministic and stateless. - daemon/ - Background service. Owns SQLite, receives IPC events, calls core to update and predict. One request per connection over a Unix socket.
- cli/ - Admin interface. Routes to init/daemon/client subcommands. Links the full daemon package.
- integrations/ - Shell-specific adapters. Minimal shims that shell out to
hunch client. No learning logic.
See AGENTS.md for the full architecture and design decisions.
| Platform | Status |
|---|---|
| Linux (x86_64, aarch64) | Full support |
| macOS (x86_64, arm64) | Supported |
| Windows (x86_64) | Supported (Unix domain sockets) |
| Other Unix (FreeBSD, etc.) | Supported (flock, XDG paths) |
On Windows, you may need to exclude %LocalAppData%\hunch\ from Windows Defender
real-time scanning to avoid lock contention with the SQLite database.
The daemon starts automatically the first time you open a terminal after boot
(your shell rc file runs hunch daemon start). It then stays alive as a
detached background process across terminal sessions. This is sufficient for
normal interactive use.
If you need the daemon running without an interactive shell (e.g. tmux sessions that auto-start, CI, SSH invocations), install a user service for your platform:
Linux (systemd):
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/hunch-daemon.service << 'EOF'
[Unit]
Description=Hunch daemon
After=network.target
[Service]
Type=simple
ExecStart=%h/go/bin/hunch daemon run
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
EOF
systemctl --user enable --now hunch-daemonmacOS (launchd):
mkdir -p ~/Library/LaunchAgents
cat > ~/Library/LaunchAgents/com.user.hunch-daemon.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.hunch-daemon</string>
<key>ProgramArguments</key>
<array>
<string>PATH/TO/hunch</string>
<string>daemon</string>
<string>run</string>
</array>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
EOF
launchctl load ~/Library/LaunchAgents/com.user.hunch-daemon.plistWindows (Task Scheduler):
$action = New-ScheduledTaskAction -Execute "hunch.exe" -Argument "daemon run"
$trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName HunchDaemon -Action $action -Trigger $triggerHunch overlaps with tools you may already run. It is designed to sit alongside them rather than replace them.
| Tool | What it answers | Relationship to hunch |
|---|---|---|
zsh-autosuggestions / fish autosuggestions |
"What did I type that started this way?" | Prefix search over history. It needs you to start typing; hunch suggests before you type anything, based on what you just ran. They compose. |
atuin |
"What did I run before, and where?" | A searchable history database with sync. It is recall on demand; hunch is a prediction offered unprompted. Different moments. |
fzf history widget |
"Let me hunt through history interactively." | Explicit search you invoke. hunch never requires an invocation. |
thefuck |
"That command failed, what did I mean?" | Corrects the command you just ran. hunch proposes the next one. |
The distinguishing idea is that hunch models the sequence: it learns that
cargo build tends to be followed by cargo run, and conditions that on the
directory you are in and whether the last command succeeded. Prefix-matching
tools have no notion of what typically comes next.
Two honest caveats. Predictions are templates hydrated with a concrete
past command, so hunch suggests things you have run before, not novel commands.
And it needs history to be useful: run hunch import-history to start from
your existing history rather than from nothing.
Measure it on your own history with hunch eval <shell> rather than taking
any of this on faith.
- No AI/LLM - purely statistical learning
- No cloud sync or telemetry
- No distributed system
- No multi-user graph merging
- No complex shell grammar parsing
- No daemon-less mode (the daemon is required)
-
Check if the daemon is running:
hunch daemon status
-
If not running, start it:
hunch daemon start
-
Verify shell integration is loaded:
hunch doctor
-
Check that your rc file sources the hunch integration script.
-
Check for stale socket file:
ls -la ~/.cache/hunch.sock -
Remove it if the daemon isn't running:
rm ~/.cache/hunch.sock hunch daemon start -
Check the log file for errors:
tail -f ~/.local/share/hunch/hunch.log
The binary isn't on your PATH. Either:
# Install globally
go install github.com/DerekCorniello/hunch@latest
# Or add to PATH
export PATH="$PATH:$(go env GOPATH)/bin"- Hunch needs time to learn your patterns. Run
hunch import-historyto jump-start from your shell history. - Check the graph size:
hunch stats - Reset and start fresh:
hunch reset
Hunch registers its zle hooks through add-zle-hook-widget (zsh 5.3+), which
keeps a list of widgets per hook and runs all of them. It composes with
zsh-autosuggestions and similar plugins regardless of load order, and adopts
any widget a plugin bound directly. On zsh older than 5.3 it falls back to
chaining a single previous widget.
Sourcing hunch after other plugins is still recommended: when two plugins both want to draw ghost text, the one that runs last is the one you see.
- Exclude
%LocalAppData%\hunch\from Windows Defender real-time scanning to avoid SQLite lock contention. - Ensure you're using Windows 10 version 1803 or later for Unix domain socket support.
Run hunch doctor for a comprehensive health check, or check the logs at ~/.local/share/hunch/hunch.log.
MIT. See LICENSE.