A POSIX shell script for switching between multiple opencode authentication accounts on the same provider — without manually editing auth.json every time.
opencode stores your login credentials in a single file:
~/.local/share/opencode/auth.json
To switch accounts you currently have to: quit opencode → edit auth.json → reopen opencode. This script automates that by maintaining named profile snapshots of auth.json alongside the live file.
~/.local/share/opencode/
├── auth.json ← live file opencode reads
├── current_profile.txt ← tracks which profile is active (managed by the script)
├── auth-work.json ← example saved profile "work"
├── auth-personal.json ← example saved profile "personal"
└── auth-client-acme.json ← example saved profile "client-acme"
Profile names may only contain letters, numbers, hyphens, and underscores (e.g. work, personal, client-acme).
| Function | Purpose |
|---|---|
get_paths |
Sets the base directory (~/.local/share/opencode by default, or $OPENCODE_PROFILE_BASE_DIR) and derives all file paths from it |
ensure_base_dir |
Creates the base directory if it doesn't exist yet |
load_profiles |
Scans for auth-*.json files and builds a sorted list of profile names |
get_current_status |
Reads current_profile.txt to report which profile is active, and cross-checks that the corresponding auth-<name>.json file still exists |
validate_profile_name |
Rejects empty names or names with special characters (spaces, dots, slashes, etc.) |
switch_to_profile |
Copies auth-<name>.json → auth.json and records the name in current_profile.txt. Also warns if opencode is currently running |
save_current_to_profile |
Copies auth.json → auth-<name>.json and records the name in current_profile.txt |
interactive_menu |
Presents the numbered menu when no CLI arguments are given |
main |
Entry point — routes to interactive mode or a direct CLI subcommand |
- ✅ No network access — the script never contacts any server.
- ✅ No elevated privileges — it only reads and writes files inside your home directory.
- ✅ No package dependencies — it is pure POSIX
sh; it works on macOS (zsh/dash/bash), Linux, and BSD out of the box. - ✅ Non-destructive saves — saving a profile copies
auth.json; it does not delete or truncate anything. - ✅ Overwrite guard — the script asks for confirmation before overwriting an existing profile.
- ✅ opencode running check — if
opencodeis detected as a running process, the script warns you to close it before switching (opencode readsauth.jsonon launch, so switching while it is open has no effect). ⚠️ auth.json contains credentials — the profile files hold the same sensitive data asauth.json. The script stores them in~/.local/share/opencode/(mode 700 by default on macOS). If you want extra protection, see Security Hardening below.
Save the script anywhere on your $PATH. A good location on macOS:
# Create a personal bin directory if you don't have one
mkdir -p ~/.local/bin
# Copy the script there
cp oc-profiles.sh ~/.local/bin/oc-profiles
chmod +x ~/.local/bin/oc-profilesMake sure ~/.local/bin is in your PATH. Add this to your ~/.zshrc (or ~/.bash_profile) if it isn't already:
export PATH="$HOME/.local/bin:$PATH"Then reload your shell:
source ~/.zshrc # or: source ~/.bash_profileoc-profiles --helpRun with no arguments to get the numbered menu:
oc-profilesYou will see something like:
=== OpenCode Profile Switcher ===
Base directory : /Users/you/.local/share/opencode
Current profile: work
1) Switch to a profile
2) Save current auth.json to a profile
3) List all profiles
q) Quit
Choose an action [1-3, q]:
oc-profiles save work
oc-profiles save personal
oc-profiles save client-acmeDo this once per account after logging in through opencode normally. You only need to do it once per account — from then on the script can switch between them instantly.
Always quit opencode first, then switch, then reopen opencode.
oc-profiles switch personaloc-profiles listOutput:
Current profile: work
Available profiles:
* work (active)
personal
client-acme
oc-profiles current# Step 1 — Log in to your first account via opencode normally, then save it
oc-profiles save work
# Step 2 — Log out of that account in opencode and log in to your second account
# (or manually replace auth.json with credentials for the second account)
oc-profiles save personal
# Step 3 — From now on, to switch accounts:
# a) Quit opencode
# b) Run:
oc-profiles switch personal
# c) Reopen opencode — it will use the personal accountThe profile files contain the same credentials as auth.json. If you want to make them harder to read by other processes or users on the same machine:
# Lock down the opencode directory to your user only
chmod 700 ~/.local/share/opencode
# Lock down each profile file
chmod 600 ~/.local/share/opencode/auth-*.jsonIf you store opencode data elsewhere, override the path:
OPENCODE_PROFILE_BASE_DIR="/Volumes/EncryptedDrive/opencode" oc-profiles listYou can make this permanent by adding to your shell config:
export OPENCODE_PROFILE_BASE_DIR="/Volumes/EncryptedDrive/opencode"| Symptom | Fix |
|---|---|
Profile not found: 'xyz' |
Run opencode-profiles list to see available profile names (case-sensitive) |
No auth.json found |
Log in via opencode first so it creates an auth.json, then save it as a profile |
| Switched profile but opencode still shows the old account | You switched while opencode was running — quit it, switch, then reopen |
current_profile.txt says a profile name but the file is missing |
The profile file was deleted manually; save it again with opencode-profiles save <name> |
| Permission denied writing to the directory | Check that you own ~/.local/share/opencode (ls -la ~/.local/share/) |
# Remove the script
rm ~/.local/bin/oc-profiles
# Optionally remove the profile files (keeps auth.json intact)
rm ~/.local/share/opencode/auth-*.json
rm ~/.local/share/opencode/current_profile.txtoc-profiles # interactive menu
oc-profiles save <name> # save current auth.json as a profile
oc-profiles switch <name> # switch to a saved profile
oc-profiles list # list all profiles + current
oc-profiles current # print current profile name only
oc-profiles --help # show usage
Thanks for extending the original gist (and documenting it). Was planning on doing this myself so this saves me time 🙏