gitbutlerapp/gitbutler · error · anyhow::Error

Interactive setup requires a terminal. Use `but agent setup

Error message

Interactive setup requires a terminal. Use `but agent setup --print` to print the default instructions without modifying files.

What it means

`but agent setup` runs an interactive wizard that needs a real terminal for prompts (via `out.prepare_for_terminal_input()`). When `out.can_prompt()` is false the command bails with this message and points at the non-interactive alternative `but agent setup --print`, which prints the default instructions without touching any files.

Source

Thrown at crates/but/src/command/agent/mod.rs:66

) -> Result<()> {
    match cmd {
        // Bare `but agent` runs the setup wizard, same as `but agent setup`.
        None => setup(current_dir, out, false),
        Some(agent::Subcommands::Setup { print }) => setup(current_dir, out, print),
    }
}

fn setup(current_dir: &Path, out: &mut OutputChannel, print_only: bool) -> Result<()> {
    if print_only {
        let default_policy = render_managed_policy_block(&WizardAnswers::default());
        print_policy(out, &default_policy)?;
        return Ok(());
    }

    let repo = discover_repo(current_dir);

    if !out.can_prompt() {
        anyhow::bail!(
            "Interactive setup requires a terminal. Use `but agent setup --print` to print the default instructions without modifying files."
        );
    }

    let mut input = out
        .prepare_for_terminal_input()
        .context("Interactive setup requires a terminal.")?;

    let plan = collect_plan(&mut input, repo)?;
    drop(input);

    match plan {
        Some(plan) => apply_plan(out, current_dir, &plan),
        None => print_cancelled(out),
    }
}

/// Run the interactive wizard. Returns the confirmed plan, or `None` if the user

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Use `but agent setup --print` to get the default policy text, and write it to the target file yourself: `but agent setup --print > AGENTS.md`
  2. Or run `but agent setup` in an interactive terminal (ssh -t, docker run -it, un-piped)
  3. For automation, skip the wizard and commit the printed block directly
  4. If you need TTY prompts over ssh, force tty allocation with `ssh -t`

Example fix

# before (in CI, fails):
but agent setup

# after (non-interactive):
but agent setup --print > AGENTS.md
git add AGENTS.md
Defensive patterns

Strategy: validation

Validate before calling

if [ -t 0 ] && [ -t 1 ]; then but agent setup; else but agent setup --print > AGENTS.md; fi

Try / catch

# shell: fall back to the non-interactive form when the tty check fails
if ! but agent setup 2>&1 | tee /dev/stderr | grep -q 'requires a terminal'; then :; else but agent setup --print > AGENTS.md; fi

Prevention

When it happens

Trigger: Running `but agent setup` (without --print) when stdout/stdin is not a TTY: piped output (`but agent setup | cat`), CI jobs, cron, ssh with no tty, non-interactive scripts, or a harness that captures output

Common situations: Setting up agent instructions in a Dockerfile or CI pipeline; Ansible/Puppet provisioning that runs `but` non-interactively; piping but output to tee or a log file; running through an IDE task runner that allocates no pty

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/a4392d247b3b5a69. Report an issue: GitHub.