Initial project documentation for workflow-miner — a Rust CLI + zsh plugin that mines recurring command workflows from Atuin shell history.
4.0 KiB
4.0 KiB
Research: zsh Plugin Integration
Plugin Structure (Universal Minimum)
my-plugin/
my-plugin.plugin.zsh # Main entry point (required, name must match dir)
functions/ # Optional: autoloaded functions
_my-plugin # Optional: completion function
bin/ # Optional: executables added to $PATH
Plugin Manager Compatibility
| Manager | Loading mechanism | Install method |
|---|---|---|
| oh-my-zsh | Sources $ZSH_CUSTOM/plugins/<name>/<name>.plugin.zsh |
git clone into plugins dir, add to plugins=() |
| zinit | zinit light user/repo |
Configured in .zshrc |
| antigen | antigen bundle user/repo |
Configured in .zshrc |
| antidote | Listed in .zsh_plugins.txt |
Listed in text file |
| sheldon | TOML config | Configured in sheldon.toml |
| Manual | source /path/to/plugin.zsh |
User adds source line |
All managers expect a Git repo with a .plugin.zsh file. Host on GitHub and it works everywhere.
Zsh Plugin Standard Best Practices
From the Zsh Plugin Standard:
-
Standardized
$0handling for reliable plugin directory detection:0="${ZERO:-${${0:#$ZSH_ARGZERO}:-${(%):-%N}}}" 0="${${(M)0:#/*}:-$PWD/$0}" -
Use
functions/subdirectory for autoloaded functions and completions (managers add to$fpath) -
Use
bin/subdirectory for executables (managers add to$PATH) -
Provide an unload function named
{pluginname}_plugin_unload -
Use
add-zsh-hookfor hooks rather than definingprecmd/preexecdirectly -
Completion files named
_<command>infunctions/
ZLE (Zsh Line Editor) Mechanisms
Key variables
$BUFFER— current command line being edited$LBUFFER/$RBUFFER— left/right of cursor$CURSOR— cursor positionzle -I— invalidate display (allows printing mid-edit)zle reset-prompt— redraw prompt after external outputzle -R "message"— display message in status area
Widget pattern for LLM/suggestion integration
_my_widget() {
zle -I
local result
result=$(my-binary --some-args 2>/dev/null)
if [[ -n "$result" ]]; then
BUFFER="$result"
CURSOR=${#BUFFER}
fi
zle reset-prompt
}
zle -N _my_widget
bindkey '^X^S' _my_widget
Hook functions
preexec— fires after Enter but before execution, receives command as$1precmd— fires after command finishes, before prompt drawszshaddhistory— fires when a command is added to historychpwd— fires on directory change
Registration:
autoload -Uz add-zsh-hook
add-zsh-hook preexec my_preexec_fn
add-zsh-hook precmd my_precmd_fn
Distribution Strategy for a Rust Binary + zsh Plugin
The plugin is a thin shell wrapper around the Rust binary:
wfm-zsh/
wfm.plugin.zsh # Check binary in PATH, set up hooks, keybindings
functions/
_wfm # Completion function
The .plugin.zsh file:
- Checks if the binary is in
$PATH - Sets up shell hooks (
precmd/preexecif ambient mode) - Adds completions to
$fpath - Defines ZLE widgets and keybindings
- Defines convenience aliases/functions
Distribution:
- Host on GitHub as a standalone repo (works with all managers)
- Provide manual install instructions (
sourceline) - Binary distributed separately via
cargo installor Homebrew - Optionally submit to oh-my-zsh as a community plugin