# pi-multi-pass lets one coding agent use several OAuth accounts and rotate on rate limits

> pi-multi-pass is a pi extension that adds extra OAuth subscriptions per provider, groups them into rotation pools with selectable strategies, and falls back across pools and models when a rate limit hits mid-turn. It suits a heavy user of the pi assistant with several accounts, and it touches your credential refresh behaviour, which is opt-in for a reason.

**hjanuschka/pi-multi-pass** — Multi-subscription extension for pi -- use multiple OAuth accounts per provider (Anthropic, Codex, Copilot, Gemini, Antigravity)

- Repository: https://github.com/hjanuschka/pi-multi-pass
- Stars: 524 · Forks: 62
- Language: TypeScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/hjanuschka-pi-multi-pass

## What the extension actually adds

pi-multi-pass is a multi-subscription extension for pi, the coding agent, and it lets you use multiple OAuth accounts per provider with automatic rate-limit rotation and project-level affinity.

The providers named are Anthropic, Codex, Copilot, Gemini and Antigravity, and the mechanism is a set of TUI commands rather than configuration files. The README says so directly: no config files needed.

The feature list is longer than the summary, and the individual entries are worth reading because they describe distinct pieces of machinery.

Multiple subscriptions means adding extra OAuth accounts for any provider. Rotation pools group subscriptions and auto-rotate on rate limits. Smart pool strategies offer round-robin, quota-first, scheduled using time windows, and custom with a JavaScript script hook. Fallback chains define ordered cross-pool and cross-model failover through `/pool chain`. Opt-in routing trace records recent selection, skip and failover decisions, but only when requested.

Model presets are named routing shortcuts across providers, so `/mp-preset coding-premium` is a shortcut rather than a full provider and model name. Built-in limits checks inspect subscription headroom across accounts with `/subs limits`, for Anthropic, Codex and Google.

Then there are two features that stand out from the rest. Experimental offline OAuth sharing copies one selected account using QR frames or a single copy/paste export string, with no network required. And an opt-in token keeper means one OAuth refresh per machine instead of one per pi process, so parallel sessions cannot burn each other's rotating refresh tokens.

There is also a live model catalog detail worth noting. Subscription providers mirror the base provider's merged model catalog, a static builtin plus a pi.dev remote overlay from `models-store.json`, on every model refresh, so newly catalogued models reach extra accounts without a pi-multi-pass release.

## Installing it and the first five commands

The install is a single command.

```bash
pi install npm:pi-multi-pass
```

Or from git.

```bash
pi install git:github.com/hjanuschka/pi-multi-pass
```

The quick start is then a sequence of slash commands.

```
/subs add              Pick a provider, add a subscription
/login                 Authenticate the new subscription
/subs switch           Manually switch to another subscription/provider
/subs limits           Check built-in quota support (Anthropic + Codex + Google)
/pool create           Group subs into a rotation pool (with strategy selection)
```

The behaviour that motivates the whole extension is stated at the end of the quick start. When one account hits a rate limit during an assistant turn, multi-pass automatically switches to the next eligible target and retries.

The word during is what makes this more than a convenience. A rate limit that fires mid-turn, after the model has already produced part of a response, is the case that ruins a session, because the user has to notice, switch by hand and ask for the work to be redone. Doing the switch inside the turn is the difference between an extension and a feature you build yourself.

The package.json shows the shape of the project. It is a pi extension, declared through the `pi` key pointing at the extensions directory, with the published files being extensions, lib, docs and the README. There are two runtime dependencies, proper-lockfile for the credential locking and qrcode-terminal for the QR frames, and a test/ directory with TypeScript tooling in devDependencies.

## The token keeper, and the refresh race it exists to fix

This is the most interesting engineering in the project and it is worth understanding before you enable it.

Anthropic and OpenAI rotate the refresh token on every refresh and reject the previous one, with the errors `refresh_token_reused` and `invalid_grant`. A rotation that never reaches `auth.json` therefore costs the login.

With many pi processes sharing one `auth.json`, pi's per-process refresh loses that race often enough to matter. Its refresh deadline of 15 seconds, or its credential lock that goes stale after 30 seconds, can expire after the provider has already rotated.

So the token keeper takes over refreshes. It renews tokens 15 minutes before expiry, ahead of pi's own 5-minute window. It holds the same `auth.json` lock pi uses, re-reads inside it, and skips the network when another process already stored a usable token. It writes the rotated credential in that same locked transaction, so a slow provider or a cancelled request cannot drop it. And it covers built-in logins such as anthropic and openai-codex as well as extra subscriptions.

The opt-in caveat is stated just as plainly. It is off by default because it changes who refreshes your credentials, so enable it only if you actually run several pi sessions at once.

That framing is correct. A credential refresh mechanism that takes over from the host application is exactly the kind of thing that should require you to opt in, and the reason for the opt-in is a specific failure mode with a specific trigger rather than a vague caution.

## Pools, strategies, chains and presets, as four layers of routing

The routing surface is layered, and the four layers are worth distinguishing because they solve different problems.

A pool is a group of subscriptions that rotate. `/pool create` picks a provider and selects members, and the pool can be enabled, disabled, listed, removed and inspected. `/pool status` shows member health, and the states it distinguishes are logged in, rate limited and cooling down. Removing a pool keeps the subscriptions and prunes linked chain entries.

The strategy decides how a pool picks among its members, and there are four. Round-robin is the obvious one. Quota-first prefers whichever account has the most headroom left. Scheduled uses time windows, which lets you reserve one account for a certain period. Custom hands the decision to a JavaScript script hook, which is the extension point for a policy you cannot express with the built-ins.

A chain is an ordered fallback across pools and models, created with `/pool chain create` and inspected with `/pool chain status` for validity. The chain is what handles the case where a whole pool is exhausted rather than one account in it.

A preset is a named routing shortcut that spans providers, so `/mp-preset coding-premium` picks the best available entry in a set rather than naming a provider and a model explicitly.

Project affinity sits on top of all of it. `/pool project` configures per-project subscription affinity, creating a `.pi/multi-pass.json` in the project directory, and when `allowedSubs` is set it is treated as an exact allow list. The practical effect is that work in one repository does not consume the accounts you have reserved for another.

Labels are the other grouping mechanism, so you can tag subscriptions as work or personal and reason about them that way.

## The routing trace, and what it deliberately does not record

The trace feature is opt-in and the README is explicit about the limits, which is what makes it usable.

Tracing is disabled by default and stores nothing until explicitly started. Entries are kept only in memory for the current pi session, with the newest 100 retained. Prompt contents are not recorded.

```
/pool trace start   Clear old entries and begin recording
/pool trace show    Inspect selections, skipped candidates, and failovers
/pool trace status  Show whether recording is active
/pool trace stop    Stop recording while retaining captured entries
/pool trace clear   Delete captured entries
```

So the trace records decisions, not content. You can see which subscription was selected, which candidates were skipped and why, and when a failover happened. That is enough to answer the question that actually comes up when routing misbehaves, which is why the automatic switch selected what it selected, without capturing what was being said to the model.

That distinction is the difference between a diagnostic tool you can leave available and one you have to switch off around sensitive work. The in-memory-only storage and the 100 entry cap make the trace something you can start for one awkward session and forget about.

The smarter retries feature is related. It preserves failover progress across internal replay retries, so a failed request does not reset the routing state and send you back to the first candidate.

## Where pi-multi-pass is the wrong choice

Four cases argue against it.

The first is a single-account user. The entire extension exists to manage several OAuth subscriptions per provider, and if you have one account per provider the rotation pools, the fallback chains and the presets have nothing to organise. The only thing that still applies is the token keeper, which is a different feature with its own trade-off.

The second is a concern about credential handling. The token keeper takes over refresh of your tokens, which means a piece of an extension is now writing to your auth.json. The code is MIT licensed and the locking is careful, but you are granting a third-party extension write access to credentials that renew your access to a paid service, and the failure mode of getting that wrong is a logged-out account rather than a crashed tool.

The third is a workflow where predictability matters more than throughput. Automatic rotation means the model answering your question may not be the one you selected, and a fallback chain means a failed request can be retried against a different model with different behaviour. If you are running something where the answer needs a specific model, the automatic switching is a liability rather than a feature.

The alternative in the same direction is to run separate pi instances per account and switch by hand, or to use a provider that does not rate limit you. The difference in approach is that this extension automates the switch inside the turn, which is the only version of this that survives a long session, whereas hand-switching costs you the partial response every time a limit fires. If you have many accounts and long sessions, the automation is the whole value. If you have one account, it is complexity for nothing.

## Conclusion

pi-multi-pass fits a pi user with several provider subscriptions who hits rate limits during long assistant turns, since the rotation and failover happen inside the turn rather than by hand. It does not fit a single-account user, and the token keeper in particular should stay off unless you run several pi processes at once. Install it with `pi install npm:pi-multi-pass`, use `/subs add` and `/login` to register an account, and enable `/subs keeper` only after you have confirmed the rotation race is actually costing you logins.

## FAQ

### What does pi-multi-pass do?

It is a pi extension that lets you use multiple OAuth accounts per provider, for Anthropic, Codex, Copilot, Gemini and Antigravity, with automatic rate-limit rotation and project-level affinity. When one account hits a rate limit during an assistant turn, it switches to the next eligible target and retries.

### How do I install pi-multi-pass?

With `pi install npm:pi-multi-pass`, or from git with `pi install git:github.com/hjanuschka/pi-multi-pass`. You then use `/subs add` to pick a provider and add a subscription, and `/login` to authenticate it. Everything is managed through commands in the TUI rather than config files.

### What is the shared OAuth token keeper?

An opt-in feature that performs one OAuth refresh per machine rather than one per pi process, because Anthropic and OpenAI rotate the refresh token on every refresh and reject the previous one. It renews tokens 15 minutes before expiry, takes pi's own auth.json lock, and skips the network when another process already stored a usable token. It is off by default because it changes who refreshes your credentials.

### What are the different rotation strategies in pi-multi-pass?

Four: round-robin, quota-first, scheduled using time windows, and custom which hands the decision to a JavaScript script hook. Which strategy applies is set when you create a pool with `/pool create`.

### Does the routing trace in pi-multi-pass record my prompts?

No. Tracing is disabled by default and stores nothing until started, entries are kept only in memory for the current session with the newest 100 retained, and prompt contents are not recorded. It captures selections, skipped candidates and failovers.

## Sources

- [hjanuschka/pi-multi-pass on GitHub](https://github.com/hjanuschka/pi-multi-pass)
- [Issues](https://github.com/hjanuschka/pi-multi-pass/issues)
- [License: MIT](https://github.com/hjanuschka/pi-multi-pass/blob/main/LICENSE)
- [README](https://github.com/hjanuschka/pi-multi-pass/blob/main/README.md)
- [Releases](https://github.com/hjanuschka/pi-multi-pass/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hjanuschka-pi-multi-pass
