Repository navigation
Description
Description
Outside a Git repository, OpenCode walks up from the cwd all the way to the filesystem root (/) and merges every opencode.json / opencode.jsonc it finds — so a forgotten ~/opencode.json silently overrides the global config for every non-Git directory below it (in my case it swapped provider credentials → misleading 401 Unauthorized with a valid key), while the docs claim the walk only "traverses up to the nearest Git directory".
Repro (installs latest opencode into a throwaway sandbox; nothing touches your real config; verified on 1.19.3 = current @latest, and 1.14.48):
#!/usr/bin/env bash
set -uo pipefail
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
if [ -n "${OPENCODE_BIN:-}" ]; then
OPENCODE="$OPENCODE_BIN"
else
echo ">> installing opencode-ai@${OPENCODE_VERSION:-latest} into sandbox ..."
npm install --silent --prefix "$TMP/pkg" "opencode-ai@${OPENCODE_VERSION:-latest}" \
|| { echo "npm install failed (npm + network required; or use OPENCODE_BIN)"; exit 1; }
OPENCODE="$TMP/pkg/node_modules/.bin/opencode"
fi
"$OPENCODE" --version
# Isolate ALL state so the tested binary cannot read/migrate the real global config.
export XDG_CONFIG_HOME="$TMP/xdg/config" XDG_DATA_HOME="$TMP/xdg/data" XDG_CACHE_HOME="$TMP/xdg/cache"
export OPENCODE_DISABLE_AUTOUPDATE=1 OPENCODE_DISABLE_MODELS_FETCH=1
mkdir -p "$TMP/tree/sub"
printf '%s\n' '{ "provider": { "openai": { "options": { "apiKey": "sk-global-correct", "baseURL": "https://global-correct.invalid/v1" } } } }' > "$TMP/global.json"
printf '%s\n' '{ "provider": { "openai": { "options": { "apiKey": "sk-ancestor-wrong", "baseURL": "https://ancestor-wrong.invalid/v1" } } } }' > "$TMP/tree/opencode.json"
cd "$TMP/tree/sub"
export OPENCODE_CONFIG="$TMP/global.json" # acts as the "global config" layer (loaded below project configs)
winner() { "$OPENCODE" debug config 2>/dev/null | grep -oE '(ancestor-wrong|global-correct)' | head -1 || true; }
echo "case 1 (cwd NOT in a Git repo): $(winner)"
git init -q .
echo "case 2 (cwd inside a Git repo): $(winner)"outputs:
[hehe@localhost test]$ OPENCODE_VERSION=1.19.3 bash opencode-config-traversal-repro.sh
>> installing [email protected] into sandbox ...
(node:104225) [DEP0060] DeprecationWarning: The `util._extend` API is deprecated. Please use Object.assign() instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
[..................] / rollbackFailedOptional: verb npm-session 2f97cd0790509e9a
[..................] / rollbackFailedOptional: verb npm-session 2f97cd0790509e9a
(node:104225) [DEP0176] DeprecationWarning: fs.F_OK is deprecated, use fs.constants.F_OK instead
+ [email protected]
added 5 packages in 43.019s
1.19.3
case 1 (cwd NOT in a Git repo): ancestor-wrong
case 2 (cwd inside a Git repo): global-correct
ancestor-wrong = ancestor-directory opencode.json overrode the global config (BUG)
global-correct = ancestor config was ignored (behavior the docs describe)
[hehe@localhost test]$
[hehe@localhost test]$
[hehe@localhost test]$ OPENCODE_BIN=$(which opencode) bash opencode-config-traversal-repro.sh
1.14.48
case 1 (cwd NOT in a Git repo): ancestor-wrong
case 2 (cwd inside a Git repo): global-correct
ancestor-wrong = ancestor-directory opencode.json overrode the global config (BUG)
global-correct = ancestor config was ignored (behavior the docs describe)
(The marker is baseURL because newer versions redact apiKey to "***" in debug config; the override mechanism is the same.)
Workaround: OPENCODE_DISABLE_PROJECT_CONFIG=1, or audit ancestor directories (especially $HOME) for stray opencode.json.
Plugins
No response
OpenCode version
1.19.3 & 1.14.48
Steps to reproduce
No response
Screenshot
No response
Operating System
CentOS Linux release 8.4.2105
Terminal
No response
Activity
opencode-agent commentedon Oct 22, 2026
Thanks for the detailed report and the self-contained repro script!
You're running OpenCode v1 (1.19.3 and 1.14.48). v1 now only gets fixes for critical bugs (data loss, security problems, or crashes or breakage with no workaround), so this is unlikely to be fixed there. You've already found the workarounds:
OPENCODE_DISABLE_PROJECT_CONFIG=1, or removing the stray ancestoropencode.json.We encourage upgrading to v2 (npm package
@opencode/cli,opencodecommand). In v2, walking up through every ancestor directory is intentional, and it happens inside Git repos too, not only outside them. The v2 docs were updated to say so (#45681). In v2 the global config directory is not picked up again by that walk, but anopencode.jsonplaced directly in an ancestor such as~still applies as project config. A stray~/opencode.jsonshould therefore be removed, or moved into the global config directory if that's what you meant it to be.Related:
..loads project config from the un-normalized path: another directory'sopencode.json(and its permissions) applies #55909: v2 report about project config being loaded from an unexpected directoryIf you think this is critical, or you see unexpected behaviour on v2, please reply here with the details.
opencode-agent commentedon Oct 23, 2026
Closing this as not planned. It was reported on OpenCode v1 (1.19.3 / 1.14.48), which only gets critical fixes, and you have workarounds:
OPENCODE_DISABLE_PROJECT_CONFIG=1, or removing the stray ancestoropencode.json. We waited a day to hear whether this is critical for you or also happens on v2, and there was no reply.In v2, project config discovery walks every ancestor directory up to the filesystem root, inside and outside Git repos, and the v2 docs say so (#45681). If you see unexpected config behaviour on v2, please open a new issue with the version and the steps to reproduce. Thanks again for the detailed repro script!