> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monolex.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# MonoSwitch

> Save Claude Code accounts behind OpenCLIs Vault, switch the default live login with explicit recovery boundaries, or run isolated accounts in parallel terminals.

MonoSwitch is the provider-namespaced account switcher for AI CLIs. Version 0
ships the `claude` namespace: it can save the currently logged-in Claude Code
account as an encrypted profile, switch the default live login to a saved
profile, or start Claude under an isolated `CLAUDE_CONFIG_DIR` so several
terminals can use different accounts at the same time.

*Published contract: `monoswitch 0.1.5`, OpenCLIs build
`2026-07-18-110041`, source commit
`f07e3578850d792b764b4cd875d9fcc7b2001505`. The parser exposes seven
`claude` verbs, a root `doctor` alias, and root help/version identity aliases.*

## Quick Start

```bash theme={null}
openclis install monoswitch

monoswitch --version
monoswitch claude list
monoswitch claude add work
monoswitch claude use work
monoswitch claude run personal -- -c
monoswitch doctor
```

Use `run` when parallel terminals should remain on different accounts. Use
`use` only when the machine's default Claude Code login should change for
running and future default-config sessions.

## Complete Command Reference

| Command                                   | What it does                                                                                                                                                         | Mutation and boundary                                                                                                                                                          |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `monoswitch`                              | Prints the embedded full guide.                                                                                                                                      | Read-only. Root aliases are `-h`, `--help`, and `help`.                                                                                                                        |
| `monoswitch version`                      | Prints the executing payload identity.                                                                                                                               | Read-only. Aliases are `-V` and `--version`.                                                                                                                                   |
| `monoswitch doctor`                       | Runs the Claude custody self-check.                                                                                                                                  | Exact alias of `monoswitch claude doctor`; reads live identity/token availability, Vault, metadata, and lock state.                                                            |
| `monoswitch claude add <name>`            | Snapshots the current token + `oauthAccount` pair into the encrypted Vault document and mirrors non-secret metadata.                                                 | Persistent secret and metadata writes. An existing name is replaced without a confirmation prompt.                                                                             |
| `monoswitch claude list`                  | Lists saved names/emails, marks the account whose UUID matches the live login, and adds last-observed 5h/weekly percentages when a Monometer spool-state row exists. | Read path, but it first tries to auto-preserve an unseen live account. A colliding live-account window is shown as `[quota settling…]` instead of a possibly wrong percentage. |
| `monoswitch claude current`               | Prints the live email and account UUID plus the first matching metadata profile.                                                                                     | Read path with the same best-effort auto-preserve attempt as `list`. The UUID is account metadata, not a secret token.                                                         |
| `monoswitch claude use <name>`            | Changes the default live login to a saved Vault profile.                                                                                                             | Keychain/config/Vault/metadata mutation; use the staged algorithm below.                                                                                                       |
| `monoswitch claude run <name> [-- args…]` | Replaces the Unix process, or spawns and waits on Windows, with `claude` under a persistent isolated config directory.                                               | Does not mutate the default live login. The isolated directory gets its own credentials during first-run `/login`.                                                             |
| `monoswitch claude remove <name>`         | Removes the matching Vault secret and metadata row.                                                                                                                  | Destructive. The live login is never changed. Internal `@last-…` backups can also be removed by exact name because this path does not apply the public-name validator.         |
| `monoswitch claude doctor`                | Prints `PASS`, `WARN`, and `FAIL` custody checks.                                                                                                                    | Read-only by contract; details and exit behavior are below.                                                                                                                    |

Profile names accepted by `add` and `run` are ASCII
`[A-Za-z0-9_-]+`. Auto-generated names use the live email's local part,
replace other characters with hyphens, and add `-2`, `-3`, and so on for
collisions. Without an email, the fallback is `auto-<first-eight-uuid-chars>`.

## Choose `use` or `run`

| Need                                                        | Correct mode               | Why                                                                                                |
| ----------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------- |
| Make the default Claude Code login a saved account          | `claude use <name>`        | Updates the live token store and default `.claude.json` identity together under both Claude locks. |
| Keep two terminals on different accounts                    | `claude run <name>`        | Each raw name owns a permanent config path; no default-login switch or Vault profile is required.  |
| Save the account that is live now                           | `claude add <name>`        | Explicitly snapshots both credential halves under a chosen name.                                   |
| Discover an unseen live account before `/login` replaces it | `claude list` or `current` | Those paths try to auto-preserve the uncovered live UUID. `doctor` only reports coverage.          |

`run` refuses to nest when `CLAUDE_CONFIG_DIR` is already non-empty. It creates
`config-dirs/<name>` even when no Vault profile has that name, strips leading
`--` separators after the name, and forwards the remaining arguments to
`claude`. Claude Code hashes the raw config path; do not rename a populated
profile directory.

## The `use` Transaction Boundary

`use` is a lock-guarded two-store operation. It is not a crash-atomic transaction
across macOS Keychain and JSON files.

1. Best-effort auto-preserve checks the current live account.
2. The current token + `oauthAccount` pair is read before any write.
3. The target must exist in the encrypted Vault document. If its account UUID
   already matches the live UUID, the command returns a no-op.
4. MonoSwitch acquires Claude Code's `~/.claude.lock` and
   `~/.claude.json.lock`. A live lock is retried for up to nine seconds; a lock
   older than ten seconds is treated as stale and taken over.
5. Before touching the live stores, the freshest outgoing pair is written to
   `@last-<uuid8>` and every non-internal named profile with the same account
   UUID. This prevents a token that rotated while live from leaving its saved
   profile frozen at add time.
6. The target token is written first and the target `oauthAccount` second.
   Both are read back; success is reported only when both match.
7. A write/read-back failure attempts to restore both original values and
   prints a separate `RESTORE WARNING` for either failed restoration. The
   `@last-…` Vault copy remains the recovery point.
8. After the live pair verifies, `state.json` is loaded and updated, then a v2
   quota switch marker is appended best-effort when the spool directory exists.

<Warning>
  A corrupt or unreadable `state.json` can make `use` exit non-zero at step 8
  after the live token and identity already changed successfully. Do not blindly
  repeat a failed switch. Run `monoswitch claude current` and `monoswitch doctor`
  to establish the live account first.
</Warning>

Running Claude sessions adopt a default-login switch on their next API call.
Status output between the swap and that call can briefly carry the previous
account's rate-limit view. The v2 switch marker records the intended boundary,
but marker absence never fails or rolls back the switch.

## Auto-Preservation and Profile State

Only `list`, `current`, and `use` call the automatic preservation helper.
`add` is the explicit snapshot command. `run`, `doctor`, and `remove` do not
auto-preserve the default live login.

The auto-preserve path first reads the non-secret UUID from `oauthAccount`. It
touches the live token store and Vault only when no metadata profile covers
that UUID. Platforms without a verified live token store skip the snapshot;
callers warn or continue according to their command contract.

`state.active` is a convenience mirror, not proof of the live account. `list`
and `current` compare account UUIDs from the live `oauthAccount` block.

### Quota window settling after a switch

A session that still holds the outgoing token can briefly report the old
account's quota under the newly live account's spool stamp. `list` has only the
current dedup-state snapshot, not Monometer's observation history, so it uses a
narrow deterministic guard: a non-live account's window remains displayable,
while the live account's window is trusted only when its five-hour reset epoch
does not equal another saved account's epoch. On collision it prints
`[quota settling…]`; once the live account reports its own distinct window,
normal `5h … · wk …` output resumes. This suppresses a known wrong value; it
does not invent or interpolate quota data.

## Storage and Credential Custody

| Store                                                                  | Content                                                                          | Write behavior                                                                                            |
| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| OpenCLIs Vault service `monoswitch-claude`                             | One encrypted JSON document containing every profile token + `oauthAccount` pair | `add`, auto-preserve, `use`, and `remove` rewrite the document.                                           |
| `~/Library/Application Support/Monolex/monoswitch/state.json` on macOS | Non-secret names, emails, UUIDs, active name, timestamps                         | Atomic temp-file rename, but separate from the Vault write. Other OSes use their normal config directory. |
| `…/Monolex/monoswitch/config-dirs/<name>/`                             | Persistent isolated `CLAUDE_CONFIG_DIR` homes                                    | Created by `run`; the child Claude process owns its login state.                                          |
| Default Claude Code stores                                             | Keychain token plus the `oauthAccount` key in `.claude.json`                     | Touched only by `add` reads and the `use` switch path on verified platforms.                              |

Vault secret writes happen before metadata writes. A later `state.json` failure
can therefore leave store drift; `doctor` reports missing secret/metadata names
and recommends re-adding the profile. The Vault executable is resolved from
`MONOSWITCH_VAULT_BIN`, then `~/.openclis/bin/openclis-vault`, then `PATH`.

On macOS, MonoSwitch calls Apple-signed `/usr/bin/security` by absolute path so
one Keychain approval is not tied to each MonoSwitch binary cdhash. Writes send
normal-size tokens as hex through `security -i` stdin. An oversized command
falls back to argv, where the hex can be briefly visible to a local process
inspector. Keychain subprocesses have a ten-second deadline rather than
hanging forever on an unseen prompt.

## Doctor Contract

`doctor` is observational, but its result is deliberately not “all warnings
are failures.”

| Check                                            | Output severity | Affects exit status?                          |
| ------------------------------------------------ | --------------- | --------------------------------------------- |
| Live `oauthAccount` readable                     | `PASS` / `FAIL` | Yes; failure makes the command non-zero.      |
| Live token store readable                        | `PASS` / `WARN` | No. Non-macOS unverified stores are warnings. |
| OpenCLIs Vault reachable                         | `PASS` / `FAIL` | Yes.                                          |
| Live UUID covered by a metadata profile          | `PASS` / `WARN` | No; doctor stays read-only.                   |
| Vault names and metadata names agree             | `PASS` / `WARN` | No.                                           |
| Claude credential/config lock directories absent | `PASS` / `WARN` | No.                                           |

A successful doctor therefore proves the two hard read boundaries, not that
every warning is absent or that a future switch will succeed.

## Parser and Exit Contract

* There is no structured JSON output or MCP schema in 0.1.5.
* Help is implemented at the root and at bare `claude` only. Do **not** probe
  `monoswitch claude add --help`, `use --help`, `run --help`, or
  `remove --help`: `--help` becomes that verb's first argument, and mutating
  paths can act on a profile or directory literally named `--help`.
* `add`, `use`, and `remove` consume the first name and ignore later tokens.
  `run` alone forwards later tokens to Claude.
* Unknown root commands and unknown Claude verbs exit non-zero. Missing names
  for `add`, `use`, `run`, and `remove` also exit non-zero.
* `list`, `current`, and both doctor routes ignore extra trailing arguments.
* `add` and auto-preserve write the Vault before `state.json`; `remove` uses
  the same order. These are not cross-store transactions.
* A non-zero OpenCLIs Vault `read` is treated as a fresh empty document by the
  current client boundary. Run `doctor` before profile mutation when Vault
  health or Keychain permission is uncertain.

## Platform and Release Proof

| Platform                               | Archive                                       | SHA-256                                                            | Runtime boundary                                                                                                                           |
| -------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| macOS Apple Silicon (`darwin-aarch64`) | `monoswitch-aarch64-apple-darwin.tar.gz`      | `93a6ca005c51101fcfe36a3ecfa62aebb2d402ecc97718edc366e8ae607df56a` | OpenCLIs-installed and release payloads reported 0.1.5; strict Developer ID verification passed, and runtime/external guides match source. |
| Linux x86-64 (`linux-x86_64`)          | `monoswitch-x86_64-unknown-linux-gnu.tar.gz`  | `988bb72ed2ab24bfe3296c9f1137d7390edcbffc4441188fa37c3fea04a53172` | Direct CDN archive executed in Ubuntu 24.04 WSL; version 0.1.5 and runtime-guide equality verified.                                        |
| Linux ARM64 (`linux-aarch64`)          | `monoswitch-aarch64-unknown-linux-gnu.tar.gz` | `2edcda742bf11f898e917e65c8fc972d550526079e0bf6fb7ab5cd590e8c6324` | Payload inspected as AArch64 ELF; packaged `initiate.md` and `SKILL.md` match release source.                                              |
| Windows x86-64 (`windows-x86_64`)      | `monoswitch-x86_64-pc-windows-msvc.tar.gz`    | `3cac8d2507575f113ad4ae4dd219a0b583cce18b7dfa5831c4769d36e99d1ae2` | Direct CDN executable ran on Windows x64, reported 0.1.5, and its raw runtime guide matched the packaged guide after CRLF normalization.   |
| Windows ARM64 (`windows-aarch64`)      | `monoswitch-aarch64-pc-windows-msvc.tar.gz`   | `005d1c0dd0653cb8205a7ca414c6d58b8ab5270d754726dddcc9f88de57901e4` | Payload inspected as AArch64 PE console executable; packaged guide pair matches release source after CRLF normalization.                   |

The release has no macOS Intel artifact. On macOS, `add` and `use` have the
verified live-token implementation. Linux, WSL, and Windows publish runnable
binaries, but `add` and `use` fail closed until their file-based live token
store is verified in this estate. `run`, `list`, `current`, `remove`, and
`doctor` remain available there; doctor reports the live-token gap as a
warning rather than a hard failure.

<Note>
  `0.1.1` and `0.1.2` were short-lived macOS-only transition builds. `0.1.4`
  introduced the mixed-era quota-window guard, but its macOS artifact recorded
  dirty source provenance. `0.1.5` supersedes it from one clean source commit and
  retains the exact auto-preserve, two-store rollback, metadata, parser, and
  platform boundaries documented here.
</Note>

## Relationships

| Tool                                      | Ownership                                                                                                                                                                                                                  |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [OpenCLIs Vault](/ai-clis/openclis-vault) | Owns stable encrypted local storage; MonoSwitch owns the multi-profile document and switch policy.                                                                                                                         |
| [Monometer Suite](/ai-clis/monometer)     | Supplies the optional per-account quota spool rows and owns history-based mixed-era quarantine; MonoSwitch applies the narrower single-snapshot collision guard in `list`, while v1 ingest skips v2 switch markers safely. |
| [NIIA](/ai-clis/niia)                     | Orchestrates AI work and can discover the installed skill; it does not own Claude credentials.                                                                                                                             |
| [OpenCLIs](/ai-clis/openclis)             | Installs, updates, and deploys the bundled MonoSwitch skill from the immutable release.                                                                                                                                    |
