zed/crates/eval_cli
Anant Goel a923597341
Fix agent terminal in headless eval sandbox (#59969)
# Objective

Fix the agent `terminal` tool in headless eval environments. In the eval
sandbox, terminal commands failed before the shell ran with `IOError:
Not a tty (os error 25)` because PTY setup attempted to acquire a
controlling terminal.

## Solution

- Add a `terminal::HeadlessTerminal` global that is set by `eval_cli`
only.
- When headless mode is enabled, run terminal task commands as plain
subprocesses with piped stdout/stderr instead of opening a PTY.
- Pump subprocess output through the existing terminal emulator/event
channel so output capture, completion, and task killing keep working.
- Build ACP terminal commands non-interactively in headless mode.
- Keep the normal editor terminal path unchanged when the global is
unset.
- Handle non-PTY output edge cases by preserving split CRLF sequences
and avoiding an indefinite wait if subprocess exit-status polling
errors.

## Testing

- `cargo fmt --all`
- `cargo test -p util non_interactive_omits_interactive_flag`
- `cargo test -p terminal test_no_pty_task_terminal_captures_output`
- `cargo test -p terminal test_convert_lf_to_crlf_preserves_split_crlf`
- `cargo test -p terminal test_write_output`
- `cargo check -p eval_cli`
- `git --no-pager diff --check`

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed the agent terminal tool failing with "Not a tty" in
headless/eval environments
2026-06-29 15:58:53 +00:00
..
script eval_cli: Add remote benchmark orchestration (#59802) 2026-06-24 15:32:41 +00:00
src Fix agent terminal in headless eval sandbox (#59969) 2026-06-29 15:58:53 +00:00
zed_eval eval_cli: Add remote benchmark orchestration (#59802) 2026-06-24 15:32:41 +00:00
.gitignore eval_cli: Add remote benchmark orchestration (#59802) 2026-06-24 15:32:41 +00:00
build.rs eval: Add eval_cli crate (#50922) 2026-03-06 11:12:38 +00:00
Cargo.toml eval_cli: Initialize themes in eval headless mode (#57139) 2026-05-19 11:29:00 +00:00
Dockerfile eval_cli: Add remote benchmark orchestration (#59802) 2026-06-24 15:32:41 +00:00
Dockerfile.dockerignore eval: Add eval_cli crate (#50922) 2026-03-06 11:12:38 +00:00
LICENSE-GPL eval: Add eval_cli crate (#50922) 2026-03-06 11:12:38 +00:00
README.md eval_cli: Add remote benchmark orchestration (#59802) 2026-06-24 15:32:41 +00:00

eval-cli

Headless Rust binary for running Zed's agent in evaluation and benchmark environments. It is designed for containerized harnesses such as Harbor and Pier, where the repository is already checked out and model API keys are provided via environment variables.

eval-cli uses the same NativeAgent + AcpThread pipeline as the production Zed editor: a full agentic loop with tool calls, subagents, and retries, without a GUI.

This directory also contains zed_eval/, the Python zed-eval package used to build this binary, launch remote benchmark runs on Modal/Harbor/Pier, and fetch results. For normal benchmark orchestration, start with zed_eval/README.md.

Building

Native, for local testing on the same OS

cargo build --release -p eval_cli

Linux x86_64, for Harbor/Pier sandboxes

Harbor and Pier containers run Linux x86_64. From the repository root, use the Docker-based build script:

crates/eval_cli/script/build-linux

This produces target/eval-cli, an x86_64 Linux ELF binary. You can also specify a custom output path:

crates/eval_cli/script/build-linux --output ~/bin/eval-cli-linux

Standalone usage

eval-cli \
  --workdir /testbed \
  --model anthropic/claude-sonnet-4-6 \
  --instruction "Fix the bug described in..." \
  --timeout 600 \
  --output-dir /logs/agent

eval-cli reads provider API keys from environment variables such as ANTHROPIC_API_KEY and OPENAI_API_KEY. It writes result.json, thread.md, and thread.json to the output directory.

Exit codes

Code Meaning
0 Agent finished
1 Error, such as model/auth/runtime failure
2 Timeout
3 Interrupted by SIGTERM or SIGINT

Running benchmarks

Most benchmark runs should use the Python zed-eval CLI instead of invoking eval-cli directly. From the repository root:

crates/eval_cli/script/install-zed-eval
zed-eval doctor --create-volume
zed-eval run rf --from local --n-tasks 2

For one-off source runs without installing the tool globally, use crates/eval_cli/script/zed-eval <args>.

See zed_eval/README.md for supported benchmarks, remote builds, Modal setup, reporting, rejudging, baselines, and Harbor/Pier installed agent usage.