Skip to content

Legacy Codex OAuth sidecars stored only in macOS Keychain still require doctor for embedded runtime path #85083

@RomneyDa

Description

@RomneyDa

Summary

#85074 (and the original #84752) restore runtime auto-migration of legacy oauthRef-backed openai-codex profiles for the embedded runner — but only when the sidecar seed lives in OPENCLAW_AUTH_PROFILE_SECRET_KEY or in a seed file under ~/.openclaw/oauth/.... Users whose legacy seed lives only in macOS Keychain (older onboarding before the file-based sidecar layout) are not self-healed by that PR and still need a one-time openclaw doctor --fix.

This issue tracks closing that remaining gap.

Why it's not in #85074

The embedded runtime path runs with allowKeychainPrompt: false (src/agents/auth-profiles/legacy-oauth-sidecar.ts:233-240) by design — embedded turns happen in Telegram replies, cron-triggered runs, sub-agent dispatch, and other contexts where popping an unexpected macOS Keychain prompt would be confusing or impossible. Simply flipping that flag to true is not acceptable: it would surface Keychain prompts at random times when no user is looking at the terminal.

So the runtime self-heal works for file/env-seed users (the modal case) but not Keychain-only users, who are documented as still needing doctor (docs/gateway/doctor.md section 5).

Affected users

Anyone who:

  • Onboarded openai-codex OAuth on a macOS host before the file-based sidecar layout was introduced, AND
  • Did not set OPENCLAW_AUTH_PROFILE_SECRET_KEY or write a seed file, AND
  • Upgraded with manual npm/pnpm/bun (skipping the openclaw update → doctor flow).

Same surface as #84893 / #85074, narrower bucket.

Two viable approaches

A. Prompt-once-and-cache in the embedded runtime path. Detect Keychain-backed legacy sidecars on first embedded-runtime store load. If the calling context is genuinely interactive (TTY attached, not cron/systemd/Telegram-bot-reply), prompt the user once to unlock the Keychain entry. On approval, read the seed, migrate all sidecar profiles inline via the existing saveAuthProfileStore path, and never need to prompt again. If the context is headless, fail gracefully with a clear message directing the user to run openclaw doctor from a terminal.

B. Auto-trigger the doctor migration on first interactive openclaw <anything> invocation after a detected legacy profile. Cleaner mental model — the migration stays doctor's responsibility, but it's triggered automatically once instead of requiring the user to know about it. Probably ~100-200 LOC in the command dispatch entry point + reuse of existing maybeRepairLegacyOAuthSidecarProfiles.

B is architecturally cleaner — it avoids spreading "when is it safe to prompt for Keychain access?" logic into the embedded runtime. A is more surgical but harder to get right.

Acceptance criteria

  • macOS Keychain-only legacy sidecar users self-heal on first interactive openclaw invocation after upgrade (whichever approach is chosen).
  • No Keychain prompts fire in headless contexts (cron, systemd, Telegram polling, embedded sub-agent dispatch).
  • Headless invocations that detect a Keychain-only profile fail with a clear actionable error directing the user to run from a terminal or run doctor.
  • Regression test covers both "interactive: migrate" and "headless: refuse cleanly" paths.

Related

Out of scope

  • Removing the legacy sidecar code paths entirely. That's a separate cleanup tracked elsewhere and should wait until all legacy users have migrated.
  • Changes to openclaw doctor --fix behavior itself; the migration path it runs is already correct.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.maintainerMaintainer-authored PR

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions