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 userView on GitHub (pinned to caf1f223d3)
Solutions
- 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`
- Or run `but agent setup` in an interactive terminal (ssh -t, docker run -it, un-piped)
- For automation, skip the wizard and commit the printed block directly
- 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
- Probe interactivity ([ -t 0 ]) before invoking interactive wizards
- Bake `but agent setup --print` into Dockerfiles/CI instead of the wizard
- When orchestrating over ssh, use `ssh -t` if prompts are actually wanted
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
- No supported agent was detected. In non-interactive mode, sp
- Refusing to directly update {target_display} without confirm
- Human input required - run this in a terminal, or specify --
- Failed to parse diff header
- BUG: It should not be possible to omit sources
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/a4392d247b3b5a69.
Report an issue: GitHub.