Exit codes lie to agents. Output parsing tells the truth.
Our coding agent kept declaring "Tests passing!" while our CI was throwing red screens everywhere. The problem? It was reading exit codes instead of actually checking test output.
Exit codes lie to agents constantly. A test runner exits 0 even when half the tests are skipped. A build script exits 0 even when it compiled nothing. A deployment exits 0 even when the health checks are screaming.
Here's what we changed: instead of trusting exit codes, our agent now parses actual output and looks for specific success indicators.
def verify_test_results(command_output):
# Don't trust exit codes - parse the actual results
if "FAILED" in command_output:
return False, "Tests failed - check output above"
if "ERROR" in command_output:
return False, "Test errors detected"
# Look for actual pass indicators
if re.search(r'\d+ passed', command_output):
return True, "Tests verified passing"
# If we can't verify success, assume failure
return False, "Cannot verify test success"The pattern works for everything. When deploying, don't trust the deployment script's exit code — check if the health endpoint actually responds. When running builds, don't trust make's exit code — verify the binary actually exists and has a recent timestamp.
Warning: This gets expensive fast if you're not careful. Our agent was re-running tests three times because it couldn't parse pytest's output format. Set clear success patterns upfront.
We added verification rules to our agent's system prompt:
VERIFICATION RULES: - Never trust exit codes alone - Always parse command output for actual results - Look for specific success indicators: "X passed", "deployed successfully", "build complete" - If you can't verify success from output, treat as failure - When in doubt, check the actual state (files exist, endpoints respond, etc.)
The difference is dramatic. Before: "Great! All tests are passing!" while our staging environment was down. After: "Tests failed - 3 integration tests are hitting timeout errors on the auth endpoint."
Your agent needs to be paranoid about success. Exit codes are suggestions. Output parsing is verification. But the real test is checking if the thing you built actually works.
This applies to everything your coding agent touches. Database migrations, API deployments, dependency installations — they all lie through exit codes. Make your agent verify the actual outcome, not just trust what the command claims happened.