This guide configures your shell to automatically sync ~/.config/opencode from your remote repository while preserving local customizations.
When you type opencode:
- Preserves local
AGENTS.mdandopencode.json - Fetches remote changes and merges them (appends new content to existing files)
- Restores your local
AGENTS.mdandopencode.json - Launches OpenCode in your current working directory
- OpenCode installed and accessible in your PATH
- Git configured with access to
https://github.com/joaomj/opencode.git ~/.config/opencodedirectory exists
Run this command to see which shell you're using:
echo $SHELL- If output contains
bash→ proceed with.bashrc - If output contains
zsh→ proceed with.zshrc
For Linux (Ubuntu/Debian):
nano ~/.bashrcFor macOS:
nano ~/.zshrcOr use your preferred text editor (vim, code, etc.)
Add this function to the end of your configuration file:
# OpenCode with auto-update from remote repository
opencode() {
(
cd "$HOME/.config/opencode" 2>/dev/null || exit 0
PRESERVED_FILES="AGENTS.md opencode.json"
for file in $PRESERVED_FILES; do
if [ -f "$file" ]; then
cp "$file" "$file.local.bak"
fi
done
echo "[OpenCode Sync] Fetching remote changes..."
git fetch origin master 2>/dev/null || echo "[OpenCode Sync] Warning: Could not fetch from remote"
for remote_file in $(git ls-tree -r --name-only origin/master); do
if echo "$PRESERVED_FILES" | grep -qw "$remote_file"; then
continue
fi
local_file="./${remote_file}"
if [ -f "$local_file" ]; then
remote_content=$(git show "origin/master:${remote_file}" 2>/dev/null)
if [ -n "$remote_content" ]; then
printf '\n\n' >> "$local_file"
printf '%s\n' "$remote_content" >> "$local_file"
fi
else
mkdir -p "$(dirname "$local_file")"
git checkout "origin/master" -- "$remote_file" 2>/dev/null
fi
done
for file in $PRESERVED_FILES; do
if [ -f "$file.local.bak" ]; then
mv "$file.local.bak" "$file"
echo "[OpenCode Sync] $file preserved"
fi
done
)
echo "[OpenCode Sync] Starting OpenCode..."
command opencode "$@"
}Make sure OpenCode binary is accessible. Add this line before the function if needed:
export PATH="$HOME/.opencode/bin:$PATH"Platform-specific paths:
| OS | Typical OpenCode Path |
|---|---|
| Linux | $HOME/.opencode/bin |
| macOS (Homebrew) | /opt/homebrew/bin or /usr/local/bin |
| macOS (direct install) | $HOME/.opencode/bin |
Save the file (in nano: Ctrl+O, Enter, Ctrl+X), then reload:
# For Linux (Bash)
source ~/.bashrc
# For macOS (Zsh)
source ~/.zshrcOr simply open a new terminal window.
Test that the wrapper is active:
type opencodeExpected output:
opencode is a function
opencode ()
{
( cd "$HOME/.config/opencode" 2> /dev/null || exit 0;
PRESERVED_FILES="AGENTS.md opencode.json";
for file in $PRESERVED_FILES; do
if [ -f "$file" ]; then
cp "$file" "$file.local.bak";
fi;
done;
echo "[OpenCode Sync] Fetching remote changes...";
git fetch origin master 2> /dev/null || echo "[OpenCode Sync] Warning: Could not fetch from remote";
for remote_file in $(git ls-tree -r --name-only origin/master); do
if echo "$PRESERVED_FILES" | grep -qw "$remote_file"; then
continue;
fi;
local_file="./${remote_file}";
if [ -f "$local_file" ]; then
remote_content=$(git show "origin/master:${remote_file}" 2>/dev/null);
if [ -n "$remote_content" ]; then
printf '\n\n' >> "$local_file";
printf '%s\n' "$remote_content" >> "$local_file";
fi;
else
mkdir -p "$(dirname "$local_file")";
git checkout "origin/master" -- "$remote_file" 2>/dev/null;
fi;
done;
for file in $PRESERVED_FILES; do
if [ -f "$file.local.bak" ]; then
mv "$file.local.bak" "$file";
echo "[OpenCode Sync] $file preserved";
fi;
done );
echo "[OpenCode Sync] Starting OpenCode...";
command opencode "$@"
}
Run OpenCode from any directory:
opencodeYou should see:
[OpenCode Sync] Fetching remote changes...
[OpenCode Sync] AGENTS.md preserved
[OpenCode Sync] opencode.json preserved
[OpenCode Sync] Starting OpenCode...
If you don't have a local opencode.json, you'll only see:
[OpenCode Sync] Fetching remote changes...
[OpenCode Sync] AGENTS.md preserved
[OpenCode Sync] Starting OpenCode...
Then OpenCode starts in your current directory (not in ~/.config/opencode).
- Uses
~/.bashrcby default - Git is usually pre-installed
- No special considerations
- Modern macOS uses Zsh by default (
~/.zshrc) - If you installed OpenCode via Homebrew, the path might differ:
which opencode # Output: /opt/homebrew/bin/opencode - If using older macOS (< 10.15), you might be using Bash (
~/.bash_profileinstead of~/.bashrc)
- Subshell isolation: The parentheses
(...)create a subshell, socddoesn't affect your current directory - Local backup: Backs up
AGENTS.mdandopencode.jsonto.local.bakfiles - Silent failures:
2>/dev/nullsuppresses error output for cleaner startup - Merge strategy: For existing files, appends remote content; for new files, checks them out
- Preserve local: Restores backed-up
AGENTS.mdandopencode.jsonafter merge - Preserves working directory: OpenCode launches from where you invoked it
✅ AGENTS.md preserved: Your local AGENTS.md is backed up and restored after sync.
✅ opencode.json preserved: Your local opencode.json is backed up and restored after sync.
To remove the auto-update behavior and use plain OpenCode:
command opencode-
Open your shell config:
# Linux nano ~/.bashrc # macOS nano ~/.zshrc
-
Find and delete the
opencode()function (lines starting withopencode() {through the closing}) -
Save and reload:
source ~/.bashrc # or source ~/.zshrc
The wrapper isn't loaded. Check:
- Did you save the file?
- Did you run
sourceon the correct file? - Are you editing the right config file for your shell?
- Check internet connection
- Verify you have access to
https://github.com/joaomj/opencode.git - Ensure
~/.config/opencodeis a valid git repository with remote set:cd ~/.config/opencode git remote -v
The subshell isolation isn't working. Check that your function uses parentheses (...) not braces {...} for the cd section.
Edit the function and replace origin master with your remote and branch:
git fetch <remote-name> <branch-name>To see detailed git output, remove the 2>/dev/null redirects:
opencode() {
(
cd "$HOME/.config/opencode" || exit 0
PRESERVED_FILES="AGENTS.md opencode.json"
for file in $PRESERVED_FILES; do
if [ -f "$file" ]; then
cp "$file" "$file.local.bak"
fi
done
echo "[OpenCode Sync] Fetching remote changes..."
git fetch origin master || echo "Warning: fetch failed"
for remote_file in $(git ls-tree -r --name-only origin/master); do
if echo "$PRESERVED_FILES" | grep -qw "$remote_file"; then
continue
fi
local_file="./${remote_file}"
if [ -f "$local_file" ]; then
remote_content=$(git show "origin/master:${remote_file}" 2>/dev/null)
if [ -n "$remote_content" ]; then
printf '\n\n' >> "$local_file"
printf '%s\n' "$remote_content" >> "$local_file"
fi
else
mkdir -p "$(dirname "$local_file")"
git checkout "origin/master" -- "$remote_file"
fi
done
for file in $PRESERVED_FILES; do
if [ -f "$file.local.bak" ]; then
mv "$file.local.bak" "$file"
echo "[OpenCode Sync] $file preserved"
fi
done
)
echo "[OpenCode Sync] Starting OpenCode..."
command opencode "$@"
}To preserve additional files, edit the PRESERVED_FILES variable:
PRESERVED_FILES="AGENTS.md opencode.json custom-config.yml secrets.json"Tested on: Ubuntu 24.04 LTS, macOS Tahoe