Advanced / Debugging
When things go wrong, or you want to see what's happening under the hood.
Tracing
Hash has a comprehensive tracing system for debugging. Events are written to JSONL files.
Environment variables
| Variable | Values | Default |
|---|---|---|
HASH_TRACE | editor, agent, shell, parser, or all | (disabled) |
HASH_TRACE_PATH | File path for trace output | hash-trace.jsonl |
HASH_TRACE_LEVEL | verbose, detailed, high | verbose |
Example: Enable tracing
export HASH_TRACE=all
export HASH_TRACE_PATH=/tmp/hash-trace.jsonl
export HASH_TRACE_LEVEL=detailed
hash
export HASH_TRACE_PATH=/tmp/hash-trace.jsonl
export HASH_TRACE_LEVEL=detailed
hash
After your session, examine the trace:
cat /tmp/hash-trace.jsonl | jq .
Trace output format
Each line is a JSON object with:
timestamp— RFC3339Nano formatdelta_ms— Time since last event in same subsystemsubsystem— Which component emitted the eventlevel— Verbosity levelevent— Event namedata— Event-specific data
PTY tracing
For debugging issues with interactive commands (programs that use the terminal directly), Hash has a separate PTY tracing system.
| Variable | Values | Default |
|---|---|---|
HASH_PTY_TRACE | 1 to enable | (disabled) |
HASH_PTY_TRACE_PATH | File path for PTY trace | hash-pty-trace.log |
Example: Debug a hanging command
export HASH_PTY_TRACE=1
export HASH_PTY_TRACE_PATH=/tmp/pty-debug.log
hash
export HASH_PTY_TRACE_PATH=/tmp/pty-debug.log
hash
PTY traces capture:
- I/O timestamps for stdin, stdout, PTY read/write
- Terminal drain operations (escape sequence cleanup)
- Stalled I/O detection
- Process termination reasons
Login vs interactive mode
Hash follows traditional shell conventions for startup files:
| Mode | How to invoke | Files sourced |
|---|---|---|
| Login | hash -l or via /etc/passwd | /etc/profile, ~/.profile, ~/.hash_profile, then ~/.hashrc |
| Interactive | hash (normal invocation) | ~/.hashrc |
| Non-interactive | hash -c "command" | init_commands only |
Environment markers
Hash sets these variables so scripts can detect the shell mode:
HASH_SHELL=1— Always setHASH_LOGIN=1— Set in login modeHASH_INTERACTIVE=1— Set in interactive mode
Shell identity
Hash identifies itself differently from bash/zsh:
$0is set tohash$SHELLis set to the hash binary path (in login mode)$HASH_SHELL=1is always set as a detection marker
Builtins
Hash provides these built-in commands:
| Command | Description |
|---|---|
cd [dir] | Change directory (supports ~ expansion) |
exit / quit | Exit the shell |
history | Show recent commands |
copy | Copy commands or output to clipboard |
status | Show system status (agent, history, etc.) |
tips | Show helpful tips about Hash features |
issue | Submit a GitHub issue with context |
history subcommands
history # Show recent 20 commands
history search git # Search history for "git"
history failed # Show failed commands (non-zero exit)
history sudo # Show commands run with sudo
history asked # Show agent interactions
history search git # Search history for "git"
history failed # Show failed commands (non-zero exit)
history sudo # Show commands run with sudo
history asked # Show agent interactions
copy subcommands
copy cmd # Copy last command
copy out # Copy last output
copy all # Copy command + output
copy cmd 2 # Copy 2nd-to-last command
copy out # Copy last output
copy all # Copy command + output
copy cmd 2 # Copy 2nd-to-last command
issue options
!! # Quick issue for last failure
issue "title here" # Create issue with title
issue --last # Pre-fill with last command context
issue # Open editor with template
issue "title here" # Create issue with title
issue --last # Pre-fill with last command context
issue # Open editor with template
Disabling builtins
Some tools like zoxide or eza replace standard commands. Disable builtins to let external tools take over:
config.toml
[shell]
disable_builtins = ["cd"]
disable_builtins = ["cd"]