Skip to content

feat: distinguish failures by exit code and add --exec to the CLI - #75

Merged
jferrl merged 1 commit into
mainfrom
feat/agentic-cli
Sep 19, 2026
Merged

jferrl merged 1 commit into
mainfrom
feat/agentic-cli

Conversation

@jferrl

@jferrl jferrl commented Sep 19, 2026

Copy link
Copy Markdown
Owner

Summary

Every CLI failure exits 1 today, so a caller cannot tell a rate limit from a
revoked key from an installation that does not exist, and retries all of them.
The library makes that unavoidable: only throttling has a typed error, and every
other rejection collapses into a string the CLI would have to pattern-match.
This adds APIError to the library, an exit code per failure class to the CLI,
and --exec, which hands the credential to a command instead of printing it
where a log or an agent transcript will keep it for the hour it stays valid.

Changes

  • APIError{StatusCode, Message} replaces an untyped fmt.Errorf for every non-throttling rejection. Error() renders the identical string, so existing callers keep working.
  • Exit codes: 2 bad invocation, 3 credential or permissions refused, 4 rate limited, 5 App not installed there. Documented in githubauth help.
  • --exec -- <cmd> runs a command with the token in $GITHUB_TOKEN, prints nothing, and exits with the command's own code.
  • Under --json or a detected coding agent, a failure is one githubauth.error JSON document on stdout with stderr silent, carrying exit_code, status_code, retry_after_seconds and suggestions.

Rationale

Agent mode changes errors only. Grafana's gcx
flips its default output format on detection, which works because its output is
data; ours is a credential meant for $(githubauth token), and flipping it would
make the README's own curl example send a JSON object as the bearer token inside
an agent session.

Migration Notes

  • The CLI exit codes are a behaviour change: a script testing $? -eq 1 now sees 2, 3 or 5 for some failures. The library change is additive.
  • A test suite that shells out to githubauth from inside a coding agent should set GITHUBAUTH_AGENT_MODE=0. This repo's own suite needed it — the tests inherited CLAUDECODE=1 and found errors on stdout.
  • CHANGELOG.md is untouched, since this repo cuts it at release time.

🤖 Generated with Claude Code

Every CLI failure exited 1, so a caller could not tell a rate limit from
a revoked key from an installation that does not exist, and retried all
of them. The library made that unavoidable: only throttling had a typed
error, and every other rejection collapsed into a fmt.Errorf string the
CLI would have had to pattern-match.

APIError carries the status code instead. Its Error() renders the same
string the fmt.Errorf did, so callers that log or match on the message
keep working, and the CLI now maps status to an exit code: 3 for a
credential GitHub refused, 4 for throttling, 5 for an App that is not
installed where it was asked to be. A missing key file and a rejected
key both exited 1 before and now exit 2 and 3.

--exec runs a command with the credential in $GITHUB_TOKEN and prints
it nowhere. A printed installation token stays valid for an hour in
every log, scrollback and agent transcript that captured the output,
and --exec is the way not to put it there.

Agent mode was deliberately limited to errors. Grafana's gcx flips its
default output format when it detects an agent, which works because its
output is data; ours is a credential meant for $(githubauth token), and
flipping it would have made the README's own curl example send a JSON
object as the bearer token inside an agent session. So detection routes
failures to stdout as one githubauth.error document and adds a stderr
hint, and leaves the token line alone.

Running the suite inside a coding agent showed why this matters: the
tests inherited CLAUDECODE=1 and found errors on stdout. They now pin
GITHUBAUTH_AGENT_MODE=0, which is what any downstream suite that shells
out to githubauth will need.
@codecov

codecov Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.71053% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.75%. Comparing base (50b8e00) to head (bf40e4f).

Files with missing lines Patch % Lines
cmd/githubauth/errors.go 97.33% 2 Missing ⚠️
cmd/githubauth/main.go 95.74% 2 Missing ⚠️
cmd/githubauth/exec.go 94.44% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #75      +/-   ##
==========================================
- Coverage   96.96%   96.75%   -0.22%     
==========================================
  Files           5        8       +3     
  Lines         462      586     +124     
==========================================
+ Hits          448      567     +119     
- Misses         14       19       +5     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jferrl
jferrl merged commit f4e8c7b into main Sep 19, 2026
8 of 10 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