atuinsh/atuin · error
expected `atuin hook
Error message
expected `atuin hook <agent>` or `atuin hook install <agent>`
What it means
`atuin hook` supports two forms: `atuin hook <agent>` (fire the hook) or `atuin hook install <agent>` (install it). Running it with neither an action nor an agent gives no usable target, so `run` bails with usage guidance.
Solutions
- Pass an agent: `atuin hook <agent>` to fire, or `atuin hook install <agent>` to install.
- Check `atuin hook --help` for valid agents.
- If invoked from a shell hook, verify the agent variable is set and quoted in the hook script.
Example fix
# before atuin hook # after atuin hook install claude # or: atuin hook claude
Defensive patterns
Strategy: validation
Validate before calling
# shell: validate args before calling case "$#" in 0) echo "usage: atuin hook <agent> | atuin hook install <agent>"; exit 1;; esac
Try / catch
atuin hook "$AGENT" || { echo "hook failed; pass an agent, e.g. atuin hook claude"; exit 1; } Prevention
- Always pass an agent argument in shell hook scripts.
- Quote and default the AGENT variable in wrapper scripts.
- Check `atuin hook --help` for accepted agents.
When it happens
Trigger: Running bare `atuin hook` with no arguments — the match arm `(None, None)` in `HookCmd::run`.
Common situations: Typing the subcommand to explore it without args; a shell hook script losing its argument due to quoting bugs or an unset variable.
Understand the failure class
Background: "no subcommand specified" and "... is required": CLI errors when a required argument is missing — this error's family across 13 libraries.
Related errors
- `atuin hook ` is not supported. Use `atuin hook install `.
- hook action cannot be combined with a positional agent
- A script named ' ' already exists
- agent does not use JSON hooks
- `atuin history tail` requires Atuin to be built with the…
AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19).
Data as JSON: /api/errors/4b1f01d9a6592385.
Report an issue: GitHub.
Appendix: source
Thrown at crates/atuin/src/command/client/hook.rs:47
#[derive(Parser, Debug)]
#[command(infer_subcommands = true, args_conflicts_with_subcommands = true)]
pub struct Cmd {
#[command(subcommand)]
action: Option<Action>,
/// Which agent's hook format to parse (e.g., "claude-code")
#[arg(value_name = "AGENT", hide = true)]
agent: Option<String>,
}
impl Cmd {
#[instrument(level = "trace", skip_all, err)]
pub async fn run(self, settings: &Settings) -> Result<()> {
match (self.action, self.agent) {
(Some(Action::Install { agent }), None) => install(&agent).await,
(None, Some(agent)) => handle(&agent, settings).await,
(None, None) => {
bail!("expected `atuin hook <agent>` or `atuin hook install <agent>`");
}
(Some(_), Some(_)) => {
bail!("hook action cannot be combined with a positional agent");
}
}
}
}
fn id_file_path(tool_use_id: &str) -> PathBuf {
std::env::temp_dir().join(format!("atuin-hook-{tool_use_id}"))
}
/// How the user makes an agent pick up a freshly installed extension. Only the
/// extension-based agents need a nudge; command-hook agents load on next run.
fn reload_hint(harness_name: &str) -> Option<&'static str> {
match harness_name {
"pi" => Some("Reload pi with `/reload` or restart pi."),
"opencode" => Some("Restart opencode to load the plugin."),View on GitHub (pinned to 900007c480)