Skip to content

agent auth and session resilience

oauth-mux

OAuth/account multiplexing for professional AI harnesses and autonomous agents.

Managed Codex resume has live installed-runtime evidence: a provider-originated usage_limit_reached turn on one account was retried on another account before Codex saw the 429. Public install lanes now resolve to 0.1.7 across GitHub Release, npm, Homebrew, curl, and deb/rpm package QA.

Codex Max managed proof · one provider, route truth moves
  1. #1
    max-2 · codex-max

    successful traffic before the quota event

    200
  2. #2
    max-2 · codex-max

    usage_limit_reached stayed inside the proxy

    429
  3. #3
    max-3 · codex-max

    same buffered request recovered on fallback

    200
  4. #4
    codex-max · live route state

    route availability moves with auth and quota state

    inspect
Cohort truth: the 2026-05-09 engineered artifact proves managed quota handoff from max-2 to max-3. It does not claim same-thread provider continuity or mid-turn streaming recovery.

Install and probe

bash
npm install -g oauth-mux
oauth-mux init --codex-max
oauth-mux doctor
oauth-mux route explain --profile codex-max --capability codex-max
oauth-mux codex resume

agent-safe operations

Inspect auth and route state without touching secrets.

The control plane is built for humans and agents: inspect configured accounts, prove runtime access, explain route health, and receive exact next-action commands without printing token material.

Works now

Installed oauth-mux codex resume has live managed-frame evidence for provider-originated quota handoff; traffic recovered onto another account without restarting the harness process.

Safe by default

Inspection commands return redacted JSON and do not open browser auth, copy provider stores, or spend provider calls.

Explicit handoffs

Login, reauth, live probes, and revalidation remain labeled user-mediated or spend-confirmed commands.

Shim bounded

The package codex shim manages future shell launches only when PATH resolves it; direct native binaries and already-running Codex sessions are not globally protected.

No-spend inspection

Run these before any live probe. The outputs show route availability, local runtime readiness, repair actions, and latest managed Codex evidence without spending provider calls.

bash
oauth-mux doctor runtime --profile codex-max --capability codex-max --json
oauth-mux accounts list --provider codex --json
oauth-mux route explain --profile codex-max --capability codex-max --json
oauth-mux repair-plan --profile codex-max --capability codex-max --json
oauth-mux codex status-latest --json
oauth-mux/README.md — agent-safe inspection

Enroll the next account

Enrollment mutates oauth-mux-owned config and store scaffolding only. Upstream login remains a user-mediated handoff, then route explanation or repair planning records fresh next actions.

bash
oauth-mux accounts list --provider codex --json
oauth-mux enroll plan codex --account max-4 --json
oauth-mux enroll codex --account max-4 --confirm-enroll --json
oauth-mux codex login-device max-4
oauth-mux repair-plan --profile codex-max --capability codex-max --json
oauth-mux/docs/onboarding.md

Repair without silent auth

Interactive reauth is a labeled command that the user runs. oauth-mux should not silently repair upstream OAuth state in the background.

bash
oauth-mux route explain --profile codex-max --capability codex-max --json
oauth-mux repair-plan --profile codex-max --capability codex-max --json
# run the labeled login command shown in the handoff
oauth-mux codex login-device max-1
oauth-mux route explain --profile codex-max --capability codex-max --json
oauth-mux/docs/provider-repair-contracts.md

Live path boundary

Live Codex work is explicit. Use the managed launch path, then inspect the redacted status artifact; do not treat raw wrapper scripts or repo-local binaries as public acceptance evidence.

bash
# spend-confirmed paths stay explicit
oauth-mux accounts list --provider codex --json
oauth-mux route explain --profile codex-max --capability codex-max --json
oauth-mux codex resume
oauth-mux codex status-latest --json
spend-confirmed/live path boundary

what oauth-mux is

A broker for AI harness auth, quota, tier, and local runtime state.

Developers and agents increasingly operate across personal, work, team, subscription, API-key, and service identities. Current CLIs often expose one active account path, so quota exhaustion or stale auth becomes a manual context switch.

oauth-mux wraps a harness with route-state diagnostics, managed auth/config overlays, and labeled fallback decisions. The goal is to keep the harness usable when account state changes without hiding the evidence from operators.

lifecycle

A brokered harness session, not a background wish.

The usable surface is a managed launch/resume path, route-state evidence, and a redacted artifact trail that a human or agent can inspect without touching credential material.

  1. 01

    Install

  2. 02

    init

  3. 03

    enroll accounts

  4. 04

    local diagnostics

  5. 05

    route selection

  6. 06

    managed harness launch

  7. 07

    provider signal observed

  8. 08

    broker decision

  9. 09

    fallback materialization

  10. 10

    redacted status artifact

  11. 11

    repair / revalidate loop

Managed Codex flow

oauth-mux codex resume selects a route, builds a mux-owned auth/config overlay, bridges native session authority, spawns Codex, classifies provider responses, retries fallback when eligible, and writes redacted evidence.

Proof ladder

oauth-mux separates diagnostics from product proof. The current public proof reaches next_turn_seamless for managed Codex quota handoff; higher continuity claims remain open.

prepared_fallback

diagnostic

A candidate fallback exists. This does not prove a harness turn survived account exhaustion.

broker_owned

implemented

The harness ran through oauth-mux-owned auth/config and redacted status instrumentation.

next_turn_seamless

live-proven for managed Codex

Quota exhaustion was observed, retried on a distinct fallback account, and kept the Codex process alive.

mid_turn_streaming

open

Streaming recovery during an active provider stream remains research.

cross_session_thread_continuity

open

Same-thread provider semantics across account boundaries remain unclaimed.

unmanaged_daemon_handoff

open

Bare Codex hot-swap from a background daemon is not part of the proven managed path.

CredentialLiveness & Availability

zig
// ── Credential Liveness ──
//
// Three distinct layers that the mux pipeline must reason about:
//
// 1. Authentication: Can the token prove identity to the provider?
//    (not expired, not revoked, parseable)
//
// 2. Operability: Is the account in a state where it can serve requests?
//    (not suspended, subscription active, tier sufficient)
//
// 3. Availability: Does the account have capacity right now?
//    (not rate-limited, quota not exhausted, not in cooldown)
//
// The mux response differs for each:
//   Auth failed    → mark dead, never retry automatically
//   Inoperable     → mark degraded, retry after long interval (hours)
//   Rate limited   → cooldown timer, retry same account after seconds
//   Quota exhausted → switch account, retry after window reset (hours/days)
//   Provider down  → switch provider entirely, not just account

pub const CredentialLiveness = union(enum) {
    live: LiveCredential,
    degraded: DegradedCredential,
    dead: DeadCredential,

    pub const LiveCredential = struct {
        availability: Availability,
    };

    pub const DegradedCredential = struct {
        reason: DegradedReason,
        since: i64,
        retry_at: ?i64 = null,
    };

    pub const DeadCredential = struct {
        reason: DeadReason,
        since: i64,
    };
};

pub const Availability = union(enum) {
    available,
    rate_limited: RateLimitInfo,
    quota_exhausted: QuotaInfo,
    cooldown: CooldownInfo,

    pub const RateLimitInfo = struct {
        retry_after_s: u32,
        limited_at: i64,
        window: RateLimitWindow,
    };

    pub const QuotaInfo = struct {
        window_resets_at: ?i64 = null,
        usage_pct: ?u8 = null,
        exhausted_at: i64,
    };

    pub const CooldownInfo = struct {
        until: i64,
        reason: []const u8,
    };
};
oauth-mux/src/types.zig:152-215

DegradedReason & DeadReason

zig
pub const DegradedReason = enum {
    tier_insufficient,
    subscription_paused,
    provider_degraded,
    scope_insufficient,
    schema_invalid,
    terms_required,
    step_up_required,
    pending_verification,
    unknown_4xx,
};

pub const DeadReason = enum {
    token_revoked,
    account_deleted,
    auth_permanently_failed,
};
oauth-mux/src/types.zig:224-240

MuxDecision

The fromHttpStatus switch is the canonical routing-semantics table — HTTP status maps to a single decision, no extra prose required.

zig
// ── Mux Decision ──
// What the pipeline should do after probing a credential.

pub const MuxDecision = enum {
    use_this,
    try_next_account,
    try_next_provider,
    wait_and_retry,
    give_up,

    pub fn fromHttpStatus(status: u16) MuxDecision {
        return switch (status) {
            200...299 => .use_this,
            401 => .try_next_account,
            403 => .try_next_account,
            429 => .wait_and_retry,
            500...599 => .try_next_provider,
            else => .try_next_account,
        };
    }

    pub fn isRecoverable(self: MuxDecision) bool {
        return self != .give_up;
    }
};
oauth-mux/src/types.zig:245-261

Install

Public npm, GitHub Release, Homebrew, curl, and package lanes now resolve to 0.1.7. Source dogfood remains a separate provenance lane when testing unreleased worktree behavior.

npm

live (v0.1.7)

Published from CI release tarballs; the private-source 0.1.7 publish used provenance disabled.

bash
npm install -g oauth-mux
oauth-mux/build.zig.zon:3 + docs/adoption.md:9-15

Local source dogfood

Use remove-then-copy for macOS local dogfood so taskgated does not keep stale signature state on the old Mach-O vnode.

bash
just build
mkdir -p ~/.local/bin
rm -f ~/.local/bin/oauth-mux
cp ./zig-out/bin/oauth-mux ~/.local/bin/oauth-mux
shasum -a 256 ./zig-out/bin/oauth-mux ~/.local/bin/oauth-mux
which -a oauth-mux
oauth-mux version
oauth-mux/docs/release-install-lanes.md

curl installer repo override

The canonical public source repo is Jesssullivan/oauth-mux; override the upstream by setting REPO= before the curl pipeline.

bash
# override the source repository (defaults to Jesssullivan/oauth-mux)
REPO=Jesssullivan/oauth-mux curl -fsSL https://omux.xoxd.ai/install.sh | sh

Usage paths

Humans get a native managed Codex path. Agents get redacted JSON inspection. Provider authors get typed validation before any live proof lane.

Human Codex path

The managed command keeps Codex inside the oauth-mux frame while preserving native chooser/session authority.

bash
oauth-mux init --codex-max
oauth-mux doctor
oauth-mux route explain --profile codex-max --capability codex-max
oauth-mux codex resume
oauth-mux/README.md — human first run

If upstream auth is stale, run the labeled command from route explanation, such as oauth-mux codex login-device max-3.

Generic provider author path

A new provider should usually start as data, not Zig:

  1. Write a JSON provider definition with credential parsing, injection, probes, and failure rules.
  2. Add redacted fixtures for the provider's success, rate-limit, quota, degraded, and auth-dead responses.
  3. Run `oauth-mux config validate` and the no-secret E2E harness.
  4. Run live QA only with explicit account-scoped consent.

Operator validation commands (verbatim, from oauth-mux/docs/onboarding.md:155-163):

bash
oauth-mux config validate
oauth-mux doctor --json
oauth-mux report --redacted --json
oauth-mux discover --json
oauth-mux/docs/onboarding.md:460-481 — provider onboarding checklist

Agent-safe inspection path

Agents start with redacted JSON discovery and never reach for credential paths. These commands expose runtime readiness, route state, repair actions, and status evidence without spending provider calls.

bash
oauth-mux doctor runtime --profile codex-max --capability codex-max --json
oauth-mux accounts list --provider codex --json
oauth-mux route explain --profile codex-max --capability codex-max --json
oauth-mux repair-plan --profile codex-max --capability codex-max --json
oauth-mux codex status-latest --json
oauth-mux/README.md — agent-safe inspection

Agent-safe command surface

  • oauth-mux config validate
  • oauth-mux doctor runtime --profile <profile> --capability <capability> --json
  • oauth-mux accounts list --provider <provider> --json
  • oauth-mux route explain --profile <profile> --capability <capability> --json
  • oauth-mux repair-plan --profile <profile> --capability <capability> --json
  • oauth-mux codex status-latest --json
  • oauth-mux report --redacted --json

Agents must not

  • read files referenced by `secret.path`;
  • print token-shaped values;
  • copy OAuth stores between accounts;
  • run live probes or revalidation unless the user explicitly authorized spend.

Security & Privacy

oauth-mux holds four hard guarantees around how secrets enter the harness, where they live, and what shows up in machine-readable output.

Four guarantees

  • no `.env` token dumping;
  • no committed credential stores;
  • no raw token output in discovery/health;
  • explicit live probes only when they may spend calls.

Allowed secret backends

The backend stores or returns raw secret material. It does not define provider logic. Any of the seven backends below is allowed; everything else is rejected at config validation time. Click a backend to expand its semantics.

Redaction posture

discover --json is intentionally redacted. It reports config path, state path, providers, account names, secret backend names, tags, profiles, and safe command templates. It does not include token material.

What is not claimed

The current public proof is deliberately narrower than the product ambition. These remain research, adapter, or evidence lanes:

  • same-thread provider semantic continuity across account boundaries
  • mid-turn streaming recovery
  • unmanaged bare-Codex daemon hot-swap
  • universal provider support
  • non-Codex stay-afloat proof

Contribute a provider

New providers travel a schema-modeled to live-proven path. Start by declaring a JSON definition with redacted cassettes, then graduate to live-proven only after operator-scoped QA. The provider-authoring checklist is the canonical source of truth for what the harness will accept.

Read the provider-authoring checklist

What we ask of contributors

  • link the provider-authoring checklist;
  • ask for redacted cassettes, official docs links, and one positive/negative probe case.

Standards baseline

Provider definitions are written against: OAuth 2.1 draft, RFC 9700, RFC 8414, RFC 7591, RFC 9728, RFC 8707, RFC 9449, and the MCP authorization 2025-11-25 profile.

Contact

Three channels cover the public surface today. There is no public security email yet.