Skip to content

feat(cli): ExitCode enum + exit-code docs (#241, PR 1 of 2)#255

Merged
pbean merged 2 commits into
mainfrom
feat/exit-code-enum
Jul 22, 2026
Merged

feat(cli): ExitCode enum + exit-code docs (#241, PR 1 of 2)#255
pbean merged 2 commits into
mainfrom
feat/exit-code-enum

Conversation

@pbean

@pbean pbean commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

PR 1 of the two-PR exit-code taxonomy (#241) — the enum + documentation half. No behavior change.

What

  • Add ExitCode(IntEnum) to cli.pyOK=0, FAILURE=1, USAGE=2 — and use it in main()'s two dispatch-tail return paths as named constants. Because ExitCode.FAILURE == 1, the returned codes are byte-identical to before.
  • USAGE=2 names argparse's own SystemExit(2); it's documented, not rerouted through main().
  • Document the codes in a new Exit codes section under the README scripting docs, including the --json verdict-vs-error caveat (validate --json exits 1 to carry a verdict, not because it broke).

Scope guardrails (per the issue)

Tests

  • New assertions pin the enum values, guard against a code ≥3 sneaking in, and confirm members return as int (so main() -> int / sys.exit consume them transparently).
  • The exit-code characterization tests Session 2 added (test_exit_* in test_entry_point.py) stay green — they pin the raw rc numbers this enum now names.
  • Full suite green except two pre-existing, unrelated skill-sync failures (local dev-install module.yaml at 0.8.1 vs canonical 0.9.0 — gitignored installed copies, not in this diff).

Closes part of #241 (the issue stays open for PR 2).

Summary by CodeRabbit

  • Documentation

    • Added CLI exit-code documentation covering success, failures, and usage errors.
    • Clarified that JSON commands may return exit code 1 while providing a complete response, so scripts should use the JSON verdict field.
  • Bug Fixes

    • Standardized command-line failure handling to consistently return the documented exit codes while preserving error details on stderr.

Add ExitCode(IntEnum) — OK=0, FAILURE=1, USAGE=2 — in cli.py and use it in
main()'s two dispatch-tail return paths as named constants. Purely a naming +
documentation change: the values are the existing released rc numbers, so
behavior is unchanged (ExitCode.FAILURE == 1).

- USAGE=2 names argparse's own SystemExit(2); it is documented, not rerouted.
- Codes 3+ and INTERRUPTED (Ctrl+C -> 130) are deferred to the follow-up PR;
  the KeyboardInterrupt path is untouched here.
- README gains an 'Exit codes' section under the scripting docs.
- Tests assert the enum values, that no codes 3+ crept in, and that members
  return as ints; the existing rc characterization tests stay green.

This is PR 1 of #241 (enum + docs, no behavior change).
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@pbean, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 39 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 884c0b56-51b1-4837-b767-a1c82c558490

📥 Commits

Reviewing files that changed from the base of the PR and between 28835cb and bf194b6.

📒 Files selected for processing (1)
  • README.md

Walkthrough

The CLI now defines named exit codes for success, failure, and usage errors. Exception backstops return the named failure code, README documents the contract and JSON verdict behavior, and tests verify enum values and integer compatibility.

Changes

CLI exit-code contract

Layer / File(s) Summary
Define and validate exit codes
src/bmad_loop/cli.py, README.md, tests/test_entry_point.py
ExitCode defines values 0, 1, and 2; exception handlers return ExitCode.FAILURE; documentation and characterization tests cover the published contract and JSON behavior.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related issues

Possibly related PRs

Poem

A bunny found codes in a neat little row,
Zero means hop, one means errors may show.
Two marks usage when words go astray,
JSON keeps verdicts for scripts to obey.
“What a tidy CLI!” the rabbit could say.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding an ExitCode enum and documenting CLI exit codes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/exit-code-enum

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 522-534: Update the “Exit codes” section around the `ExitCode`
enum and normal command-dispatch contract to clarify that the three documented
codes apply only to those paths. Add a concise exception stating that Ctrl+C
remains an exit status of 130 until the planned follow-up change, and adjust the
“every command” wording so it does not incorrectly include interruptions.

In `@src/bmad_loop/cli.py`:
- Around line 2603-2609: Resolve Ruff BLE001 in the CLI boundary backstop around
the outer exception handler: either narrow the caught exception if the
surrounding flow permits, or add a targeted Ruff suppression for this
intentional catch. Preserve the existing stderr error message and
ExitCode.FAILURE behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 18a8ad4f-95e2-485a-a80f-7ef1ab3d6c54

📥 Commits

Reviewing files that changed from the base of the PR and between e342aba and 28835cb.

📒 Files selected for processing (3)
  • README.md
  • src/bmad_loop/cli.py
  • tests/test_entry_point.py

Comment thread README.md
Comment thread src/bmad_loop/cli.py
CodeRabbit (Major): the 'every command exits with one of three codes' claim
was wrong — an uncaught KeyboardInterrupt dies by SIGINT and exits 130, which
is not in {0,1,2}. Narrow the contract to normal dispatch + argparse usage
errors and document interruption as the one exception (130, a bare traceback
today; #241 PR 2 makes it a clean message but keeps the code).

130 stays prose-only, not an ExitCode member: PR 1 must not add codes >=3 and
INTERRUPTED is deferred to PR 2.
@pbean
pbean merged commit dc71927 into main Jul 22, 2026
9 checks passed
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