- Book: RAG Pocket Guide
- The series: Pocket Guides for Developers — 8 short books on agents, RAG, prompts, observability, events, databases and system design — the whole series
- My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools
- Me: xgabriel.com | GitHub
Hermes IDE 2.3.7 went out at noon UTC today, November 7, 2026, with two fixes to what your shell history saves. On macOS, a new terminal now starts with the history of earlier terminals and saves what you run. And the command Hermes types to start an agent no longer lands in your history.
I build Hermes IDE, so weigh this with that in mind. Those two bugs are a good excuse to look at the part no IDE can fix for you: your own ~/.zshrc or ~/.bashrc.
Picture the afternoon. Five panes run coding agents, a sixth is your own shell. Before one of the launches you typed export ANTHROPIC_API_KEY=.... You close the panes in a random order. Which commands survive in the history file, and is the key one of them? With bash's defaults, the answer is "whatever the last pane to exit decided". With zsh's, it is "only the panes that have exited so far", and a pane that gets killed saves nothing. Either way, the key can be in there.
Eight settings follow, each with the exact line and what breaks without it.
What actually lands in the history file
An agent's tool calls usually don't fill your history. They tend to run in child shells that aren't interactive, and bash turns command history on by default only in interactive shells (bash manual, set -o history). What lands is what gets typed at each pane's prompt: the line that starts the agent, the export you ran before it, and whatever you run in that pane after the agent exits. Each of those shells has its own idea of what the shared file should hold.

Two agent sessions side by side in Hermes IDE: Codex on orders-types and Claude Code on orders-api, each in its own hermes/ worktree, with status, context use, cost and branch in the sidebar.
zsh: get every line into the file, keep secrets out
1. INC_APPEND_HISTORY (or SHARE_HISTORY, never both)
setopt INC_APPEND_HISTORY
zsh's default APPEND_HISTORY adds to the file instead of replacing it, so panes don't overwrite each other, but it writes only when a shell exits (zsh options). A pane that gets killed takes its lines with it, and a new pane can't see what the open ones ran. INC_APPEND_HISTORY writes each line to $HISTFILE "as soon as they are entered", so a crashed pane has already saved its commands, and a new pane starts with all of them.
SHARE_HISTORY goes one step further: every shell also imports the new lines the others wrote. The zsh docs say INC_APPEND_HISTORY "should be turned off" when it is on, and that history movement "visit[s] the imported lines as well as the local lines" by default. With five agent panes, that means ↑ in your own shell can bring back a line from another pane. You can toggle that per shell with the set-local-history widget (zsh line editor). My pick for agent setups is INC_APPEND_HISTORY, with item 8 to pull other panes in when you want them.
2. HIST_IGNORE_SPACE, and bash's ignorespace
setopt HIST_IGNORE_SPACE
HISTCONTROL=ignoreboth
zsh removes "command lines from the history list when the first character on the line is a space" (zsh options). In bash, ignorespace does the same, and ignoreboth is ignorespace plus ignoredups (bash variables).
Skip it and the one-off export before an agent launch is saved like any other line, in a plain text file that any process running as you can read, including an agent's shell tool. A leading space is all it takes to keep it out. One zsh detail from the docs: the line stays in that shell's internal history until you enter the next command, so ↑ can still show it for a moment.
3. HISTORY_IGNORE for export *KEY*=
The leading space only works when you remember it. A pattern catches the times you don't:
HISTORY_IGNORE='(export *KEY*=*|export *TOKEN*=*)'
zshaddhistory() {
emulate -L zsh
[[ $1 != ${~HISTORY_IGNORE} ]]
}
HISTORY_IGNORE is one pattern, so alternatives go in (a|b) (zsh parameters). On its own it only applies "at the time history files are written": a matching line never reaches the file, but it stays in that pane's ↑ list until the shell exits. The zshaddhistory hook is the one from the same docs page. It keeps a matching line out of the history list too, though, as with a leading space, the line lingers until you run the next command (zsh hook functions).
Bash has one variable for both jobs, and its patterns "must match the complete line" (bash variables):
HISTIGNORE='export *KEY*=*:export *TOKEN*=*'
It only catches what you wrote a pattern for. The match is case-sensitive, and curl -H "Authorization: ..." sails straight past it. Add patterns for the secrets you actually type.

A pattern filter catches the secrets you forgot to hide with a leading space.
zsh: make the file readable later
4. EXTENDED_HISTORY timestamps, and bash's HISTTIMEFORMAT
setopt EXTENDED_HISTORY
HISTTIMEFORMAT='%F %T '
zsh saves "each command's beginning timestamp ... and the duration" in the form : <beginning time>:<elapsed seconds>;<command> (zsh options). history is the same as fc -l, and -i prints ISO 8601 dates, so history -i shows when each line ran (zsh builtins). In bash, setting HISTTIMEFORMAT makes the shell write timestamps to the file "so they may be preserved across shell sessions" (bash(1)).
Six panes appending to one file give you a list where you can't tell when anything ran until each line carries a time. Then you can line up "the migration ran at 14:02" against what the agent's transcript says it did. One trade-off: INC_APPEND_HISTORY writes the line before the command finishes, so the duration isn't known yet. INC_APPEND_HISTORY_TIME writes after the command ends and records it, but the zsh docs call the three options "mutually exclusive" and note other shells don't see the line right away.
5. HIST_VERIFY, and bash's histverify
setopt HIST_VERIFY
shopt -s histverify
With it, a line that uses history expansion (!!, !$, !git) is put back in the editor for you to read instead of running straight away (zsh options, bash shopt). Without it, sudo !! runs whatever !! expands to. Once your history holds lines from several panes, that may not be the command you think it is.
bash: stop the last pane from overwriting the rest
6. histappend plus PROMPT_COMMAND='history -a'
shopt -s histappend
PROMPT_COMMAND="history -a${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
When bash exits, it "copies the last $HISTSIZE entries from the history list to $HISTFILE", and unless histappend is on, it "overwrites the history file" (bash(1)). zsh appends by default; bash doesn't, so six bash panes closing in turn means the last one out wins.
histappend fixes the overwrite, but lines still wait until exit. history -a appends "the 'new' history lines" to the file (bash history builtins), and PROMPT_COMMAND runs before each prompt, so every finished command is saved. The ${PROMPT_COMMAND:+...} part keeps whatever your prompt setup already put there. Note the timing: the line lands when the next prompt appears, so a long agent session started from bash shows up in the file after the agent exits.

Six interactive shells, one history file. In bash's default setup, the last pane to exit decides what it holds.
Size the file, then pull in other panes on demand
7. HISTSIZE and SAVEHIST (bash: HISTFILESIZE)
HISTFILE=~/.zsh_history
HISTSIZE=60000
SAVEHIST=50000
setopt HIST_EXPIRE_DUPS_FIRST
HISTSIZE=50000
HISTFILESIZE=50000
In zsh, if HISTFILE is unset, history isn't saved at all, and SAVEHIST caps the file (zsh parameters). With INC_APPEND_HISTORY the file is still rewritten to trim it once it grows 20% past $SAVEHIST (zsh options). HIST_EXPIRE_DUPS_FIRST drops duplicates before unique lines, and the docs suggest HISTSIZE larger than SAVEHIST as a cushion. Bash truncates the file to HISTFILESIZE "after writing it when a shell exits" (bash(1)).
Leave the default caps and six shells feed one small file: last week's command rolls off under today's repeated test runs.
8. fc -RI in zsh, history -n in bash
fc -RI
history -n
With INC_APPEND_HISTORY, every line from every pane is in the file, but a shell that's already open doesn't read it again. fc -R reads the history file, and with -I "only those events that are not already contained within the internal history list are added" (zsh builtins). The zsh docs suggest exactly this as the manual alternative to SHARE_HISTORY. In bash, history -n reads "the history lines not already read from the history file" (bash history builtins).
Run it in your own pane when you want the command an agent pane's shell ran a minute ago, and leave your ↑ clean the rest of the time. If you'd rather have bash share all the time, add history -n to the same PROMPT_COMMAND after history -a. That is roughly SHARE_HISTORY, with the same ↑ trade-off as item 1.
Where Hermes fits, and where it doesn't
Hermes runs every agent in a real terminal (README), so your ~/.zshrc or ~/.bashrc decides what lands in the history file, as in any other terminal. Since 2.3.7, its own launch line stays out of your history, a new macOS terminal gets your earlier history, and ↑ goes to your history even with the suggestion list open. Since 2.3.2, a command holding a key, token, password or auth header is never shown as a suggestion. The same note says it plainly: "Your shell's own history is not changed." Keeping the key out of ~/.zsh_history is still items 2 and 3.
Hermes is free, source-available under BSL 1.1, and runs on macOS, Windows and Linux. It isn't affiliated with Nous Research, Anthropic, OpenAI or any agent vendor. The eight settings work the same in any terminal, with or without it.
If this was useful
A history file is a small retrieval problem: decide what gets stored, filter what should never be stored, and make it findable later. The RAG Pocket Guide asks the same questions about documents and code, with retrieval, chunking and reranking patterns for production. It's one of 8 short Pocket Guides for Developers, covering agents, RAG, prompts, observability, events, databases and system design.
If you run several agents at once, download Hermes IDE, and if it helps, star it on GitHub.

Top comments (0)