toguru
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 9 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
One CLI to swap between multiple Claude Code (Anthropic) and Codex (OpenAI) accounts.
toguru トグル
One CLI to swap between multiple Claude Code (Anthropic) and Codex (OpenAI) accounts.
toguru (トグル) is Japanese for "toggle" — and that's exactly what it does:
toggle between accounts.
Tired of logging out and back in to switch between your personal and work
Claude/Codex subscriptions? tg saves each signed-in session and lets you flip
between them in a second — from a single tool, on macOS, Linux, and Windows.
It is a thin, safe layer over the credentials your existing CLIs already write:
| Provider | Live credential location |
|---|---|
| Claude Code | macOS Keychain (Claude Code-credentials) · ~/.claude/.credentials.json elsewhere |
| Codex | ~/.codex/auth.json (override the dir with CODEX_HOME) |
Saved accounts live in ~/.toguru/store.json (override withTOGURU_HOME), written atomically with 0600 permissions.
Install
# with bun
bun add -g toguru-cli
# or npm / pnpm
npm install -g toguru-cli
The command is tg (with toguru as a longer-form alias — they're
identical). tg isn't a standard Unix/Linux command, so it won't clash with
anything already on your PATH.
Just run tg
That's the whole thing — run tg with no arguments and you drop straight
into the interactive hub: every saved account across Claude and Codex, arrow-key
to one to switch / re-authenticate / rename / remove, or log in to a new one.
$ tg
? Accounts — pick one to manage
Claude Code (Anthropic)
❯ [email protected] [active]
Codex (OpenAI)
[email protected] ⚠ re-auth
──────────────
🔑 Log in to a new account
🚪 Exit
No flags to memorize. Everything below is just the same actions as direct
commands, for when you want them.
Auth status
toguru flags each account's sign-in state — read locally from the saved
token, no network calls:
| Tag | Meaning |
|---|---|
| (none) | Signed in, token still valid |
⟳ expired |
Access token expired — the provider refreshes it automatically on next use |
⚠ re-auth |
No refresh token — you must log in again (tg <provider> auth <name>) |
tg status spells this out per active account (e.g. "✓ signed in (token
expires in 8 hours)"), and tg switch tells you right after switching if the
session it activated has expired or needs re-authentication.
Quick start
# 1. Log in AND save in one step (opens your browser):
tg claude auth work # or: tg codex auth work
# 2. Add another account the same way:
tg claude auth personal
# 3. Switch any time:
tg switch claude personal
tg switch claude # interactive picker
tg # …or just run tg and pick
# See where things stand:
tg list
tg status
If a saved profile's token goes stale, re-authenticate it in place — same
name, fresh session:
tg claude auth work # re-runs login and updates the "work" profile
Already logged in through the provider's own CLI? You can still snapshot the
current session without re-authenticating: tg add claude work.
Profiles default to your account email — log in as [email protected]
and the profile is named that (just press Enter at the prompt, or pass your own
name).
Commands
| Command | Description |
|---|---|
tg / tg status |
Interactive hub: arrow-key a profile → switch / re-auth / rename / remove (alias: current) |
tg <provider> auth [name] |
Log in (or re-authenticate a profile) and save it — e.g. tg codex auth |
tg auth [provider] [name] |
Same as above, with the provider as an argument |
tg switch [provider] [name] |
Activate a saved account (alias: use) |
tg add [provider] [name] |
Save the current live session as a named account (no re-login) |
tg list [provider] |
List saved accounts (alias: ls) |
tg current [provider] |
Show active account + live-sync status, then open the hub on a TTY (alias: status; use --json for plain output) |
tg sync [provider] |
Capture a token refresh / re-auth from the live session into the active profile |
tg rename [provider] [old] [new] |
Rename a saved account (alias: mv) |
tg remove [provider] [name] |
Forget a saved account (alias: rm) |
tg export [provider] |
Export accounts as JSON |
tg import <file> |
Import accounts from a JSON export |
tg update |
Update to the latest version (auto-detects npm/bun/pnpm/yarn) |
provider is claude or codex. Omit any positional argument and you'll be
prompted for it.
Useful flags
tg add --label <email>— set a custom label;--activateto switch to it immediately;--forceto overwrite.tg list --json/tg current --json— machine-readable output for scripts.tg remove --yes— skip the confirmation prompt.tg export --out accounts.json— write to a file;tg import --overwriteto replace existing entries.tg update --check— only report whether a newer version exists;--pm <npm|bun|pnpm|yarn>to force the package manager.-v, --version,-h, --helpeverywhere.
Updating
tg update # checks npm, then updates in place via the manager that installed it
tg update --check # just tell me if there's a newer version
update figures out whether toguru was installed with npm, bun, pnpm or yarn
(from where the binary lives) and runs the matching global install. From a source
checkout or npx, it prints the manual command instead.
Examples
tg add codex --label [email protected] --activate
tg switch codex # pick interactively
tg list --json | jq '.[0].accounts'
tg export --out backup.json # ⚠️ contains credentials — keep it private
tg import backup.json
How it works
authdelegates to the provider's own login (claude auth login/codex login), then captures the resulting session and saves it as a profile
— all in one command. Re-authenticating an existing profile overwrites it in
place (and, for Claude, pre-fills the profile's email on the login page). Note
that the account you end up with is whichever one you sign into in the browser.addreads whatever session your provider CLI currently holds and stores
a copy under a name you choose. Your live session is left untouched.switchwrites a saved credential back into the provider's live location,
making that account active. On macOS, Claude credentials round-trip through
the Keychain; everywhere else they are plain files. For Claude, toguru also
restores the signed-in identity (oauthAccountin~/.claude.json) so the
displayed account, email and org match the active tokens — not just the
credentials.currentcompares the live session against what it last activated and
warns if they have drifted (e.g. a token was refreshed by the provider).
Staying in sync after a re-auth
Say you tg switch claude work, then run claude and it asks you to log in
again. The provider writes fresh credentials to its live location — and tg keeps
up: it treats the live session as the source of truth for the active profile
and copies those updated credentials back into it, so switching away and back
never restores a stale token. (We don't symlink the credential files — the
macOS Keychain can't be symlinked, and the atomic write-temp-then-rename most
CLIs use would break a symlink anyway.)
This reconcile happens automatically whenever tg looks: opening the hub (tg),tg switch, and tg status. You can also force it with tg sync. If the live
session turns out to be a different account (you logged in elsewhere withouttg switch), tg won't overwrite your saved profile — it tells you to tg add
the new one instead.
Nothing ever calls a remote API. Labels and plan names shown for Codex are
parsed locally from the (unverified) id_token purely for display.
⚠️ Security: saved accounts and exports contain real OAuth tokens. The
vault is created with0600permissions; treat exports as secrets.
Run from source (Bun)
bun install
bun run dev -- --help # run the CLI in dev
bun run build # produce dist/
bun test # run the test suite
Use as a library
The CLI is built on a small, typed core you can drive directly:
import { Store, providers } from "toguru-cli";
const store = await Store.load();
const account = store.get("claude", "work");
if (account) {
await providers.claude.writeActive(account.credential);
await store.setActive("claude", "work");
}
Exports: Store, providers, getProvider, providerIds, ToguruError,createProgram, plus all related types.
Project layout
src/
cli.ts # executable entrypoint (#!/usr/bin/env node)
program.ts # wires commander commands together
index.ts # public library surface
commands/ # one file per command (+ interactive menu, shared prompts)
providers/ # provider abstraction + claude/codex implementations
core/ # paths, keychain, account vault (Store)
utils/ # fs, jwt, logger, errors, strings, process helpers
tests/ # bun:test unit tests
License
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found