{"record":{"id":"bbccdeb31eaeb962","repo":"atuinsh/atuin","slug":"hook-action-cannot-be-combined-with-a-positional-agent","errorCode":null,"errorMessage":"hook action cannot be combined with a positional agent","messagePattern":"hook action cannot be combined with a positional agent","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin/src/command/client/hook.rs","lineNumber":50,"sourceCode":"    #[command(subcommand)]\n    action: Option<Action>,\n\n    /// Which agent's hook format to parse (e.g., \"claude-code\")\n    #[arg(value_name = \"AGENT\", hide = true)]\n    agent: Option<String>,\n}\n\nimpl Cmd {\n    #[instrument(level = \"trace\", skip_all, err)]\n    pub async fn run(self, settings: &Settings) -> Result<()> {\n        match (self.action, self.agent) {\n            (Some(Action::Install { agent }), None) => install(&agent).await,\n            (None, Some(agent)) => handle(&agent, settings).await,\n            (None, None) => {\n                bail!(\"expected `atuin hook <agent>` or `atuin hook install <agent>`\");\n            }\n            (Some(_), Some(_)) => {\n                bail!(\"hook action cannot be combined with a positional agent\");\n            }\n        }\n    }\n}\n\nfn id_file_path(tool_use_id: &str) -> PathBuf {\n    std::env::temp_dir().join(format!(\"atuin-hook-{tool_use_id}\"))\n}\n\n/// How the user makes an agent pick up a freshly installed extension. Only the\n/// extension-based agents need a nudge; command-hook agents load on next run.\nfn reload_hint(harness_name: &str) -> Option<&'static str> {\n    match harness_name {\n        \"pi\" => Some(\"Reload pi with `/reload` or restart pi.\"),\n        \"opencode\" => Some(\"Restart opencode to load the plugin.\"),\n        _ => None,\n    }\n}","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/atuinsh/atuin/blob/900007c48045867e7f44b0f9bc55ad9dbe99ee0d/crates/atuin/src/command/client/hook.rs#L32-L68","documentation":"`atuin hook` treats a positional agent and an action as mutually exclusive: the action form is `atuin hook install <agent>` where the agent is a flag value, not a bare positional. Providing both `--install <agent>` and a positional agent is ambiguous, so `run` bails.","triggerScenarios":"Running e.g. `atuin hook install claude` where claude is also captured positionally, or combining `Some(Action::Install{..})` with `Some(agent)` in `HookCmd::run` — the `(Some(_), Some(_))` arm.","commonSituations":"Users typing `atuin hook install <agent>` expecting install to be global-ish while also passing the agent positionally; scripting that concatenates args and duplicates the agent.","solutions":["Use exactly one form: `atuin hook <agent>` or `atuin hook install --agent <agent>` per CLI syntax (check `atuin hook --help`).","Remove the redundant positional argument when using the install action.","Fix any wrapper script that passes both forms."],"exampleFix":"# before\natuin hook install claude  # if CLI takes --agent, positional is rejected\n\n# after\natuin hook install --agent claude","handlingStrategy":"validation","validationCode":"# pass the agent exactly once, in the form your atuin version expects\nif [ -n \"$AGENT\" ] && [ -n \"$INSTALL\" ]; then\n  echo \"pass either 'atuin hook <agent>' or 'atuin hook install --agent <agent>'\"; exit 1\nfi","typeGuard":null,"tryCatchPattern":"atuin hook install --agent \"$AGENT\" 2>&1 | grep -q 'combined with a positional agent' && echo \"remove the duplicate positional agent\" ","preventionTips":["Use one canonical invocation form in scripts.","Don't concatenate the agent positionally when using an install action.","Verify against `atuin hook --help` after upgrades."],"tags":["cli","mutually-exclusive","hook"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"900007c48045867e7f44b0f9bc55ad9dbe99ee0d","analyzedAt":"2026-09-19T12:52:51.491Z","contentChangedAt":"2026-09-19T12:52:51.491Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}