Skip to content

feat(menu): unify Claude and Codex account switching (view-only segments, shared System Account submenu) - #3550

Closed
zenibako wants to merge 16 commits into
steipete:mainfrom
zenibako:feat/claude-swap-view-only-accounts
Closed

zenibako wants to merge 16 commits into
steipete:mainfrom
zenibako:feat/claude-swap-view-only-accounts

Conversation

@zenibako

@zenibako zenibako commented Sep 11, 2026

Copy link
Copy Markdown
Contributor
claude-swap-view-only-light claude-swap-view-only-dark

Why

Claude and Codex should behave the same way, so expectations don't differ per provider. Before this PR they didn't:

  • Clicking a Codex segment changes which account CodexBar follows. It never touches the Codex CLI login; that happens in the System Account submenu.
  • Clicking a Claude (claude-swap) segment ran cswap --switch-to, changing Claude Code's login from a click that looks like "show me this account".

This PR gives both providers one model: segments select, the System Account submenu switches.

What

1. Claude segment clicks are view-only.

  • Clicking a claude-swap segment only changes which account's details are shown. It never runs cswap.
  • The viewed account is keyed by ProviderAccountIdentity. It survives refreshes, reordering and menu closes for the session, and is not persisted across restarts. It never changes which account drives the menu bar quota.
  • It is dropped when the adapter is disabled or its executable changes. If its slot disappears, it falls back to the source-reported active account, and it never invents one.
  • Unavailable accounts stay inspectable. A view selection outranks a pending or failed switch, and a switch error stays attached to the account that produced it.

2. One shared account switcher for Claude and Codex.

  • AccountSegmentedSwitcherView replaces CodexAccountSwitcherView and ClaudeSwapAccountSwitcherView. It owns the layout, selection styling, click tracking, hit-testing, tooltips and accessibility.
  • Providers only supply labels. Codex's width-aware email/workspace/discriminator titles and private ordinals moved into CodexAccountSwitcherLabeling as pure functions.
  • Shared vocabulary: the filled segment is Selected, and a leading marks the System account, the one the CLI uses (Codex isLive, claude-swap active slot).
  • CodexAccountSwitcherView remains as an override-free subclass, so menu reuse still recognizes the Codex row.

3. One shared System Account submenu for switching.

  • Codex's existing submenu becomes a shared builder behind two defaulted ProviderImplementation hooks.
  • A provider-neutral requestSystemAccountSwitch action replaces requestCodexSystemPromotion.
  • Codex: promotion eligibility and CodexAccountPromotionCoordinator are unchanged. Submenu titles now honor Hide Personal Info; previously they showed raw emails. The submenu title is now localized.
  • Claude: claude-swap accounts appear while claude-swap owns Claude account presentation. The active slot is checked, and inactive slots with usable credentials are enabled. Choosing one awaits the existing serialized cswap --switch-to <slot> --json transaction.
  • Claude cards: they no longer offer "Switch Account…" for inactive slots. They keep fix(claude): preserve historical account usage and explicit repair #3452's accent Active badge and its explicit Re-authenticate repair action for an active slot claude-swap marks re-activatable (foreign_credential).

4. Switch feedback.

  • The target card's subtitle shows "Switching Claude Code to Account 7…" and then "Account 7 is now the System account", for every layout:
    • segmented and single live cards;
    • stacked and compact Codex account cards;
    • claude-swap account cards.
  • An error already on the card outranks progress and success. That includes a claude-swap switch error published before the follow-up Claude refresh finishes.
  • A card showing switch feedback stops following the live refresh monitor's provider status, so the feedback is what renders. The header resolves its subtitle through MenuCardLiveSubtitle.resolve.
  • When no menu is open at completion, a notification reports success or failure. If a failure notice can't be delivered (notifications not authorized), the alert Codex showed before is presented instead.

5. The claude-swap executable has a real default, and its settings are grouped.

  • ~/.local/bin/cswap was only the settings field's placeholder, so enabling the adapter without typing a path silently did nothing.
  • The default now applies, but only when something executable is at that path.
  • An explicit path always wins, including when it is missing.
  • The toggle, executable field, adapter status and discovered accounts render as one settings section through supplementarySettingsContent, the slot Codex already uses.

Behavior changes for existing users

  • Claude: clicking a segment no longer switches accounts, and cards no longer offer "Switch Account…"; use System Account in the menu. Re-authenticate stays on the active card. This is covered in the changelog and docs/claude.md.
  • Codex:
    • the live account gains a in the switcher;
    • a failed promotion shows on the card while the menu is open;
    • when the menu is closed, a failed promotion is reported by notification, with the previous alert as fallback when notifications aren't allowed.
  • Upgrades with the claude-swap adapter enabled and an empty saved path start using ~/.local/bin/cswap if it is installed there. Otherwise nothing runs, as before.

Proof

The signed synthetic native proofs are opt-in via CODEXBAR_CLAUDE_SWAP_VIEW_PROOF_DIR. They require credential isolation and use synthetic accounts and stub executables only.

  • Screenshots: the production switcher in Light and Dark, viewing slots 2, 7 and 9 while slot 2 is System.

  • Segments vs submenu (menu-owner.json):

    • Clicking every segment through the real menu's switcher view starts 0 activations: no switch task, and no stub --switch-to invocation.
    • The System Account submenu checks slot 2, enables only slot 7, and disables unavailable slot 9.
    • Choosing slot 7 runs exactly --switch-to 7 --json and posts one notice: "Claude Code now uses Account 7".
  • Executable discovery (discovery.json), run through the production config loader, resolver and reader:

    Config Result
    Fresh config, cswap at the default listed 3 accounts
    Fresh config, nothing at the default idle, nothing run
    Upgraded config with a saved empty path, cswap at the default listed 3 accounts
    Explicit path, default also installed explicit binary used
    Explicit path that does not exist "Missing CLI" error; the default is never run

Testing

  • Rebased on main 62a7fa1c.
  • make check: 0 violations, including the app locale checker.
  • Full sharded suite (Scripts/test.sh): 106/106 groups pass on the first pass, with nothing skipped.
  • Review fixes, each with a test that fails without it:
    • a published claude-swap switch error outranks progress;
    • stacked and compact Codex account cards show progress and failure for the promoted account only;
    • an applied subtitle wins over a live MenuCardRefreshMonitor.
  • Alert fallback: an undelivered failure notice raises the fallback alert, and an undelivered success notice does not. Both tests use injected delivery; no UI is shown.
  • Other new coverage:
    • the shared switcher view, the feedback model, the submenu builder, and the applied subtitle;
    • the Codex adapter (promotion plus an unknown account) and redacted Codex submenu titles;
    • the Claude adapter (entries, success, failure, unavailable slot, controller notice) and the card repair action being offered only for active repair.
  • Migrated: existing Codex and Claude switcher, menu and proof tests.
  • No real cswap, provider probe or Keychain read in any test.

Notes

Not included

The merged-menu row-height bug from #3549 is fixed separately in #3616.

🤖 Generated with Claude Code

https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R

@clawsweeper

clawsweeper Bot commented Sep 11, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8a9b9cae89

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +107 to +108
var resolvedClaudeSwapExecutablePath: String {
Self.resolveClaudeSwapExecutablePath(configured: self.claudeSwapExecutablePath)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Share the default executable path with CLI consumers

When the new settings UI is enabled with its path left blank, the config still stores no claudeSwapExecutablePath; only this app-scoped computed property supplies ~/.local/bin/cswap. Consequently, codexbar cards still resolves the path to "" in CLIClaudeSwapCards.executablePath, and dashboard collection does the same in CLIDashboardCommand, so both pass an unconfigured path to ClaudeSwapAccountReader even though the menu-bar app now works. Put the fallback in shared config/path resolution or apply it at both CLI call sites as well.

AGENTS.md reference: AGENTS.md:L4-L4

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Sep 11, 2026
@clawsweeper

clawsweeper Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed September 14, 2026, 10:25 AM ET / 14:25 UTC (Revision 11).

ClawSweeper review

What this changes

Unifies Claude and Codex account menus, separates viewing from activation, adds switch feedback, and groups Claude adapter settings with automatic executable discovery.

Merge readiness

Blocked before merge - 5 items remain

This PR remains distinct from the merged account-menu work. Earlier privacy and subtitle fixes are preserved, but the previously reported feedback-identity defect remains unresolved.

Priority: P2
Reviewed head: e34d465b755bb47f0ad5c84eb84e2e49ffcabb42
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) Useful native evidence and substantial coverage support the patch, but an existing correctness finding and a specific notification proof gap remain.
Proof confidence 🦐 gold shrimp (3/6) Needs stronger real behavior proof before merge: Inspected native artifacts demonstrate Claude selection styling, private Codex card feedback and actual alert presentation after injected delivery failure. AppNotifications still lacks after-fix evidence of real macOS delivery and denied-permission recovery, explicitly excluded by the proof document. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Patch quality 🦐 gold shrimp (3/6) 1 actionable review finding remain.

Verification

Check Result Evidence
Real behavior Needs proof Needs stronger real behavior proof before merge: Inspected native artifacts demonstrate Claude selection styling, private Codex card feedback and actual alert presentation after injected delivery failure. AppNotifications still lacks after-fix evidence of real macOS delivery and denied-permission recovery, explicitly excluded by the proof document. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed 9 items Complete introduced scope: The local pinned base-to-head comparison contains 91 files, 3,801 additions and 824 deletions. This recovers the files omitted from the supplied patch; no dependency, workflow, or release-script change belongs to this introduced delta.
Still distinct from main and release: Current main and v0.60.2 still activate healthy inactive Claude accounts from segment selection. Main also lacks the shared executable resolver. The merged layout, privacy, historical-usage and row-sizing PRs do not implement this PR's complete interaction change.
Feedback retains a transient visible identity: The controller captures the visible account ID before promotion. The existing projection changes same-email managed account IDs to live IDs after promotion, while account cards require an exact feedback-ID match. The promotion service refreshes account state before returning, so completion feedback can no longer match its target card.
Findings 1 actionable finding [P2] [P2] Keep switch feedback keyed to a stable Codex account identity
Security None None.

How this fits together

CodexBar turns provider account snapshots into menu cards and account controls. Explicit System Account actions call the existing provider switching transactions, then display progress and completion feedback.

flowchart TD
  A[Provider account snapshots] --> B[Shared account menu]
  B --> C[Select account to view]
  C --> D[Usage card]
  B --> E[Explicit System Account choice]
  E --> F[Existing provider switching transaction]
  F --> G[Card feedback or notification]
Loading

Decision needed

Question Recommendation
Should existing Claude installations adopt view-only segments, submenu-only switching, and executable discovery for an enabled adapter with an empty saved path? Accept the documented transition: Approve the unified interaction and default-path behavior after the feedback defect and notification proof gap are resolved.

Why: These deliberately change shipped interaction and configuration semantics; documentation and synthetic upgrade checks establish behavior but cannot establish maintainer acceptance.

Before merge

  • Add real behavior proof - Needs stronger real behavior proof before merge: Inspected native artifacts demonstrate Claude selection styling, private Codex card feedback and actual alert presentation after injected delivery failure. AppNotifications still lacks after-fix evidence of real macOS delivery and denied-permission recovery, explicitly excluded by the proof document. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • [P2] Keep switch feedback keyed to a stable Codex account identity (P2) - This previously reported defect remains. With multiple Codex workspaces sharing an email, promotion changes the target's visible ID from managed:&lt;UUID> to live:&lt;identity>. Feedback captures the former here, and codexAccountMenuCardModel matches against the latter after the promotion refresh, so the target loses its success feedback in stacked/compact layouts; private notification lookup also falls back to a generic account label. Retain the persisted managed-account identity and resolve its current display row when rendering, with a same-email promotion regression.
  • Resolve merge risk (P1) - Existing Claude users must switch accounts through a different control, and enabled installations with an empty saved path will begin executing an installed ~/.local/bin/cswap after upgrade; explicit maintainer acceptance of this transition remains unrecorded.
  • Complete next step (P2) - Repair the feedback identity defect, provide actual macOS notification delivery and permission-denial proof, and obtain acceptance of the documented upgrade transition.
  • Resolve maintainer decision - Resolve the maintainer decision shown above before merge.

Findings

  • [P2] [P2] Keep switch feedback keyed to a stable Codex account identity — Sources/CodexBar/StatusItemController+SystemAccountSwitch.swift:67-71
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production and test growth Production +817 net lines; tests +2,023 net lines Production totals include locale strings; growth supports the stated shared controls, feedback and settings work, with substantial regression and native-proof coverage.

Merge-risk options

Maintainer options:

  1. Approve the tested transition (recommended)
    Accept the documented fresh/upgrade behavior after correcting feedback identity and completing native notification validation.
  2. Keep blank-path upgrades inert
    Retain current empty-path behavior for existing configurations and make executable discovery an explicit setup action.

Technical review

Best possible solution:

Keep shared presentation and existing transaction owners, bind feedback to stable account identity, and ship the interaction/default transition only with explicit acceptance and native notification evidence.

Do we have a high-confidence way to reproduce the issue?

Yes, by source inspection: promote a managed Codex workspace among accounts sharing an email, then rebuild its stacked or compact card; its visible ID changes while feedback retains the old ID. No runtime reproduction was executed in this read-only review.

Is this the best way to solve the issue?

Unclear until the upgrade direction is accepted; sharing controls while retaining existing switching owners is maintainable, but feedback must use stable identity and the notification path needs real native validation.

Full review comments:

  • [P2] [P2] Keep switch feedback keyed to a stable Codex account identity — Sources/CodexBar/StatusItemController+SystemAccountSwitch.swift:67-71
    This previously reported defect remains. With multiple Codex workspaces sharing an email, promotion changes the target's visible ID from managed:&lt;UUID> to live:&lt;identity>. Feedback captures the former here, and codexAccountMenuCardModel matches against the latter after the promotion refresh, so the target loses its success feedback in stacked/compact layouts; private notification lookup also falls back to a generic account label. Retain the persisted managed-account identity and resolve its current display row when rendering, with a same-email promotion regression.
    Confidence: 0.98

Overall correctness: patch is incorrect
Overall confidence: 0.96

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against a5f2c581ce2e.

Labels

Label justifications:

  • P2: This is a bounded account-menu improvement with a remaining feedback defect, rather than an urgent runtime outage.
  • merge-risk: 🚨 compatibility: The patch changes existing Claude activation controls and makes enabled empty-path configurations discover and execute a default binary.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: Inspected native artifacts demonstrate Claude selection styling, private Codex card feedback and actual alert presentation after injected delivery failure. AppNotifications still lacks after-fix evidence of real macOS delivery and denied-permission recovery, explicitly excluded by the proof document. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. Inspected native artifacts demonstrate Claude selection styling, private Codex card feedback and actual alert presentation after injected delivery failure. AppNotifications still lacks after-fix evidence of real macOS delivery and denied-permission recovery, explicitly excluded by the proof document.

Evidence

What I checked:

  • Complete introduced scope: The local pinned base-to-head comparison contains 91 files, 3,801 additions and 824 deletions. This recovers the files omitted from the supplied patch; no dependency, workflow, or release-script change belongs to this introduced delta. (e34d465b755b)
  • Still distinct from main and release: Current main and v0.60.2 still activate healthy inactive Claude accounts from segment selection. Main also lacks the shared executable resolver. The merged layout, privacy, historical-usage and row-sizing PRs do not implement this PR's complete interaction change. (Sources/CodexBar/Providers/Claude/StatusItemController+ClaudeSwapMenu.swift:83, 3335e8a0d4d7)
  • Feedback retains a transient visible identity: The controller captures the visible account ID before promotion. The existing projection changes same-email managed account IDs to live IDs after promotion, while account cards require an exact feedback-ID match. The promotion service refreshes account state before returning, so completion feedback can no longer match its target card. (Sources/CodexBar/StatusItemController+SystemAccountSwitch.swift:69, e34d465b755b)
  • Existing projection explains the transition: For multiple accounts sharing an email, visibleAccountID returns live:<identity> for the live account and managed:<UUID> for a managed account; storedAccountID survives that transition. (Sources/CodexBarCore/Providers/Codex/CodexVisibleAccountProjection.swift:312, e34d465b755b)
  • Prior finding remains applicable: The feedback model, controller and Codex card integration are unchanged from the preceding reviewed revision. The shared CLI resolver, error precedence, live-subtitle override and privacy repairs are present; the latest merge resolves base integration without repairing the outstanding identity finding. (Sources/CodexBar/Providers/Codex/StatusItemController+CodexAccountCard.swift:18, e34d465b755b)
  • Native proof inspected: Inspected both prepared Claude selection images and repository images showing private Codex progress and the actual fallback alert. These demonstrate rendered native behavior. The proof document explicitly excludes macOS notification authorization, successful delivery and actual permission-denial handling; the native test injects delivery failure before presenting the alert. (docs/screenshots/system-account-switch-feedback-proof.md:22, e34d465b755b)

Likely related people:

  • unknown: The claimed source-line change could not be verified from bounded local history. (role: source history unknown; confidence: low)
  • Chandler Anderson: Raw commit 4cfb606 adds Sources/CodexBar/CodexAccountSwitcherLabeling.swift:8 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 4cfb60692bdd; files: Sources/CodexBar/CodexAccountSwitcherLabeling.swift)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Preserve feedback through same-email workspace promotion and add a focused regression.
  • Add redacted native notification-delivery and permission-denial evidence through AppNotifications; screenshots or recordings are preferred when informative, and logs are acceptable. Remove private details before posting, then update the PR body to trigger review or ask a maintainer to comment @clawsweeper re-review.
  • Obtain explicit acceptance of the documented interaction and executable-discovery transition.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (10 earlier review cycles; latest 8 shown)
  • reviewed 2026-09-11T13:29:17.594Z sha 1adbaad :: needs real behavior proof before merge. :: none
  • reviewed 2026-09-12T18:57:51.113Z sha 1adbaad :: needs real behavior proof before merge. :: none
  • reviewed 2026-09-13T00:51:37.049Z sha 581af6f :: needs real behavior proof before merge. :: none
  • reviewed 2026-09-13T10:33:33.446Z sha 8c70fa9 :: needs real behavior proof before merge. :: [P2] [P2] Let published Claude switch errors override progress | [P2] [P2] Route switch feedback into stacked Codex cards
  • reviewed 2026-09-13T11:15:13.021Z sha 88cc007 :: needs real behavior proof before merge. :: [P2] [P2] Let published Claude switch errors override progress | [P2] [P2] Route switch feedback into stacked Codex cards | [P2] [P2] Preserve overrides through the live subtitle renderer
  • reviewed 2026-09-13T11:53:00.098Z sha df3df0c :: needs real behavior proof before merge. :: [P2] [P2] Let published Claude switch errors override progress | [P2] [P2] Route switch feedback into stacked Codex cards | [P2] [P2] Preserve overrides through the live subtitle renderer
  • reviewed 2026-09-13T14:06:35.989Z sha 0c775b8 :: needs real behavior proof before merge. :: [P2] [P2] Reapply privacy when rendering switch feedback
  • reviewed 2026-09-14T13:30:12.161Z sha eaed799 :: needs real behavior proof before merge. :: [P2] [P2] Keep switch feedback keyed to a stable Codex account identity

@zenibako
zenibako force-pushed the feat/claude-swap-view-only-accounts branch 2 times, most recently from 1aa6acc to 1adbaad Compare September 11, 2026 13:24
@clawsweeper clawsweeper Bot added proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Sep 12, 2026
@zenibako
zenibako force-pushed the feat/claude-swap-view-only-accounts branch from 1adbaad to 581af6f Compare September 13, 2026 00:47
@zenibako zenibako changed the title feat(claude): make claude-swap account selection view-only and default its executable path feat(menu): unify Claude and Codex account switching (view-only segments, shared System Account submenu) Sep 13, 2026
@zenibako
zenibako force-pushed the feat/claude-swap-view-only-accounts branch 2 times, most recently from 88cc007 to df3df0c Compare September 13, 2026 11:47
zenibako and others added 12 commits September 13, 2026 09:33
Selecting a Claude account segment now only changes which account's details
the menu shows; it never invokes cswap activation. Activation stays behind the
existing explicit "Switch Account…" card action with its validation and
serialization intact.

- Highlight the viewed segment (filled) independently from claude-swap's
  source-owned active marker (a "●" glyph plus tooltip/accessibility text).
- Keep the viewed account for the app session across menu closes, keyed by
  ProviderAccountIdentity so it survives refreshes and list reordering.
- Scope the selection to the adapter configuration: disabling claude-swap or
  changing its executable drops it. A removed slot falls back to the
  source-reported active account, and no active account is invented.
- Keep unavailable accounts inspectable without activation, and let a later
  view selection outrank pending/failed activation while the activation error
  stays attached to its own account.

Adds menu-model regression coverage plus an opt-in synthetic render proof; no
real cswap executable, provider probe, or Keychain read is involved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
Enabling "Read accounts from claude-swap" no longer requires typing a path.
The adapter now resolves ~/.local/bin/cswap — the location the settings field
already advertised as its placeholder — whenever something executable is really
there. An explicitly configured path always wins, including when it is missing,
so a wrong path reports an error instead of silently running another binary; a
missing default resolves to empty, so users without claude-swap keep seeing no
adapter activity and no recurring error.

The claude-swap toggle, executable field, adapter status and discovered accounts
now render as one section through the same supplementarySettingsContent slot the
Codex accounts section uses, replacing the split toggle/field layout whose status
text said "below" while the settings form rendered fields above toggles.

Also drops the "Details for <account>" heading from the segmented menu: it dated
from when the switcher highlighted the active account while the card showed a
different one, and now only restates the highlighted segment. VoiceOver still
reads the state from the segment's own accessibility label.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017aP1xPvmUqQLRtXXqUjiLx
…wap proof

The signed proof recorded activationsStarted as a literal 0. It now clicks
every segment through the real menu's switcher view and handler, and measures
activation on the store's switch owner after each click and on a logging stub
standing in for cswap. It also records that the card's explicit Switch Account
action is offered only where activation is possible.

A second case runs executable discovery for fresh, missing-default, upgraded
empty-path, explicit and missing-explicit configs through the production config
loader, shared resolver and account reader against synthetic stubs, and checks
that an explicit path never falls back to the default.

Both cases stay skipped unless CODEXBAR_CLAUDE_SWAP_VIEW_PROOF_DIR is set with
credential isolation, and run no real cswap, account or Keychain access.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
One segmented switcher for account menus: layout, selected styling, click
tracking and hit-testing ported from the Codex switcher, plus a leading ● marker
for the System account and tooltips/accessibility labels that name the System
and Selected states. Providers supply labels and width-aware titles.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
… mark the System account

The Codex menu switcher is now the shared segmented switcher. Width-aware
email/workspace/discriminator titles and private ordinals move into
CodexAccountSwitcherLabeling as pure functions; CodexAccountSwitcherView remains
as an override-free subclass so menu reuse still recognizes the Codex row.

The live account (the one the Codex CLI uses) gains a ● System marker, and
tooltips name the System and Selected states.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
The segmented claude-swap switcher is now the shared account switcher, built
through ClaudeSwapAccountMenuDisplay.switcherView from the same display model.
The ● marker is the System account (the one claude-swap reports active) and
tooltips read System and Selected, matching Codex. Selection stays view-only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
Adds UsageMenuCardView.Model.applyingSubtitle(text:style:), matching the
applyingUsageItemVisibility pattern, so account switch progress can show in
loading, info or error style on both account and live cards built through the
shared card construction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
A pure per-provider phase (switching, succeeded, failed) that derives the card
subtitle and the completion notification. Successes clear once a menu closes;
failures stay until the next switch; a discarded result leaves nothing behind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
Codex's System Account submenu becomes a shared builder behind two defaulted
ProviderImplementation hooks, with a provider-neutral
requestSystemAccountSwitch action replacing requestCodexSystemPromotion. Codex
keeps its exact promotion eligibility and coordinator; its submenu titles now
honor Hide Personal Info and the title is localized.

The controller records switch progress per provider: the card subtitle shows
switching, success and failure, successes clear after a top-level menu closes,
and a notification reports the result when no menu is open, replacing the Codex
failure alert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
…ubmenu

claude-swap accounts join the shared System Account submenu while claude-swap
owns Claude account presentation: the active slot is checked, inactive slots
with usable credentials are enabled, and everything is disabled while a switch
runs. The adapter awaits the existing serialized cswap --switch-to transaction,
which now returns its task, and reads the per-slot error from the store.

The card no longer offers Switch Account for inactive slots. It keeps upstream's
Active badge and its explicit Re-authenticate repair action for an active slot
claude-swap marks re-activatable. The target card shows switch progress and
success; errors keep rendering on the account that produced them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
Adds the System Account submenu title, the Selected switcher state, and the
switch progress, success, notification and stale-account strings to all 23 app
catalogs, reusing each locale's existing System account wording.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
Documents the System Account submenu as the activation entry point for claude-swap
and Codex, the ● System marker, switch feedback and notifications, and lists the
claude-swap changes under 0.60.2 Unreleased.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
zenibako and others added 2 commits September 13, 2026 09:33
…nly clicks

The signed claude-swap proof now also switches through the System Account
submenu against the logging stub (the Claude refresh is replaced): segment clicks
start no activation, the submenu checks the System slot and enables only the
switchable one, choosing it runs exactly one cswap --switch-to, and a success
notice is posted. The receipt records the submenu, the switch invocation and the
notice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
Addresses review of the shared switch feedback:

- A switch error claude-swap already published outranks switching progress on
  the card, instead of staying hidden until the Claude refresh finishes.
- Stacked and compact Codex account cards show progress, success and failure
  for the account being promoted.
- Switch feedback no longer gets replaced by the live refresh monitor: a card
  with an applied subtitle stops following live provider status, and the header
  resolves its subtitle through a helper covered by a monitor-backed test.
- A failure notice that cannot be delivered (notifications not authorized)
  falls back to the alert Codex showed before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
@zenibako
zenibako force-pushed the feat/claude-swap-view-only-accounts branch from df3df0c to 0c775b8 Compare September 13, 2026 14:01
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. label Sep 13, 2026
@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. label Sep 14, 2026
steipete added a commit that referenced this pull request Sep 17, 2026
Apply the existing private account-label policy to System Account submenu titles while preserving raw names when privacy is off and retaining promotion targets, checked state, and visibility.

Native proof: #3702 (comment)

Extracted from #3550; the broader account-switching redesign remains separate.

Co-authored-by: Chandler Anderson <chanderson90@proton.me>
@steipete

Copy link
Copy Markdown
Owner

The existing System Account submenu now honors Hide Personal Info on main through #3702, merged as 141ecf6. It uses stable private account labels while keeping promotion targets and menu state intact; privacy off retains the original display names.

Validation: make test-fast FILTER='CodexSystemAccountPrivacy|CodexAccountSwitcherRedaction|ProviderArchitectureGatekeeper' passed 56 tests. Signed synthetic native before/after proof is at #3702 (comment). make check, final independent P2 review, and every macOS/Linux check passed: https://github.com/steipete/CodexBar/actions/runs/35174630916. The only integration conflict was in the changelog; source and test blobs remained unchanged.

Thanks @zenibako. This repairs the existing submenu's privacy omission; the broader account-switching redesign in #3550 remains open.

@steipete

Copy link
Copy Markdown
Owner

Thanks @zenibako for the implementation and proof. Closing this broad unification proposal. Main already fixes Codex System Account label privacy in 141ecf6 and clarifies Claude’s explicit chip switching and reconciliation feedback in 9a2f5e4 (#3740). The remaining changes are a larger UX redesign: view-only chips, relocated activation, executable discovery, grouped settings, and shared notification state. Those are not all superseded, but we are retaining the current provider-specific behavior rather than adopting this combined redesign.

@steipete steipete closed this Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants