atuinsh/atuin · error

hook action cannot be combined with a positional agent

Error message

hook action cannot be combined with a positional agent

What it means

`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.

Solutions

  1. Use exactly one form: `atuin hook <agent>` or `atuin hook install --agent <agent>` per CLI syntax (check `atuin hook --help`).
  2. Remove the redundant positional argument when using the install action.
  3. Fix any wrapper script that passes both forms.

Example fix

# before
atuin hook install claude  # if CLI takes --agent, positional is rejected

# after
atuin hook install --agent claude
Defensive patterns

Strategy: validation

Validate before calling

# pass the agent exactly once, in the form your atuin version expects
if [ -n "$AGENT" ] && [ -n "$INSTALL" ]; then
  echo "pass either 'atuin hook <agent>' or 'atuin hook install --agent <agent>'"; exit 1
fi

Try / catch

atuin hook install --agent "$AGENT" 2>&1 | grep -q 'combined with a positional agent' && echo "remove the duplicate positional agent" 

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.

Related errors


AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19). Data as JSON: /api/errors/bbccdeb31eaeb962. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin/src/command/client/hook.rs:50

    #[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."),
        _ => None,
    }
}

View on GitHub (pinned to 900007c480)