cli-guard examples/exitcode

NAME

exitcode-demo - show the public exit-code taxonomy

SYNOPSIS

exitcode-demo

DESCRIPTION

exitcode-demo exercises the public exit-code taxonomy. External consumers (orchestrators, CI steps, watchdogs, retry loops) pattern- match on the process exit code to decide retry vs. abort vs. handoff without parsing stderr. The codes are a stable contract.

The taxonomy:

0 - Success      verb ran, underlying tool returned without error
1 - Generic      catch-all, prefer a typed code over this
2 - PolicyDenied coily pre-flight rejected the call (metachar,
                 missing required arg, deny rule hit). The
                 underlying tool was never invoked.
3 - UpstreamFailed the wrapped tool ran and returned non-zero.
                 Stdout/stderr from the tool flow through; the
                 envelope's message is the wrapping error.
4 - Internal     coily-internal failure (config load, manifest
                 miss, audit-write fail). Distinct from
                 PolicyDenied because the user cannot fix it;
                 this is a coily bug or a host problem.
5 - UserError    obviously-wrong input that wasn't a metachar
                 rejection (missing flag, wrong arg count).
                 Distinct from PolicyDenied so a consumer can
                 differentiate "you typed it wrong" from "policy
                 says no".

Operating model for an agent consuming an exit code:

- 2 (PolicyDenied) is non-retryable. The argv is hostile or
  malformed in a way that the gate refuses to forward. Surface
  to operator; do not escape and retry.
- 3 (UpstreamFailed) is potentially retryable but only with the
  same argv and only if the underlying tool's exit suggests
  transience (network blip, lock contention). The wrapper does
  not retry for you. Read stderr to decide.
- 4 (Internal) is non-retryable on this host. Report a bug, try
  a different host, or wait for a fix.
- 5 (UserError) is non-retryable from automation; the operator
  needs to correct the input.

Add a new code only when an external consumer can act differently on it. Do not subdivide for taxonomy; a single rejection class with a yaml error envelope is more useful than a fan-out of codes.

Usage:

exitcode-demo [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]

COMMANDS

success

exit 0

policy

exit 2 (PolicyDenied)

upstream

exit 3 (UpstreamFailed)

internal

exit 4 (Internal)