hydra on the command line.
hydra opens terminals inside named environments. Each one has its own Claude Code account, GitHub login, git author and SSH key, cloud logins and secrets. A terminal stays in its environment, and none of them can quietly use another's account.
Download the installer hydra + hydraui
Portable: hydraui.exe · hydra.exe
What hydra does
Most command-line tools read their login and settings from a folder you can move with an environment variable. Claude Code uses CLAUDE_CONFIG_DIR, the GitHub CLI uses GH_CONFIG_DIR, git uses GIT_CONFIG_GLOBAL. hydra keeps a separate set of those folders for each environment and starts your shell with them already set.
[work] PS> gh api user --jq .login work-user [work] PS> git config user.email work@example.com
[personal] $ gh api user --jq .login my-username
- Stop identity mix-ups. Commits and pushes always use the environment's author, SSH key and GitHub login.
- Run Claude Code on several accounts at once. Each environment has its own Claude sign-in, usage limits and history. Your skills, plugins, settings and MCP servers stay shared.
Install and update
Download the installer hydra + hydraui
Portable: hydraui.exe · hydra.exe
The installer puts hydra.exe (and hydraui) in %LOCALAPPDATA%\Programs\hydra, adds it to your PATH and runs hydra init: open a new terminal and hydra is there. For the portable hydra-x86_64-pc-windows-msvc.exe instead (it has a .sha256 beside it in the latest release), rename it to hydra.exe, put it in a folder on your PATH, then create hydra's home folder:
PS> hydra init created C:\Users\you\.hydra\config.toml
From then on, hydra update fetches the latest release and checks its SHA-256 checksum before replacing itself. hydra update --check only reports. It won't update while another hydra terminal is open.
PS> hydra update hydra 0.5.0 is installed; 0.5.1 is available updated to 0.5.1
To build from source instead, install Rust from rustup.rs, then git clone https://github.com/davojc/hydra.git and cargo build --release.
Prefer a window? hydraui, the desktop app, opens the same environments as tabs, with a file tree, git changes and account status. It reads the same ~/.hydra folder, so everything here applies to it too. See the App guide.
Walkthrough: two accounts, GitHub and Claude
This sets up a work and a personal environment, each with its own GitHub account, Claude account, git author and SSH key.
Step 1One SSH key per GitHub account
GitHub won't accept the same key on two accounts. Add each .pub file to the matching account under Settings → SSH and GPG keys.
ssh-keygen -t ed25519 -f $HOME\.ssh\id_ed25519_work -C "work@example.com" ssh-keygen -t ed25519 -f $HOME\.ssh\id_ed25519_personal -C "me@example.com"
Step 2Create the environments
Each gets its own colour. New environments start with no tools on.
hydra env new work hydra env new personal
Step 3Turn on the tools each one uses
hydra add only writes configuration. It never runs a tool or signs you in.
hydra add claude work hydra add git work --name "Your Name" --email work@example.com --ssh-key ~/.ssh/id_ed25519_work hydra add github work --owner acme hydra add git personal --name "Your Name" --email me@example.com --ssh-key ~/.ssh/id_ed25519_personal hydra add github personal hydra add claude personal
Step 4Sign in inside each environment
Use each tool's own sign-in command. The terminal opens even before you've signed in, and hydra lists what's missing.
PS> hydra shell work hydra: claude: not signed in - run claude auth login hydra: github: not signed in - run gh auth login [work] PS> gh auth login [work] PS> claude auth login [work] PS> exit
Repeat in hydra shell personal with your personal accounts.
Step 5Check
PS> hydra whoami --env work env work · work claude work@example.com (Acme) ok github work-user ok git work@example.com ok
Each terminal stays in its environment until you close it, and you can have both open at once. Run claude in each: /status shows that environment's account.
How it works
hydra starts each terminal with environment variables that point every tool at that environment's own folder under ~/.hydra/state/<env>/.
- Nothing leaks between environments. Identity variables inherited from the terminal you started in are removed, for example
GH_TOKEN,AWS_PROFILEorANTHROPIC_API_KEY. That includes those of tools the environment doesn't use, even when one hydra terminal is started from inside another. - Launch fails closed. If something could make a tool fall back to another identity, hydra refuses to open the terminal and tells you how to fix it. Examples are a configured SSH key that doesn't exist, or a secret you referenced but never stored. A tool that simply isn't signed in yet doesn't block anything.
- Secrets live in Windows Credential Manager. Config files only reference them. Values never go to disk or into hydra's output, with one exception: a gws credentials file, which is written readable by your Windows account only.
Tools
Turn a tool on with hydra add <tool> [env]. Inside a hydra terminal you can leave out the environment. hydra add with no tool lists tools and which are on; hydra remove <tool> [env] turns one off and keeps its saved logins.
| Tool | What each environment gets | Flags |
|---|---|---|
claude | Its own Claude Code sign-in, sharing your ~/.claude setup | --mcp-exclude |
github (gh) | Its own gh auth login; git's HTTPS pushes to github.com use it | --owner, --strict |
git | Always on, even without hydra add git: your global git config loads underneath, plus the folder guard. Adding it gives the author, email, SSH key, optional signing key and its own Git Credential Manager space for other HTTPS hosts. | --name, --email, --ssh-key, --signing-key |
aws | An AWS profile, optionally with private config and credentials files | --profile (required), --isolate |
azure | Its own az login | |
gcloud | Its own gcloud auth login and configurations | |
gws | Its own Google Workspace CLI login, or stored credentials | --credentials-secret |
kube | Its own kubeconfig | --kubeconfig |
codex | Its own Codex CLI login | |
gemini | GEMINI_API_KEY from a stored secret | --api-key-secret (required) |
jev | JEV_API_KEY (TypeSafe's Jev) from a stored secret, separate from hydraui's own Jev key | --api-key-secret (required) |
linear | LINEAR_API_KEY (a Linear personal API key) from a stored secret | --api-key-secret (required) |
Borrowing a login
If two environments use the same account, let one borrow the tool from the other instead of signing in twice. In envs/work/env.toml:
[claude] from = "personal" [github] from = "personal"
Or from the command line: hydra add claude work --from personal.
- The whole tool folder is shared, not just the credential file: login, history, sessions and settings. Nothing is copied or synced, so a sign-in or refresh in
personalis seen byworkstraight away. - A borrowing section holds only
from. The owner's settings are used, so any other key there is an error. The owner must have the same tool turned on withoutfrom; chains aren't allowed, and an environment can't borrow from itself. - Except
[github]ownersandstrict. They are guard policy, so they stay with each environment:[github]may set them next tofrom(hydra add github work --from personal --owner acme --strict). The borrower's own values are used, never the owner's; leaving them out means no owner list and not strict. - Only the folder is borrowed. A Claude login made with an API key in the owner's
[env](ANTHROPIC_API_KEYand the like) isn't borrowed; set it in the borrower's[env]too. - Sign in from the owner. If the borrowed tool isn't signed in, the terminal says where.
hydra whoamishows the owner next to the account.
PS> hydra shell work hydra: claude: not signed in - work borrows it from personal -> sign in there: hydra shell personal, then claude auth login
gitcan't be borrowed. The commit author and SSH key stay per environment. Git over HTTPS signs in throughgh, so borrowinggithubcovers it.- Guards still compare environment names. A folder bound to
personalstill blocksgit commitfrom aworkterminal, even ifworkborrows personal's GitHub login. The guards and the SSH key read only the borrower's own env.toml. - Editing the owner can break borrowers. If
hydra env edit personalremoves a toolworkborrows,workfails closed on its next launch and says why; its guard keeps working meanwhile, andhydra whoamishows the problem on that tool's line. - Removing and renaming are safe for owners.
hydra remove <tool> workon a borrower removes the section and leaves the owner's login alone.hydra remove <tool> personalrefuses while another environment borrows that tool from it, and names them.hydra env rm personalrefuses while any environment borrows from it (work borrows claude, github from personal).hydra env rename personal homerewritesfrom = "personal"in every borrower and lists the ones it changed. It refuses while a borrower's terminal is open.
Claude Code: separate accounts, shared setup
Each environment's Claude folder (~/.hydra/state/<env>/claude) is rebuilt from your existing ~/.claude every time a terminal opens. hydra only ever reads ~/.claude and ~/.claude.json.
Linked from ~/.claude
One copy; every environment sees it.
skills/,commands/,agents/hooks/,output-styles/plugins/: install once, available everywhere
Rebuilt each launch
Shared base plus this environment's changes.
settings.json+envs/<env>/claude/settings.jsonCLAUDE.md+ the environment's own section- MCP servers from
~/.claude.json, minus--mcp-exclude
Private
Never shared between environments.
- the Claude sign-in
- history, projects, sessions
- the rest of
.claude.json
settings.json or CLAUDE.md, for example with /model, hydra saves your version as .bak on the next launch, tells you, and rebuilds the file. Put lasting changes in ~/.claude or ~/.hydra/envs/<env>/claude/.Sign-in settings are never shared. If ~/.claude/settings.json has an apiKeyHelper or an API key under env, hydra leaves it out of every environment and warns you. Running claude outside hydra keeps using ~/.claude as before.
Each environment's settings.json also gets a PreToolUse hook that blocks git commit, git push and gh write commands in folders bound to another environment. See Folders and guards.
Folders and guards
A folder can belong to an environment. hydra then opens the right terminal there, and blocks git commit, git push and gh write commands (gh pr create, gh repo delete, gh api -X POST and the like) when they run from a terminal for a different environment. It covers commands you type and commands Claude Code runs.
Bind a folder
hydra bind E:\work work # a rule in config.toml: everything under E:\work hydra bind --file work # or a .hydra file in the current folder hydra bind # show which environment this folder resolves to hydra bind --list # list the rules in config.toml hydra unbind E:\work # remove the rule and/or .hydra file
--file writes .hydra and adds it to the repo's .git/info/exclude, so it is never committed. You can also write rules by hand:
[bindings] "E:/work/**" = "work" "E:/personal/**" = "personal"
The most specific binding wins. A .hydra file beats a rule at the same or shallower depth, and among rules the longest literal prefix wins. A folder that matches nothing is unbound, and nothing is blocked there.
hydra shell with no name opens the environment bound to the current folder. hydra shell work opens in the environment's home folder (set in env.toml) when you start it from somewhere not bound to it. hydra env new work --home E:\work sets home and binds the folder in one step. hydra whoami shows a folder line.
What a block looks like
[personal] PS> git push hydra: blocked git push - this folder belongs to work (rule E:/work/**), this terminal is personal -> open a work terminal here: hydra shell work -> or run it once anyway: hydra allow -- git push
hydra allow -- <command> runs that one command past the guard. When Claude Code is blocked, it is told to ask you to run hydra allow in your own terminal. It can't run hydra allow itself.
How it's enforced
git hooks
Each environment's gitconfig sets core.hooksPath to hydra's wrappers.
pre-commitandpre-pushask hydra first- Then the repo's own hook, or your global one, runs as usual
- The environment's
ssh_keyreaches git throughcore.sshCommand
Claude Code hook
A PreToolUse hook on the Bash and PowerShell tools.
- Follows
cdandgit -C - Catches
--no-verify - Checks
ghwrite commands too
If a binding names an environment that doesn't exist, hydra prints guard skipped and allows the command.
Git is always on. Every environment gets hydra's gitconfig, even without hydra add git. It includes your real global config (GIT_CONFIG_GLOBAL if you set it, else ~/.config/git/config and ~/.gitconfig) plus the guard. The Credential Manager namespace is written only with [git], and the gh credential helper only with [git] or [github].
Limits
The guard stops mistakes. It isn't a security boundary.
--no-verifyskips git hooks outside Claude Code. The Claude hook catches it.- A repo that sets its own
core.hooksPath(Husky, for example) replaces hydra's hooks, so the git guard is off there.hydra whoamisays so. The Claude hook still applies. - In a hydra terminal,
pre-commit installrefuses andgit lfs installcomplains, becausecore.hooksPathis set. Run them from a normal terminal. git config --globalinside hydra edits the generated file, which hydra rewrites on the next launch. Edit your real global file instead. The generated file's header names it.- The git hook looks up the binding at the repo root.
ghwrite commands you type yourself aren't guarded, even in a folder bound to another environment.ghstill uses the terminal's own environment's login, so it can't act as another account.- Plain
sshorscptyped by hand uses ssh's normal key selection, not the environment's key.
Variables and secrets
Any other variable goes under [env] in the environment's env.toml (hydra env edit work). Values can be plain or come from a secret stored in Windows Credential Manager.
[env] REGION = "eu-west" LINEAR_API_KEY = "secret:work/linear"
PS> hydra secret set work/linear value: •••••••••••••••• stored work/linear in Windows Credential Manager
For multi-line values such as JSON, pipe them in: Get-Content -Raw creds.json | hydra secret set work/gws-creds.
Commands
| Command | What it does |
|---|---|
hydra init | Creates ~/.hydra |
hydra env new|list|edit|rm|rename | Manages environments. env new <name> --home DIR sets where its terminals open and binds that folder. rename updates bindings, secrets, saved logins and borrowers too. |
hydra add [<tool>] [<env>] | Turns a tool on by writing its settings. Never signs in. --from <env> borrows the tool from another environment (see Borrowing a login). |
hydra remove <tool> [<env>] | Turns a tool off. Saved logins are kept. |
hydra shell [<env>] | Opens a terminal in an environment. With no name, the environment comes from the current folder's binding. Options: --shell pwsh|bash, --cwd DIR. |
hydra run <env> -- <command> | Runs one command in an environment |
hydra auth <tool> <env> | Runs a tool's sign-in inside an environment without opening a terminal |
hydra secret set|rm <env>/<key> | Stores or removes a secret |
hydra bind [<path>] <env> | Binds a folder to an environment. --file writes a .hydra file instead of a rule. With no arguments it shows the current folder's binding; --list lists every rule. |
hydra unbind [<path>] | Removes a folder's rule and/or .hydra file |
hydra allow -- <command> | Runs one command past the folder guard |
hydra whoami [--env <env>] | Shows which account each tool is actually using, and the current folder's binding |
hydra update [--check] | Installs the latest release from GitHub after checking its checksum |
Files
config.toml global settings and [bindings] envs/<env>/ yours: env.toml, plus optional claude/ overrides state/<env>/ hydra's: each tool's folder, sign-ins, generated config state/<env>/git/hooks/ hydra's git hook wrappers (the guard) secrets.toml names (never values) of stored secrets
HYDRA_HOME moves ~/.hydra. Deleting state/<env> resets an environment, but you'll need to sign in again.
Troubleshooting
| Message | What to do |
|---|---|
hydra: <tool>: not signed in | Sign in with that tool's own command inside the environment's terminal. If it says work borrows it from personal, sign in from the owner: hydra shell personal. |
hydra: work borrows [x] from y, but y has no [x] | Turn it on in the owner: hydra add x y. |
hydra: work borrows [x] from y, which borrows it from z | Borrowing doesn't chain. Borrow from the owner: from = "z". |
secret work/x isn't set | hydra secret set work/x |
…id_ed25519_work not found | Fix the key path: hydra add git work --ssh-key <path> |
CLAUDE_CONFIG_DIR error when opening | Remove CLAUDE_CONFIG_DIR from [env]; [claude] sets it. Then sign in again. |
… is a real folder, not a link | Move anything you want to keep into ~/.claude, delete that folder, and reopen the terminal. |
hydra: blocked git push - this folder belongs to work … | The folder is bound to another environment. Open the right terminal (hydra shell work) or run it once with hydra allow -- git push. hydra bind shows which rule applies. |
hydra: warning: guard skipped | A binding names an environment that doesn't exist, so nothing was checked. Fix the name in config.toml or the .hydra file, or create the environment. |
whoami says the repo sets its own core.hooksPath | Husky or similar replaces hydra's git hooks in that repo, so the git guard is off there. The Claude hook still guards it. |
| A Claude setting you changed disappeared | Your version is in settings.json.bak. Put lasting changes in ~/.claude/settings.json or envs/<env>/claude/settings.json. |
hydra is in use - not updating | Close the listed hydra terminals, then run hydra update again. |
Planned
These are designed but not built yet:
ssh,scpandsftpusing the environment's key outside git.- Windows Terminal profiles. One coloured tab per environment.
hydra doctorand macOS / Linux support.