Skip to content

fix(tools): stop reporting empty git output as a missing repository - #3291

Open
reacechalmers-lab wants to merge 1 commit into
ultraworkers:mainfrom
reacechalmers-lab:fix/git-tools-empty-output
Open

fix(tools): stop reporting empty git output as a missing repository#3291
reacechalmers-lab wants to merge 1 commit into
ultraworkers:mainfrom
reacechalmers-lab:fix/git-tools-empty-output

Conversation

@reacechalmers-lab

Copy link
Copy Markdown

Summary

The read-only Git* tools reported a successful git invocation as a failure whenever git
printed nothing, and the failure they reported was specifically "Ensure the current directory is
inside a git repository."

git_stdout ended with (!stdout.is_empty()).then_some(stdout), collapsing two distinct outcomes
— git failed, and git succeeded with nothing to say — into the same None. So a clean GitDiff,
an empty GitLog, or a blame of an empty file all claimed the repository was missing from
inside a perfectly valid one
.

That is a bad failure to hand an agent. "You are not in a repository" is a statement about the
environment, not about the query, so the model stops trusting its own working directory and starts
inventing explanations for a machine it cannot see, rather than reading the empty result as
"no changes". Observed in practice: a model received it from a clean staged diff, concluded its
filesystem access was disabled, retried the identical command three times, and ended the task
claiming work was complete that it had never done.

No machine-specific configuration is included — this is code only.

The change

The interpretation is split so the two outcomes stay distinct:

  • interpret_git_output(success, stdout) — a zero exit is success even with no stdout. Pure,
    and directly unit-tested.
  • git_stdout_allow_empty — backs the five read-only Git* tools.
  • git_stdout — keeps the non-empty requirement for the one caller where an empty value carries
    no meaning: branch --show-current on a detached HEAD.

Two things also change in what the tools return:

Success payloads carry an explicit empty flag. {"output": "", "empty": true} cannot be
misread as a failure, and it cannot be mistaken for a truncated or dropped result either.

Genuine failures name the directory git actually ran in. These tools always use the process
working directory and ignore any cdGitDiff's path is a pathspec after --, not a repo
selector — so a workspace root that is not itself a repository is the common cause and was
completely invisible in the old message. The new message names the directory and points at the
cd <repo> && git ... workaround via the bash tool.

GitShow and GitBlame keep their more specific existing error text; only the empty/failure
distinction changes for them.

Verification

  • cargo test -p tools — 123 pass, 0 fail, including 5 new tests in mod git_output_tests
  • New tests mutation-checked: restoring the .filter(|s| !s.is_empty()) turns
    treats_empty_successful_output_as_success red, then restored
  • Behaviour reproduced against real git before the fix: git diff --cached -- <clean path>
    exits 0 with 0 bytes of stdout, which the old code reported as a missing repository
  • scripts/fmt.sh --check — clean
  • cargo clippy -p tools --all-targets -- -D warnings — clean for the crate touched. The
    pre-existing crates/runtime lint errors on main are unchanged by this PR
  • cargo test --workspace — pass/fail counts identical to pristine main with these changes
    reverted; this PR introduces no new failures

🤖 Generated with Claude Code

`git_stdout` returned `None` both when git failed and when git succeeded
with no output, so every read-only `Git*` tool turned a legitimately empty
result into "Ensure the current directory is inside a git repository". A
clean `GitDiff`, an empty `GitLog`, and a blame of an empty file all
reported a missing repository from inside a perfectly valid one — which
reads to an agent as a broken environment rather than as "no changes", and
invites it to invent a cause and give up.

Split the interpretation. `interpret_git_output` treats a zero exit as
success even with no stdout; `git_stdout_allow_empty` backs the `Git*`
tools; `git_stdout` keeps the non-empty requirement for the one caller
where an empty value carries no meaning (`branch --show-current` on a
detached HEAD).

Successful results now carry an explicit `empty` flag, so "git ran and
found nothing" cannot be confused with a failure. Genuine failures name
the directory git actually ran in and point at the bash workaround: these
tools always use the process working directory and ignore any `cd`, so a
workspace root that is not itself a repository is the usual cause and was
invisible in the old message.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant