Summary
When a Codex agent runs rg and the search finds nothing, Codeg shows the terminal tool call as failed, in red. Nothing failed. Ripgrep returns exit code 1 to mean "no matches were found."
I have hit this in conversation after conversation. A successful negative search looks like a broken command, and the agent reads it the same way I do, so it retries the search or falls back to slower file scanning.
The root cause is upstream, not in Codeg. Codeg is still the layer where a fix reaches users soonest.
Environment
- Codeg Desktop 0.30.2
- Windows
- PowerShell
- Codex agents through ACP
Reproduction
- Open a Codex conversation in Codeg.
- Search for a token that does not exist:
rg -n "__definitely_absent_token__" README.md
- The command writes nothing to stdout or stderr. Codeg labels the tool call failed.
A captured ACP transcript contains this terminal result:
{
"_meta": {
"terminal_exit": {
"exit_code": 1,
"signal": null
}
},
"rawOutput": {
"exit_code": 1,
"formatted_output": ""
},
"status": "failed"
}
Repeated examples
I reproduced this in four separate Codeg conversations:
- Conversation 117:
rg -n -C 50 '"id": "CP-0090"|"id": "CP-0085"|"id": "CP-0084"' docs/backlog.json returned no output, marked failed.
- Conversation 113:
rg -n -i "Reconcile post-B-2 accessibility delta|post-B-2 accessibility|..." docs .github 2>$null returned no output, marked failed.
- Conversation 90: a bounded
rg search across the docs returned no output, marked failed.
- Conversation 103: the compound case. An initial
rg --files printed a valid filename, a later rg found nothing, and Codeg rendered the whole tool call as failed because the last process exited 1.
Real ripgrep errors look different. The same transcripts contain malformed regexes, missing paths, and invalid Windows globs, and every one of those wrote a diagnostic to stderr. Those should stay failures.
Why it happens
Ripgrep's documented exit contract is:
0: a match was found
1: no matches were found
2: an actual error occurred
Codex reports a shell command as failed whenever its exit code is nonzero. openai/codex#8268 reports the same behavior upstream, and it is closed as not planned.
Codeg keeps that wire status as-is. In src-tauri/src/parsers/acp_native.rs the parser copies the incoming status and treats status == "failed" as is_error. The UI has no neutral state left to show for an expected empty result.
Expected behavior
Show an rg run that exits 1 with no matches neutrally. Something like:
No matches found, or
Completed, no matches
It should not get the same red failure treatment as a malformed regex, a missing path, a permission denial, or a process that never launched.
Possible approaches
ACP hands Codeg a failed status, so any fix here normalizes at the integration or presentation layer. Only when all of these hold:
- the executed command is a standalone ripgrep search;
- the exit code is 1;
- there is no stderr or error diagnostic;
- the process was not canceled or denied.
Another option: a neutral nonzero-exit state such as Exited 1, no output. Or let a command declare which exit codes count as success, without rewriting the underlying ACP record.
Please do not treat every exit code 1 as success. Real errors and compound shell commands need to keep their actual meaning. Regression tests should separate four cases:
rg with matches, which is a success;
rg with no matches and no diagnostics, which is a neutral no-match;
- malformed regex or missing path, which stays a failure;
- compound and pipelined commands, which keep the overall shell result or get shown without claiming every command in the chain failed.
Impact
- Misleading red failure markers in otherwise healthy agent runs.
- Agents read a valid negative search as a broken command or a broken environment.
- Wasted retries and slower fallback scans.
- When every fourth tool call is red, you stop reading the red.
Summary
When a Codex agent runs
rgand the search finds nothing, Codeg shows the terminal tool call as failed, in red. Nothing failed. Ripgrep returns exit code 1 to mean "no matches were found."I have hit this in conversation after conversation. A successful negative search looks like a broken command, and the agent reads it the same way I do, so it retries the search or falls back to slower file scanning.
The root cause is upstream, not in Codeg. Codeg is still the layer where a fix reaches users soonest.
Environment
Reproduction
A captured ACP transcript contains this terminal result:
{ "_meta": { "terminal_exit": { "exit_code": 1, "signal": null } }, "rawOutput": { "exit_code": 1, "formatted_output": "" }, "status": "failed" }Repeated examples
I reproduced this in four separate Codeg conversations:
rg -n -C 50 '"id": "CP-0090"|"id": "CP-0085"|"id": "CP-0084"' docs/backlog.jsonreturned no output, marked failed.rg -n -i "Reconcile post-B-2 accessibility delta|post-B-2 accessibility|..." docs .github 2>$nullreturned no output, marked failed.rgsearch across the docs returned no output, marked failed.rg --filesprinted a valid filename, a laterrgfound nothing, and Codeg rendered the whole tool call as failed because the last process exited 1.Real ripgrep errors look different. The same transcripts contain malformed regexes, missing paths, and invalid Windows globs, and every one of those wrote a diagnostic to stderr. Those should stay failures.
Why it happens
Ripgrep's documented exit contract is:
0: a match was found1: no matches were found2: an actual error occurredCodex reports a shell command as failed whenever its exit code is nonzero. openai/codex#8268 reports the same behavior upstream, and it is closed as not planned.
Codeg keeps that wire status as-is. In
src-tauri/src/parsers/acp_native.rsthe parser copies the incoming status and treatsstatus == "failed"asis_error. The UI has no neutral state left to show for an expected empty result.Expected behavior
Show an
rgrun that exits 1 with no matches neutrally. Something like:No matches found, orCompleted, no matchesIt should not get the same red failure treatment as a malformed regex, a missing path, a permission denial, or a process that never launched.
Possible approaches
ACP hands Codeg a
failedstatus, so any fix here normalizes at the integration or presentation layer. Only when all of these hold:Another option: a neutral nonzero-exit state such as
Exited 1, no output. Or let a command declare which exit codes count as success, without rewriting the underlying ACP record.Please do not treat every exit code 1 as success. Real errors and compound shell commands need to keep their actual meaning. Regression tests should separate four cases:
rgwith matches, which is a success;rgwith no matches and no diagnostics, which is a neutral no-match;Impact