Skip to content

Ask each agent whether it is logged in, without spending a request - #9

Merged
pathscale merged 1 commit into
masterfrom
feat/auth-status
Jul 28, 2026
Merged

pathscale merged 1 commit into
masterfrom
feat/auth-status

Conversation

@pathscale

Copy link
Copy Markdown
Owner

Answers "is each of the three agents logged in?", which previously had no clean answer: a missing login was only discoverable by running a turn and catching Error::NotAuthenticated, which costs quota and is a poor way to populate a settings screen.

for agent in Agent::ALL {
    let status = AuthStatus::check(agent).await?;
    println!("{agent}: {}", status.summary());
}

Real output from the live test:

claude-code: logged in as claude@pathscale.com (max)
codex:       logged in as ChatGPT
copilot:     unknown: copilot exposes no status command, so this cannot be
             confirmed without spending a request

What each CLI actually offers

Command Shape
Claude claude auth status --json JSON: loggedIn, authMethod, email, subscriptionType
Codex codex login status prose: "Logged in using ChatGPT"
Copilot none —

Two details worth flagging:

  • Codex needs the negative matched first, since not logged in contains logged in. Tested against all three phrasings.
  • Copilot reports Unknown, never LoggedOut. Telling someone to re-authenticate a working setup is worse than admitting the question cannot be answered, so needs_login() is true only for a confirmed logout. A host gating on it never nags about an agent that simply cannot be asked. Where a credential env var is set, that is reported as context without claiming the token is valid, since we have not checked it.

A real bug found on the way

Reading Copilot's login --help to write this turned up that COPILOT_GITHUB_TOKEN is its highest-precedence credential variable and was missing from essential_env. A host authenticating that way would have failed to authenticate at all once EnvPolicy::Minimal became the default in this release. Fixed here, ahead of publishing.

Testing

Parsing is split from spawning, so each agent's real output is unit-tested without needing its CLI installed. The live check runs by default alongside the version probe, since asking costs no quota, and fails loudly if a CLI changes its wording rather than letting the crate quietly report a working login as unknown.

107 unit tests, clippy clean, cargo package verifies.

Worth noting for release sequencing: #8 was merged while this was in flight, so 0.2.0 is already on master. This adds to it, and AuthStatus plus the COPILOT_GITHUB_TOKEN fix are both worth having in 0.2.0 rather than in a follow-up, since the token gap is a regression introduced by that release's own default change.

A missing login was only discoverable by running a turn and catching
Error::NotAuthenticated, which spends quota and is a poor way to populate a
settings screen.

AuthStatus::check(agent) asks the CLI directly. What each offers differs, and
the interface reports that difference rather than hiding it:

- Claude has `auth status`, which answers JSON, so login state, method, account
  and plan are all read directly.
- Codex has `login status`, which answers prose. The negative is matched first,
  since "not logged in" contains "logged in".
- Copilot has neither. That case is AuthState::Unknown, never LoggedOut:
  telling someone to re-authenticate a working setup is worse than admitting
  the question cannot be answered. `needs_login()` is true only for a confirmed
  logout, so gating on it never nags about an agent that cannot be asked.

Also fixes a real gap found while reading Copilot's login help:
COPILOT_GITHUB_TOKEN is the highest-precedence credential variable it accepts
and it was missing from essential_env, so a host authenticating that way would
have failed to authenticate at all once EnvPolicy::Minimal became the default.

Parsing is split from spawning so each agent's real output is unit-tested
without needing the CLI installed, and a live test checks the installed ones by
default, since asking costs no quota. That test fails if a CLI changes its
wording, rather than the crate quietly reporting a working login as unknown.
@pathscale
pathscale merged commit cb3de7e into master Jul 28, 2026
2 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