Context
I spend a lot of time in the terminal. It's a scratchpad for me. At the time of writing, I have 57 tmux panes spread across 14 sessions. I start and stop A LOT of shells.
After installing the kiro-cli, my shell felt rather sluggish: new tabs were not immediately ready to use, and the delay showed up in both normal terminal windows and tmux.
What I measured
Before any changes, zsh -i -c exit was roughly 0.29s warm and 0.43s cold.
zsh -l -i -c exit sat around 0.31s.
What happened?
Kiro injected shell hooks into both .zshrc and .zprofile.
After gating those hooks, login-shell startup dropped to about 0.04-0.07s from 0.29-0.43s.
What I changed
- Removed Kiro hooks from shell startup.
- Moved Kiro integration behind an on-demand
kiro-cli()shell wrapper. - Swapped the prompt to
starship. Unnecessary in hindsight, but whatever. I've been wanting to try something other thanomz.
After
Current warm timings are roughly 0.04s-0.05s for both interactive and login shells, with the first shell in a batch sometimes landing around 0.09s.
Benchmark timeline
| Step | Timing |
|---|---|
| Baseline | ~0.36s |
| Remove OMZ | 0.21s faster for normal, non-login shells |
| Move Kiro hooks out of startup | faster by 0.02s-0.04s for normal shells, 0.24s on login shells |
compinit was first optimized by using compinit -C with ~/.zcompdump and compiling that cache with zcompile, but I removed that change later because it was not worth the extra maintenance.
I also tried lazy-loading Bun and terraform completion, but I removed that too for the same reason.
Takeaway
Interesting reminder about .zprofile and zsh hooks.
Relevant diffs
typeset -g _dotfiles_kiro_integration_loaded=0
_dotfiles_load_kiro_integration() {
(( _dotfiles_kiro_integration_loaded )) && return 0
_dotfiles_kiro_integration_loaded=1
[[ -f "${HOME}/Library/Application Support/kiro-cli/shell/zprofile.pre.zsh" ]] && builtin source "${HOME}/Library/Application Support/kiro-cli/shell/zprofile.pre.zsh"
[[ -f "${HOME}/Library/Application Support/kiro-cli/shell/zshrc.pre.zsh" ]] && builtin source "${HOME}/Library/Application Support/kiro-cli/shell/zshrc.pre.zsh"
[[ -f "${HOME}/Library/Application Support/kiro-cli/shell/zprofile.post.zsh" ]] && builtin source "${HOME}/Library/Application Support/kiro-cli/shell/zprofile.post.zsh"
[[ -f "${HOME}/Library/Application Support/kiro-cli/shell/zshrc.post.zsh" ]] && builtin source "${HOME}/Library/Application Support/kiro-cli/shell/zshrc.post.zsh"
}
kiro-cli() {
_dotfiles_load_kiro_integration
command kiro-cli "$@"
}
autoload -Uz compinit
if [[ -f "$HOME/.zcompdump" ]]; then
compinit -C
else
compinit
fi
if [[ -f "$HOME/.zcompdump" && ( ! -f "$HOME/.zcompdump.zwc" || "$HOME/.zcompdump" -nt "$HOME/.zcompdump.zwc" ) ]]; then
zcompile "$HOME/.zcompdump"
fi
typeset -g creates a global flag in zsh, and the (( ... )) && return 0 check makes the loader a one-time guard. That means the Kiro integration is sourced only the first time I run kiro-cli in a shell, not on every prompt.
The builtin source calls pull in Kiro’s generated shell hooks without going through my wrapper function again.
Sidenote: compinit cache
compinit reads a generated dump file, ~/.zcompdump, so zsh does not have to rediscover every completion definition on every shell launch.
I also compile that dump to ~/.zcompdump.zwc, which just makes loading the generated cache cheaper.
If the cache ever gets out of date, it is safe to delete ~/.zcompdump*. Zsh will rebuild it the next time compinit runs.