---
title: "Exit with zero only when the command did · Agent Wranglers"
url: https://agentwranglers.se/playbook/desktop-apps/command-line-tools/exit-codes
id: DSK-20
level: Recommended
updated: 2026-10-22
tokens: 902
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Exit with zero only when the command did everything it was asked

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Command-line tools](https://agentwranglers.se/playbook/desktop-apps/command-line-tools.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: DSK-20
- Level: Recommended
- Chapter: [Command-line tools](https://agentwranglers.se/playbook/desktop-apps/command-line-tools.md)
- Rule: Exit 0 only when every action succeeded, and exit with a code from 1 to 125 on any failure. Document each code in the help text and keep its meaning fixed.
- Check: A test runs each command with a missing file, a wrong flag and a server that answers 500. Each run exits with its documented non-zero code. A successful run exits 0, and the help text lists every code.
- How: Scripts, CI jobs and agents read the exit code, not the text. A tool that prints an error and exits 0 lets a broken deploy carry on. POSIX defines 0 as success and leaves 126, 127 and codes above 128 to the shell. Keep 2 for wrong usage, as many tools do. Give each failure a meaning a caller can act on, such as "not found" or "try again". [Keep error types stable](https://agentwranglers.se/playbook/api-design/errors/stable-error-types.md) asks the same of APIs. On Ctrl+C, stop cleanly and exit 130. A partial success is a failure, with the details in the output.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### Python example

```python
import sys

EXIT_OK, EXIT_FAILED, EXIT_USAGE, EXIT_NOT_FOUND, EXIT_RETRY = 0, 1, 2, 3, 4

def main() -> int:
    try:
        invoice = client.fetch(args.invoice_id)
    except NotFound:
        print(f"invoice {args.invoice_id} not found", file=sys.stderr)
        return EXIT_NOT_FOUND
    except ServiceUnavailable:
        print("service unavailable, try again later", file=sys.stderr)
        return EXIT_RETRY
    print(invoice.number)
    return EXIT_OK

if __name__ == "__main__":
    sys.exit(main())
```

### Go example

```go
const (
	exitOK       = 0
	exitFailed   = 1
	exitUsage    = 2
	exitNotFound = 3
	exitRetry    = 4
)

func main() {
	invoice, err := client.Fetch(invoiceID)
	switch {
	case errors.Is(err, ErrNotFound):
		fmt.Fprintf(os.Stderr, "invoice %s not found\n", invoiceID)
		os.Exit(exitNotFound)
	case err != nil:
		fmt.Fprintln(os.Stderr, "service unavailable, try again later")
		os.Exit(exitRetry)
	}
	fmt.Println(invoice.Number)
}
```

## Sources

- [POSIX.1-2024, Exit Status for Commands](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_08_02)

## Related rules

- API-17 [Keep error types stable](https://agentwranglers.se/playbook/api-design/errors/stable-error-types.md) in API design

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/desktop-apps/command-line-tools/exit-codes">Agent Wranglers desktop apps, extensions and CLIs playbook</a>`. In code you write, add a comment next to it with the same link.

- Next: [Write results to stdout and everything else to stderr](https://agentwranglers.se/playbook/desktop-apps/command-line-tools/stdout-stderr.md)
- [Command-line tools](https://agentwranglers.se/playbook/desktop-apps/command-line-tools.md)
