New
Apps 821Makers 820This week 821
Promote your app−30%
Ditto CLI screenshot 1
2views in
the last 30 days

Ditto CLI

Switch between multiple Claude Code, Codex, opencode, OMP, Prime Agent, Pi, Gemini CLI, Copilot...

Built with Claude Code

by reyanshgupta · from USUnited States · added Oct 29, 2026
no ratings0 comments

Keep your work, personal, and client logins apart across your coding agents — Claude Code, Codex, opencode, Gemini CLI, Copilot, Cursor, Grok, Goose, and thirty more.

Each profile gets its own credentials and conversation history. Everything you set up once — skills, subagents, slash commands, hooks, plugins, memory files — stays shared, so a profile is the same working environment signed in as somebody else. Your existing setup keeps working as the default profile; nothing is moved, copied, or migrated.

ditto-cli create work        # a profile with logins of its own
ditto-cli claude work        # launch Claude Code inside it
ditto-cli workspace use work # or bind the project once and stop typing the name
ditto-cli codex-app work     # open its Codex Desktop window (macOS)

Pick a profile, then a tool:

┌──────────────────────────────────────────────────────────────────────────────┐
│            Ditto CLI  choose a profile, then Enter to pick a tool            │
└──────────────────────────────────────────────────────────────────────────────┘
┌ Profiles ──────────────┐┌ Selected profile ──────────────────────────────────┐
│  default  existing     ││work  Isolated profile                              │
│  personal              ││                                                    │
│› work  ★               ││★ Used when no profile is named                     │
│                        ││                                                    │
│                        ││Tools and sign-in status                            │
│                        ││Claude Code  ● Signed in                            │
│                        ││Codex        ○ Sign in required                     │
│                        ││Codex Desktop  Open app                             │
│                        ││fx           ● Signed in                            │
│                        ││opencode     ○ Sign in required                     │
│                        ││OMP          ● Signed in                            │
│                        ││Prime Agent  ● Signed in                            │
│                        ││Pi           ○ Sign in required                     │
│                        ││Gemini CLI   ● Signed in                            │
│                        ││Grok         ○ Sign in required                     │
│                        ││                                                    │
│                        ││Profile directories                                 │
│                        ││Claude Code  ~/.ditto/profiles/work/claude          │
│                        ││Codex        ~/.ditto/profiles/work/codex           │
│                        ││fx           ~/.ditto/profiles/work/fx-home/.fx     │
│                        ││opencode     …o/profiles/work/opencode/data/opencode│
│                        ││OMP          ~/.omp/profiles/work/agent             │
│                        ││Prime Agent  ~/.ditto/profiles/work/prime-agent     │
│                        ││Pi           ~/.ditto/profiles/work/pi              │
│                        ││Gemini CLI   …itto/profiles/work/gemini-home/.gemini│
└────────────────────────┘└────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│                  c Claude Code · x Codex · f fx · o opencode                 │
│             p OMP · a Prime · i Pi · X Codex Desktop · ⏎ any tool            │
│                   ↑↓ select · n new · e rename · d default                   │
│                  l sign in · L sign out · r refresh · q quit                 │
└──────────────────────────────────────────────────────────────────────────────┘

Ditto CLI takes its name from the shape-shifting Pokémon: one small tool, whichever coding identity you need.

Contents

Getting going — How it works · Supported agents · Install · Update · Quick start

Everyday use — TUI controls · Command-line usage · Which profile a command uses · Workspaces · T3 Code · Shell integration · Knowing which profile you are in

What a profile keeps and shares — Settings a new profile inherits · Skills, subagents, and everything else you set up once · Where credentials and files are stored

Reference — Scripting and agents · Environment variables · Renaming a profile signs Claude Code out · Windows notes · Remove Ditto CLI · Development

How it works

Every coding agent keeps its configuration and login somewhere under your home directory, and every one of them can be told to look somewhere else: through a variable of its own (CLAUDE_CONFIG_DIR, CODEX_HOME, GEMINI_CLI_HOME), through the XDG base directories, or, when it honours neither, through HOME itself. Ditto CLI keeps one such place per profile and starts the agent pointed at it:

ditto-cli claude work    # claude, with CLAUDE_CONFIG_DIR=~/.ditto/profiles/work/claude
ditto-cli gemini work    # gemini, with GEMINI_CLI_HOME pointing into the same profile

Nothing is moved, copied, or swapped, and only the process Ditto CLI started is affected. The profile is the same working environment signed in as somebody else: skills, subagents, commands, hooks, plugins, and memory files are linked back to yours, and only credentials, sessions, and caches stay inside it. Which lever each agent uses is in the table below.

Why opencode, Prime Agent, and Pi take more than one variable

opencode has no single home variable; it resolves its directories the XDG way, so Ditto CLI pins the three bases that hold credentials, configuration, and session state. XDG_CACHE_HOME is deliberately left alone so profiles keep sharing opencode's downloaded tooling. Those variables are set for the launched process and anything it starts, including commands opencode's own tools run.

Prime Agent and Pi settings can name a session directory, so managed profiles set PRIME_AGENT_SESSION_DIR or PI_CODING_AGENT_SESSION_DIR explicitly. That keeps transcripts and local harness state inside the selected profile even while reusable settings and capabilities are linked to yours.

Supported agents

Ditto CLI is not tied to any one agent, vendor, or launcher: anything that runs in a terminal and can be pointed at a directory can have a profile. Every agent is launched by its own command name, and everything after -- is the agent's own:

ditto-cli <command> <profile> -- <arguments>
ditto-cli grok work -- login

ditto-cli --help lists them all. Three levers cover every agent:

  • A variable of its own, set to a directory inside the profile — CODEX_HOME, GROK_HOME.
  • The XDG bases, pinned inside the profile, for agents that follow that convention. XDG_CACHE_HOME is left shared.
  • A private HOME, for agents that derive their paths from the home directory and honour nothing else. The profile's home mirrors your real one entry by entry — shell startup files, Git configuration, SSH, toolchains — except for the agent's own directory, so commands the agent runs still find your setup.
Agent Command Pointed at the profile by Sign-in state read from
Claude Code claude (cc) CLAUDE_CONFIG_DIR claude auth status; on macOS the credential is in the Keychain, keyed to that directory
Codex codex (cx) CODEX_HOME codex login status
fx fx private HOME, with FX_DISABLE_KEYCHAIN=1 so the login is a file inside it fx status --json
opencode opencode (oc) XDG_DATA_HOME, XDG_CONFIG_HOME, and XDG_STATE_HOME opencode auth list
OMP omp omp --profile <name> and OMP_PROFILE credentials in its agent.db
Prime Agent prime-agent (pa) PRIME_AGENT_CODING_AGENT_DIR and PRIME_AGENT_SESSION_DIR auth.json
Pi pi PI_CODING_AGENT_DIR and PI_CODING_AGENT_SESSION_DIR auth.json
Gemini CLI gemini GEMINI_CLI_HOME oauth_creds.json
Qwen Code qwen QWEN_HOME oauth_creds.json
OpenClaude openclaude OPENCLAUDE_CONFIG_DIR .credentials.json; the macOS Keychain, which it prefers, is user-wide
Copilot copilot COPILOT_HOME not readable: the token is in the OS keychain, keyed by GitHub account
Cursor Agent cursor-agent CURSOR_CONFIG_DIR, with AGENT_CLI_CREDENTIAL_STORE=file not readable
Grok grok GROK_HOME auth.json
Devin devin XDG bases credentials.toml
Kimi Code kimi KIMI_CODE_HOME credentials/
Cline cline CLINE_DIR data/settings/providers.json
Codebuff codebuff private HOME (~/.config/manicode) credentials.json
Continue cn CONTINUE_GLOBAL_DIR none: current builds have no sign-in
Command Code command-code private HOME auth.json
Hermes Agent hermes HERMES_HOME auth.json, .env
OpenClaw openclaw OPENCLAW_STATE_DIR credentials/, secrets.json, .env
Mistral Vibe vibe VIBE_HOME, with VIBE_TEST_DISABLE_KEYRING=1 .env
Rovo Dev acli private HOME (~/.rovodev and ~/.acli) ~/.acli
Amp amp XDG bases secrets.json
Droid droid private HOME, with FACTORY_DISABLE_KEYRING=1 not readable
Goose goose XDG bases, with GOOSE_DISABLE_KEYRING=1 secrets.yaml
Aider aider private HOME oauth-keys.env; API keys come from the environment
Crush crush XDG bases the data directory's crush.json
Kilo Code kilo XDG bases auth.json
Kiro kiro-cli private HOME data.sqlite3
Auggie auggie private HOME session.json
Antigravity agy private HOME not readable: the Google login is in the OS keychain with no way out, so only GEMINI_API_KEY is per profile
MiMo Code mimo XDG bases auth.json
Ante ante ANTE_HOME auth/
Trae traecli private HOME cli/auth.json; the least certain entry, since Trae's documentation names no variable
Autohand autohand AUTOHAND_HOME not readable: the login shares config.json with the settings

"Not readable" means ditto-cli status reports the agent as unavailable even when it is installed: the login is somewhere Ditto CLI has no file to check, and a keychain entry is one every profile shares besides. Sign in with the agent's own command through Ditto CLI — ditto-cli grok work -- login — or from inside it; the sign_in field of ditto-cli create --json names the right form for each.

The rule for what a profile shares is the same for every row: settings, instructions, skills, commands, and plugins are linked back to yours; credentials, sessions, and caches are not, and neither are MCP configuration files, because the ones that carry OAuth tokens are named the same as the ones that do not. Each entry's own caveats — an undocumented variable, a keychain with no switch, a fork's macOS data directory — are in the comment beside it in src/tools.rs, and DITTO_<AGENT>_BIN overrides any agent's executable (DITTO_CURSOR_AGENT_BIN=agent).

Install

Ditto CLI is useful once at least one supported agent is installed.

Take whichever channel you already use. They all install the same binary, and the command is ditto-cli either way:

Channel Command Notes
Homebrew brew install reyanshgupta/tap/ditto-cli macOS and Linux. Prebuilt, so no Rust toolchain.
npm npm install -g @reyanshgupta/ditto-cli macOS, Linux, and Windows. The same prebuilt binaries.
binstall cargo binstall ditto-cli Takes the released binary rather than compiling one.
Cargo cargo install ditto-cli Builds from source; needs Rust 1.85 or newer.

If you installed Claude Code or Codex with npm, npm is already here. You can also try Ditto CLI without installing it:

npx @reyanshgupta/ditto-cli list

The npm package is scoped because plain ditto-cli on npm belongs to an unrelated project. The command it installs is still ditto-cli.

cargo binstall is a good deal quicker than cargo install, because a source build compiles a bundled SQLite before it links anything. To build from the latest source, or from a checkout:

cargo install --git https://github.com/reyanshgupta/ditto-cli

git clone https://github.com/reyanshgupta/ditto-cli.git
cd ditto-cli
cargo install --path .

After a Cargo install, make sure Cargo's binary directory is on your PATH:

export PATH="$HOME/.cargo/bin:$PATH"

On Windows, cargo install already writes into %USERPROFILE%\.cargo\bin, which rustup puts on your PATH, and an npm install needs nothing further either.

Ditto CLI installs as ditto-cli, not ditto: macOS already uses that name for its built-in file-copy utility at /usr/bin/ditto.

macOS, Linux, and Windows are all supported, and every command below behaves the same on each. A few smaller things differ on Windows — see Windows notes.

Update

A Homebrew install updates through Homebrew:

brew upgrade ditto-cli

An npm install updates through npm:

npm install -g @reyanshgupta/ditto-cli@latest

A Cargo install updates itself:

ditto-cli update           # install the newest crates.io release
ditto-cli update --check   # compare versions without installing
ditto-cli update --git     # install from the Git repository instead

update runs cargo install for you, so it needs Rust on your PATH. It stops early when you already have the newest release. During a build it shows a compact animated status instead of Cargo's full compilation log; if the build fails, it prints that log so the error is not hidden. Asking crates.io for the published version needs a network connection; without one it says so and installs anyway.

update only replaces a copy in Cargo's own bin directory. Run it against a Homebrew install, or a binary from the releases page, and it says so before it starts, then leaves that copy alone: a cargo install would land in a different directory and shadow the existing binary rather than replace it. Use brew upgrade ditto-cli or the newer archive instead.

Against an npm install it does not start at all. npm keeps its copy inside its own tree, so update names the npm command and stops rather than leaving you with two copies and whichever PATH reaches first. Pass --git if a source build is what you actually want.

Quick start

Open the picker:

ditto-cli
  1. Make a profile. Press n and name it, such as work.
  2. Sign in. With the profile selected, press l and choose Claude Code, Codex, fx, opencode, or Prime Agent; Prime Agent opens straight onto its /login dialog. Every other agent signs in from inside itself — launch it in step 3 and run /login, or its own login command, there.
  3. Launch a tool. Press Enter for a searchable list of installed agents, including Codex Desktop on macOS, or a key directly: c Claude Code, x Codex CLI, X Codex Desktop, f fx, o opencode, p OMP, a Prime Agent, i Pi.

Each tool keeps its own credentials. Signing in to one does not copy credentials into another.

Or skip the picker entirely — every one of those steps has a command:

ditto-cli create work
ditto-cli claude work -- auth login
ditto-cli claude work

TUI controls

Key Action
↑ / ↓ or k / j Select a profile
c Launch Claude Code
x Launch Codex CLI
X (Shift+x) Open Codex Desktop with the selected profile (macOS)
f Launch fx
o Launch opencode
p Launch OMP
a Launch Prime Agent
i Launch Pi
Enter or t Pick an installed agent, including Codex Desktop on macOS; type to filter
l Sign in with Claude Code, Codex, fx, opencode, or Prime Agent
L Sign out, with confirmation
n Create a profile
e Rename the selected profile
d Mark the selected profile ★ as the default, or unset it
r Refresh sign-in status
q, Esc, or Ctrl+C Quit or close a dialog

Sign-in status is checked in the background, so the list stays responsive while each CLI is asked. A spinner marks the tools still being checked. On macOS, an installed Codex Desktop also appears in the selected-profile pane and the launch menu. Its Open app label does not claim a desktop sign-in state from CLI credentials.

Enter puts every installed agent in one list, narrowed as you type:

┌──────────────────────────────────────────────────────────────────────────────┐
│            Ditto CLI  choose a profile, then Enter to pick a tool            │
└──────────────────────────────────────────────────────────────────────────────┘
┌ Profiles ──────────────┐┌ Selected profile ──────────────────────────────────┐
│  default  existing     ││work  Isolated profile                              │
│  personal              ││                                                    │
│› work  ★               ││★ Used when no profile is named                     │
│                        ││                                                    │
│                        ││Tools and sign-in status                            │
│                        ││Claude Code  ● Signed in                            │
│       ┌ Launch in 'work' ────────────────────────────────────────────┐       │
│       │› ▏                                                           │       │
│       │                                                              │       │
│       │Claude Code  ● Signed in                                      │       │
│       │Codex        ○ Sign in required                               │       │
│       │Codex Desktop  Open app                                       │       │
│       │fx           ● Signed in                                      │       │
│       │opencode     ○ Sign in required                               │       │
│       │OMP          ● Signed in                                      │       │
│       │Prime Agent  ● Signed in                                      │       │
│       │Pi           ○ Sign in required                               │       │
│       │Gemini CLI   ● Signed in                                      │       │
│       │Grok         ○ Sign in required                               │       │
│       │                                                              │fx     │
│       │type to filter · ↑↓ · Enter launches · Esc                    │pencode│
│       └──────────────────────────────────────────────────────────────┘       │
│                        ││Prime Agent  ~/.ditto/profiles/work/prime-agent     │
│                        ││Pi           ~/.ditto/profiles/work/pi              │
│                        ││Gemini CLI   …itto/profiles/work/gemini-home/.gemini│
└────────────────────────┘└────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│                  c Claude Code · x Codex · f fx · o opencode             

Description taken from the repository README.

Ratings

–
0 ratings
5 0
4 0
3 0
2 0
1 0

Rate this app

Sign in to rate

Comments 0

Sign in to comment

No comments yet.

Related apps

#accounts · #switcher · #cli