v2.2.2

Manage AI CLI environments, per shell

Isolate accounts for Claude Code, Codex, and Gemini CLI across work and personal contexts — switch accounts freely while keeping your conversations continuous.

Get Started View on GitHub
Install via Homebrew
$ brew install OffskyLab/orrery/orrery
Or via APT (Ubuntu / Debian)
$ echo "deb [trusted=yes] https://offskylab.github.io/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/orrery.list
$ sudo apt update && sudo apt install orrery
Activate shell integration
$ source ~/.orrery/activate.sh

Everything you need to context-switch

🔒

Switch freely, no login hassle

Set up once, then switch with one command. Each environment has its own credentials, completely isolated — no logging out, no re-entering passwords, no waiting for auth flows.

💬

Shared sessions

Switch accounts and pick up where you left off. Session data is shared by default — claude --resume works seamlessly after switching environments.

🐚

Per-shell activation

orrery use work sets environment variables only in the current shell. Other windows stay on their own environment, unaffected.

Interactive wizard

Create environments with a guided multi-select UI. Pick your tools with arrow keys and space — no flags needed.

🔑

Custom env vars

Store API keys and other variables per environment. They're automatically exported when you switch with orrery use.

Zero runtime overhead

Built in Swift — native binary, instant startup. Shell integration is a tiny eval'd function, not a daemon. Supports bash and zsh.

How it works

1

Install shell integration

Run orrery setup once. It generates ~/.orrery/activate.sh and adds it to your rc file. Then source ~/.orrery/activate.sh to activate in the current shell.

activate.sh also checks for new Orrery releases in the background (once per day) and shows a notice at your next shell open.

2

Create environments

Run orrery create work. An interactive wizard lets you pick tools and configure session sharing. Environments are stored under ~/.orrery/envs/.

3

Switch with one command

orrery use work exports the right config dirs and custom env vars into your current session. Your conversation history stays intact across switches.

4

Resume where you left off

After switching accounts, claude --resume picks up your last session. Auth is isolated, but sessions are shared — the best of both worlds.

The origin Environment

Not just another environment — a system passthrough

origin is Orrery's reserved name for your unmodified system environment. Switching to it with orrery use origin (or orrery deactivate) doesn't load any isolated config — it unsets all Orrery variables and lets your tools fall back to their system-wide settings, exactly as if Orrery weren't installed.

Unlike regular environments, origin cannot be deleted, renamed, or configured with tools and environment variables. It has no isolation, no per-project memory, and no session separation — it's simply the state before Orrery.

This makes origin useful as a clean escape hatch: run a quick command under your default system credentials without switching accounts or polluting any Orrery environment.

Use Cases

💼

Work / Personal

Your company uses a Claude Team plan, and you have a personal Pro subscription. Instead of logging out and back in, just switch environments.

$ orrery use work
# → uses company Team plan

$ orrery use personal
# → uses personal Pro plan
🏢

Multiple Clients

Freelancers and consultants working with different clients — each with their own API keys and credentials. One command to switch context.

$ orrery create client-a --tool claude
$ orrery create client-b --tool claude
$ orrery use client-a
💬

Resume After Switching

Mid-conversation with Claude on your work account? Switch to personal, do something, then switch back — your session is still there.

$ orrery use work
$ claude
# ... working on a task ...

$ orrery use personal
$ orrery use work
$ claude --resume
# → picks up exactly where you left off

AI Tool Integration

Orrery integrates with Claude Code, Codex CLI, and Gemini CLI via MCP. Delegate tasks across accounts, share memory between tools, and manage sessions — all from one place.

1

One-time setup

Run this in your project directory. Orrery registers itself as an MCP server and installs slash commands.

$ orrery mcp setup
2

Slash commands

After setup, use these directly in Claude Code:

/orrery:delegate Delegate a task to another account
/orrery:delegate Use the "work" account to review this PR for security issues
/orrery:sessions List sessions and resume by index
/orrery:sessions
then: orrery resume 1
3

Or just ask naturally

Claude understands your environments through MCP tools. You can say things like:

"Review this PR using my work account"
"Which account am I on?"
"Show me recent sessions and resume the last one"
4

MCP tools & shared memory

All AI tools get these tools automatically. Knowledge saved by one tool is accessible from any other.

orrery_memory_read Read shared project memory
orrery_memory_write Write to shared project memory
orrery_delegate Run a task under a different account
orrery_list List all environments
orrery_sessions List sessions for the current project
orrery_current Get the active environment
5

External memory storage

By default, memory is stored under ~/.orrery. You can redirect it to any directory — including an external wiki like Obsidian — so your AI memory lives alongside your notes.

$ orrery memory storage ~/Documents/my-wiki/orrery
New path has no memory yet. Copy current memory there?
▶ Copy memory to new path
No, start fresh

Fragments and consolidation work the same way — the AI agent reads and writes directly to your wiki folder.

P2P Memory Sync EXPERIMENTAL

Keep project memory in sync across machines and teammates — in real time, peer to peer.

🌐

Desktop + Laptop

Same person, two machines. Start the daemon on each — Bonjour finds them automatically on the same network.

# Desktop
$ orrery sync daemon --port 9527

# Laptop (auto-discovers via Bonjour)
$ orrery sync daemon --port 9528
👥

Team Collaboration

Create a team, share an invite code. When teammates join and start the daemon, everyone's memory stays in sync.

$ orrery sync team create my-team
$ orrery sync team invite --port 9527
# → share the invite code

# Teammate joins:
$ orrery sync team join <code>
$ orrery sync daemon --port 9528
🔒

Encrypted (mTLS)

For sensitive environments. Both peers must present certificates signed by the same CA — unauthorized peers are rejected at handshake.

$ orrery sync daemon --port 9527 \
  --tls-ca ca.pem \
  --tls-cert node.pem \
  --tls-key node-key.pem
🌍

Cross-Network

Different offices, different networks. A lightweight rendezvous server coordinates peer discovery — data flows directly between peers.

# On a VPS:
$ orrery sync rendezvous --port 9600

# Each peer:
$ orrery sync daemon --port 9527 \
  --rendezvous rv.example.com:9600

Only project memory is synced — sessions stay local (they're machine-specific). New teammates get all existing memory on first connect via manifest reconcile. Memory changes are tracked as conflict-free fragments and consolidated by the AI agent at session start.

Commands

Environments
orrery create <name>Create a new environment
orrery delete <name>Delete an environment
orrery rename <old> <new>Rename an environment
orrery listList all environments
orrery info [name]Show environment details
Switching
orrery use <name>Activate in current shell
orrery deactivateDeactivate current environment
orrery currentPrint active environment
orrery which <tool>Print tool config dir path
Configuration
orrery tools add [-e <name>]Add a tool (wizard)
orrery tools remove [-e <name>]Remove a tool
orrery env set <K> <V>Set an environment variable
orrery env unset <K>Remove an environment variable
orrery memory storage <path>Redirect memory to external path
Sessions
orrery sessionsList all sessions for current project
orrery sessions --claudeClaude sessions only
orrery sessions --codexCodex sessions only
orrery sessions --geminiGemini sessions only
Sync
orrery sync daemonStart the sync daemon
orrery sync statusShow daemon and peer status
orrery sync pair <host:port>Pair with a remote peer
orrery sync team createCreate a new team
orrery sync team inviteGenerate an invite code
orrery sync team joinJoin a team
orrery sync rendezvousRun a rendezvous server
Shell integration
orrery setupInstall shell integration
orrery initPrint shell function (eval)
orrery updateSelf-update via Homebrew / apt

Release History

Release notes — full technical details in the CHANGELOG.

v2.2.2 latest

orrery list: pipe-buffer deadlock fix + parallel lookups + memory path = directory

orrery list could hang indefinitely on machines where Claude Code had connected several MCP servers (figma, notion, etc.) — their OAuth tokens get embedded into the Claude Keychain entry, and the resulting credential JSON exceeds the macOS pipe buffer (~16 KB, sometimes less). ClaudeKeychain.findPassword called security, then waitUntilExit(), then read the pipe — the textbook pipe-buffer deadlock: security blocks writing into a full pipe while orrery blocks waiting for it to exit. Diagnosed by running security find-generic-password directly (returns in 25 ms with the full credential), confirming Keychain itself was fine. Fix: drain the pipe before waitUntilExit. The same pattern lurked in MCPServer.execCommand; both stdout and stderr pipes are now drained concurrently on background queues, since serialized drain would still deadlock on whichever pipe filled second.

Each env's Claude/Codex/Gemini account lookup used to run serially, so even one slow Keychain read on env 1 blocked envs 2..N. environmentRows now flattens every (env, tool) pair into a single work list and dispatches them via DispatchQueue.concurrentPerform. Worst-case wall time drops from O(N×M×per-call) to roughly O(per-call). Output formatting and ordering are unchanged.

orrery info and orrery memory info used to print .../ORRERY_MEMORY.md — a file that never actually existed. The original v1.1.0 design wrote a single ORRERY_MEMORY.md and symlinked it into Claude's auto-memory dir; v1.1.2 switched to directory-level symlinking so every auto-memory write lands in the shared/syncable path, which left the filename as dead weight the code kept referencing. The Memory Path line now shows the folder (e.g. ~/.orrery/shared/memory/{projectKey}/), which is where MEMORY.md + fragment files actually live.

The MCP tools orrery_memory_read / orrery_memory_write now operate on MEMORY.md inside that folder — matching Claude's auto-memory convention — so Codex and Gemini (which call these tools via MCP) read and write the exact same file Claude does at session start. Internal rename: EnvironmentStore.memoryFile()memoryDir(); memory export now defaults its output filename to MEMORY.md.

v2.2.0

Localized CLI + Japanese stub + readable orrery list

Every CLI string now lives in Sources/OrreryCore/Resources/Localization/<locale>.json instead of being hard-coded in Swift. An SPM build plugin reads the JSON on every swift build and generates typed accessors plus embedded translation tables — no runtime resource lookup, so single-file deploys (Homebrew, .deb) keep working. A drift check (missing keys, mismatched placeholders) fails the build before a release can ship a half-translated locale. Japanese (ja.json) is wired up but stubbed from English while the translation lands; it falls back to EN at runtime via AppLocale.detect().

orrery list got a multi-line layout: each environment becomes its own block with one tool per indented row, prefixed with ·. Once an env has multiple tools or longer suffixes (email + plan + model), this is much easier to scan than the old single-line format. The active environment header is highlighted in cyan; the rest uses a quiet monochrome ladder (email near-white → plan mid-gray → model dim) so the data stays readable without competing colors. ANSI is stripped cleanly when piped or read by MCP.

v2.1.2

Gemini honors orrery envs — and delegate --gemini works with API keys

gemini-cli ignores GEMINI_CONFIG_DIR and always reads ~/.gemini/, which made per-env isolation impossible. Each env now ships with a sibling gemini-home/ directory whose .gemini symlinks back to the env's gemini config; orrery use exports ORRERY_GEMINI_HOME and a shell gemini() wrapper runs gemini with HOME=$ORRERY_GEMINI_HOME so it lands in the right place. Setup is idempotent and backfilled for existing envs on the next orrery use.

orrery delegate --gemini with API-key auth used to fail because gemini-cli's non-interactive validator only looks at process.env.GEMINI_API_KEY and won't fall through to its own Keychain or encrypted-file lookup. Delegate now pre-extracts the stored key (macOS Keychain first, then decrypts gemini-credentials.json via the same scrypt + AES-256-GCM derivation gemini-cli uses) and injects it before invoking the child. orrery list also surfaces gemini's auth type — gemini(api key) / gemini(vertex) / OAuth email — by reading settings.json.

v2.1.1

orrery delegate no longer stalls 3 seconds in non-TTY callers

When orrery delegate was invoked from a script, SSH without a pty, or the MCP server, Claude (and the other tools) would print a "no stdin data received in 3s" warning and hang for 3 seconds before continuing. The delegated tool already takes the prompt as a CLI argument, so the child's stdin is now wired to /dev/null instead of inheriting the caller's. Removes both the warning and the latency.

v2.1.0

orrery delete opens a multi-select when called without args

Cleaning out throwaway envs after testing used to mean running orrery delete <name> once per env. Now orrery delete with no name opens a multi-select picker — arrow keys + space to mark, enter to confirm — and deletes them all in one go. --force skips the confirmation; passing a name still does the original single-env delete.

Bug fixes bundled in: orrery create --tool X now still runs the chosen tool's sub-wizard (login source, clone source, sessions, memory) instead of skipping every wizard step; clone no longer leaks identity via a backups/ heal step; self-login and clone strip identity + onboarding so Claude re-prompts cleanly; missing .claude.json is healed from backups after migration; stale symlinks after migration and origin tool logins are fixed.

v2.0.0

Renamed to Orrery

Why the rename? orbital is a crowded name in software land — search results constantly collide with unrelated tools. This release renames the project to orrery (the mechanical model of the solar system) — thematically closer to what this tool does (maintaining multiple parallel config universes), and much less common as a software name.

No feature changes — purely a rename: CLI binary orbitalorrery, config dir ~/.orbital/~/.orrery/, env vars ORBITAL_*ORRERY_*, Swift module OrbitalCoreOrreryCore, Homebrew tap OffskyLab/orrery/orrery.

Automatic migration: on first run, orrery detects ~/.orbital/ (when no ~/.orrery/ exists) and moves the directory in place, regenerates activate.sh, and updates the source line in your shell rc files. The old Orbital repo stays up as a deprecated wrapper — existing orbital invocations, MCP configs, and shell aliases keep working with a deprecation notice.

v1.1.6

Change accounts without losing the setup you've tuned

Copying an env used to be an awkward tradeoff: either re-login (annoying), or clone everything and watch the account get overwritten along with your theme, plugins, and dismissed hints. This release splits "which account to log in with" and "which env's settings to copy" into two independent steps — you can pull the account from A and everything else from B, and orrery merges .claude.json for you. Identity keys follow the login source; theme, projects, dismissed dialogs follow the clone source; per-account caches are cleared so Claude refreshes them cleanly.

Each tool also has its own login + clone flow now. When you create an env it asks "Add and set up {tool}?" one at a time, instead of bundling all three together. orrery tools splits into tools add and tools remove; session isolation is per-tool, so "Claude shared, Codex isolated" is finally a valid combination; and orrery list / orrery info show each tool's login as email and plan.

v1.1.5

The create wizard cleans up after itself

Every wizard step used to leave its menu onscreen, so by the time you finished, your scrollback was filled with intermediate choices and the actual summary got buried. Now each step clears itself when you confirm, leaving only the final result visible. After orrery create, you're also asked whether to switch to the new env right away — one less command to type. While we were at it, the defunct claude auth login step was removed too: it doesn't respect CLAUDE_CONFIG_DIR, so keeping it around was just misleading.

v1.1.4

Version checks no longer stall shell startup

Powerlevel10k instant-prompt users kept having the prompt interrupted every time they opened a shell — the culprit was a synchronous version check during shell init. Now it runs in the background when you invoke an orrery command, at most once every 4 hours. When a new version is out, a yellow notice appears on each orrery command until you run orrery update.

v1.1.3

orrery use persists across new shells

After running orrery use work in one terminal, opening a fresh terminal used to drop you back to origin. The switch simply wasn't being written to the current-env pointer, so new shells had nothing to restore. Every successful orrery use now writes the pointer, and new shells pick up where you left off.

v1.1.2

Memory just works — no CLAUDE.md tweaks

Getting Claude to read orrery's shared memory used to require hand-editing CLAUDE.md with a "please read memory from this path" instruction — hardly the "just works" experience we wanted. Now each project's Claude auto-memory directory is symlinked to orrery's shared memory automatically. No config, no CLAUDE.md edits — Claude picks it up on its own. Same memory across envs and machines.

v1.1.1

ORRERY_MEMORY.md hooks into Claude automatically

Switching envs meant Claude couldn't see the memory you'd saved earlier, because each env's auto-memory directory is its own. Now orrery create (when Claude is selected) drops a symlink inside that directory pointing to orrery's shared memory, so the same memory shows up across envs. Also fixed a Homebrew cache issue in orrery update — it runs brew update first now.

v1.1.0

default renamed to origin

Why the rename? default was too ambiguous: is it "orrery's default environment" or "the system state before orrery touched anything"? Even I got confused sometimes. origin makes it obvious — it's the starting point, the state you were in before entering orrery. Existing envs and config files migrate automatically.