Per-folder GitHub CLI workspace manager
Project description
GH Workspace Manager (ghw)
Per-folder GitHub CLI auth for multi-account workflows.
Why This Exists
You work with multiple GitHub accounts:
- personal - Your personal account
- work - Your work/employer account
- client - Client projects
Example uses: personal + work + freelance clients, or personal + open source + consulting.
GitHub CLI stores auth globally in ~/.config/gh/. Every gh auth login overwrites the previous one. You're constantly switching and losing track.
Solution: Each folder uses mise to set GH_CONFIG_DIR, and ghw validates before running gh. You cd into a project, gh automatically uses the right account.
Install
Required: mise
ghw requires mise — it is the mechanism that sets GH_CONFIG_DIR per project folder. Without it, workspace switching doesn't happen. If you are not using mise, this tool is not for you.
curl https://mise.run | sh
Add to your shell rc (~/.bashrc or ~/.zshrc):
export MISE_TRUSTED_CONFIG_PATHS="$HOME/src"
eval "$(mise activate bash)" # or: eval "$(mise activate zsh)"
Install ghw
uv tool install ghw # recommended
pipx install ghw # fallback if no uv
uvx ghw # zero-install try-it
Verify:
ghw --help
Setup
1. Create Workspaces
One per GitHub account you want to use:
ghw workspace init personal
ghw workspace init work
ghw workspace list
Configs live under ~/.config/gh-workspaces/<workspace>/.
2. Add .mise.toml to Each Project
Lazy way (with init-here):
cd ~/src/my-project
# If git remote exists, auto-detect from URL:
git remote add origin git@github.com:personal/myrepo.git
ghw init-here --auto
# Or specify workspace explicitly:
ghw init-here --workspace personal
Manual way:
Create ~/src/PROJECT/.mise.toml:
[env]
# Absolute path required — mise does not expand ~ or $HOME in env values.
# macOS: /Users/<you>/.config/gh-workspaces/personal
# Linux: /home/<you>/.config/gh-workspaces/personal
GH_CONFIG_DIR = "/home/<you>/.config/gh-workspaces/personal"
Replace personal with work or client as needed. Tip: ghw init-here --workspace personal emits the correct absolute path for your OS automatically.
3. Configure mise Auto-Trust
Add to your shell rc (~/.bashrc or ~/.zshrc) so all .mise.toml files
under ~/src are trusted without manual mise trust:
# Must be exported BEFORE `mise activate` so activation picks it up.
export MISE_TRUSTED_CONFIG_PATHS="$HOME/src"
eval "$(mise activate bash)" # or: eval "$(mise activate zsh)"
4. Add gh Wrapper Function
Add to the same shell rc:
gh() {
if [[ -n "$GH_CONFIG_DIR" ]]; then
echo "[ghw] Using gh via ghw wrapper (GH_CONFIG_DIR: $GH_CONFIG_DIR)"
ghw gh "$@"
else
command gh "$@"
fi
}
Reload your shell:
exec $SHELL
5. Authenticate Each Workspace
# In a project using personal workspace
cd ~/src/some-project
gh auth login # Authenticates personal
# In a project using work workspace
cd ~/src/other-project
gh auth login # Authenticates work (different from personal)
Folder names don't matter - the .mise.toml in each folder determines the workspace.
Daily Workflow
# In a project using personal workspace
cd ~/src/myapp
gh auth status
# [ghw] Using gh via ghw wrapper (GH_CONFIG_DIR: <your-home>/.config/gh-workspaces/personal)
# github.com
# ✓ Logged in to github.com account your-username (keyring)
# Switch to project using work workspace
cd ~/src/client-portal
gh auth status
# [ghw] Using gh via ghw wrapper (GH_CONFIG_DIR: <your-home>/.config/gh-workspaces/work)
# github.com
# ✓ Logged in to github.com account work-account (keyring)
# Outside any project
cd ~
gh auth status
# (no [ghw] message - regular gh)
Note: Folder names like myapp or client-portal are arbitrary. What matters is the .mise.toml inside each folder.
Safety: Strict Validation
The protection mechanism: If GH_CONFIG_DIR is set but workspace missing, ghw errors hard.
cd ~/src/myapp
export GH_CONFIG_DIR=<your-home>/.config/gh-workspaces/missing
gh auth status
# [ghw] Using gh via ghw wrapper (GH_CONFIG_DIR: <your-home>/.config/gh-workspaces/missing)
# ╭─────────────────────────────────── Error ────────────────────────────────────╮
# │ Workspace config missing at <your-home>/.config/gh-workspaces/missing. Run: │
# │ ghw workspace init missing │
# ╰──────────────────────────────────────────────────────────────────────────────╯
No fallback. No silent default. You always know what's happening.
Commands
# Quick setup (lazy way)
ghw init-here --workspace personal # Create .mise.toml for current project
# OR if git remote is set:
git remote add origin git@github.com:personal/repo.git
ghw init-here --auto # Auto-detect from git remote
# Workspace management
ghw workspace list # Show: client, personal, work, test
ghw workspace init new-client # Create new workspace
# Run gh with validation
ghw gh auth status # Explicit version
gh auth status # Via alias (same thing)
# Diagnostics
ghw doctor # Check setup and diagnose issues
ghw --version # Show version
How It Works
cd ~/src/myapp
↓
mise reads .mise.toml (contains GH_CONFIG_DIR=.../personal)
↓
exports GH_CONFIG_DIR=<your-home>/.config/gh-workspaces/personal
↓
gh auth status (alias)
↓
sees GH_CONFIG_DIR, calls ghw gh auth status
↓
ghw validates workspace exists
↓
runs the real gh (e.g. /opt/homebrew/bin/gh on macOS, /usr/bin/gh on Linux)
The folder name (myapp) is irrelevant. The .mise.toml inside determines the workspace.
File Locations
~/.config/gh-workspaces/ # Your workspaces
├── personal/
├── work/
└── ...
~/.bashrc or ~/.zshrc # Your gh() wrapper function lives here
~/src/*/ # Your projects with .mise.toml
Troubleshooting
Quick Diagnosis
Run ghw doctor to check your entire setup:
ghw doctor
This checks:
- ghw is installed correctly
- mise is installed and in shell
- gh is installed
- gh alias is loaded
- Workspaces exist
- GH_CONFIG_DIR detection
"Workspace config missing"
ghw workspace init <name>
"ghw command not found"
cd ~/src/gh-workspace-manager
uv tool install -e .
Alias not working
# Check if wrapper function loaded
type gh
# Should show "gh is a function", not the raw binary path
# (e.g. /opt/homebrew/bin/gh on macOS, /usr/bin/gh on Linux)
# Reload if needed
exec $SHELL
mise not setting GH_CONFIG_DIR
# Check mise is in shell
echo $SHELL
mise --version
# Check .mise.toml exists in project folder
cat ~/src/myapp/.mise.toml
# Force reload
cd . && cd ~/src/myapp
env | grep GH
Further Reading
- docs/guides/quickstart.md — condensed setup + daily workflow reference
- docs/architecture/design.md — component diagram, data flow, trade-offs, alternatives considered
Development
cd ~/src/gh-workspace-manager
# Run tests
uv run --group dev pytest tests/ -v
# Reinstall after changes
uv tool install -e .
# Test locally
ghw workspace list
Key Principles
- Per-folder only: .mise.toml in exact folder only, no inheritance
- Strict validation: Error if workspace missing, never fallback
- Reminder message: Always know when using ghw vs regular gh
- Cross-platform: pathlib, works on macOS/Linux/Windows
Questions
Why not just use GH_CONFIG_DIR manually? Easy to forget, easy to mess up. ghw adds validation and reminder.
Why mise instead of direnv? Faster (<1ms vs 20-50ms), cleaner config, unified with your other tools.
What if I delete a workspace folder? ghw will error immediately and tell you to recreate it.
Can I use this outside my src folder? Yes, anywhere. Just add .mise.toml with the workspace you want.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ghw-1.0.1.tar.gz.
File metadata
- Download URL: ghw-1.0.1.tar.gz
- Upload date:
- Size: 30.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcf12a6a1ae2ade4dc4e9fe67edf0da79dc0a2107f43cb15c11d8d2a558a1881
|
|
| MD5 |
112eebefe729dd25849f8981c9a07a3a
|
|
| BLAKE2b-256 |
4a8d40c6b3141dd082ea5a5a8a3cc0a5ea82905944a9237a1c19d7e4bf6fe661
|
File details
Details for the file ghw-1.0.1-py3-none-any.whl.
File metadata
- Download URL: ghw-1.0.1-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6e45b70c4d1dbc85b8742615ee02177bdb18ebfbfc14dfba02d3582dcbd3520
|
|
| MD5 |
1f806355bdb5b10e912c522644963091
|
|
| BLAKE2b-256 |
885d2893ebf1a072c3a2795dd29f27f30eb2e09a8298d8e84a6cbed854563076
|