fix(opencode): honor the user's own opencode config - #387
Conversation
ucode exported XDG_CONFIG_HOME to send opencode to its own directory. That removed all of ~/.config/opencode from opencode's load path. Thus the user's permission rules, MCP servers, disabled_providers, global skills, agents, commands, plugins, tui.json and global AGENTS.md had no effect in a ucode session. Name ucode's file with OPENCODE_CONFIG in place of the redirect. OPENCODE_CONFIG is a config layer above the user's global config, and opencode merges the layers. Objects merge one key at a time and the later scalar wins. Thus ucode keeps control of `model` and `provider`, and the user keeps everything else. ucode still writes to its own file only. The config file path does not change, so MCP servers that `ucode mcp add` registered survive the upgrade.
There was a problem hiding this comment.
Pull request overview
This PR updates the OpenCode agent integration so ucode opencode no longer hides the developer’s existing OpenCode config under ~/.config/opencode/. Instead of redirecting XDG_CONFIG_HOME, ucode now points OpenCode at ucode’s generated config via OPENCODE_CONFIG, allowing OpenCode to merge configs as intended while keeping ucode’s config written under ~/.ucode/.
Changes:
- Stop exporting
XDG_CONFIG_HOMEfor OpenCode; setOPENCODE_CONFIGto ucode’s generated config file instead. - Update e2e/unit tests to avoid reading the developer’s real
~/.config/opencodeby settingXDG_CONFIG_HOMEto a test-only empty location. - Document the OpenCode managed file path as a layering config in the README.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/ucode/agents/opencode.py |
Switch runtime env construction from XDG_CONFIG_HOME redirection to OPENCODE_CONFIG layering. |
tests/test_agent_opencode.py |
Adjust unit tests to assert OPENCODE_CONFIG is used and XDG_CONFIG_HOME is not overridden. |
tests/test_e2e.py |
Update OpenCode e2e launches to keep tests hermetic now that XDG_CONFIG_HOME isn’t redirected by ucode. |
tests/test_e2e_user_agent.py |
Update OpenCode user-agent e2e test env to use OPENCODE_CONFIG plus an empty XDG_CONFIG_HOME. |
README.md |
Update managed-local-files table to reflect OpenCode’s config layering behavior and ucode-managed path. |
Suppressed comments (1)
tests/test_e2e.py:872
- Same hermeticity concern here: XDG_CONFIG_HOME is pointed at tmp_path/empty-xdg but the directory isn’t created, which can allow fallbacks to the developer’s real config depending on opencode’s lookup behavior.
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "empty-xdg"))
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The single test asserted only that build_runtime_env adds no XDG_CONFIG_HOME when the variable is absent. A reintroduced redirect that overwrites a value the user already set would have passed. Split the case in two so the pass-through is asserted with a sentinel.
The old test restated the module constants and over-reached by asserting ~/.config is not a parent. Pin the literal path instead: a rename orphans the MCP servers that ucode mcp add wrote there. Rewrite two comments to state the constraint, not the history or the design rationale.
|
@rohita5l @AarushiShah-db @lilly-luo @Edwinhe03 this is ready for review. The one-line fix swaps |
Fixes #391.
Before this,
ucode opencodeignored your~/.config/opencode/. Now it honors it.The fix
One line, in
build_runtime_env:The two variables answer different questions.
XDG_CONFIG_HOMEanswers "where isthe config folder?".
OPENCODE_CONFIGanswers "which extra config file should Ialso read?".
ucode set the first one to its own folder. OpenCode then appended
opencodetothat folder and read from there, so
~/.config/opencode/was not a configlocation at all. The user's permissions, MCP servers,
disabled_providers,skills, agents, plugins and global
AGENTS.mdall disappeared.OPENCODE_CONFIGnames one file instead. ucode leavesXDG_CONFIG_HOMEalone,so OpenCode still reads the user's folder and merges ucode's file on top.
Before and after
Before: ucode replaced the config location. Your config was invisible.
After: ucode adds one file at slot 3. Both are read and merged. ucode
outranks your global config, and a project config still outranks ucode.
Where slot 3 is
OpenCode has eight config sources. A later source overrides an earlier one:
~/.config/opencode/opencode.jsonOPENCODE_CONFIGopencode.jsonin the repo.opencode/directories"Overrides" means the later source wins a conflict. It does not replace the file.
A scalar from the higher layer wins, so ucode keeps
model. Objects merge key bykey, so the user's MCP servers and ucode's both survive. Arrays are replaced
whole, which is why ucode writes no top-level array — one would wipe the user's
disabled_providers.ucode still writes only its own file, and the path is unchanged, so servers from
ucode mcp addsurvive.Verification
opencode debug configbefore the change shows only ucode's keys. After thechange it shows the user's
permission,disabled_providersand MCP serversmerged with ucode's
model,providerand MCP server. A launcheducode opencode runstill reaches the gateway and returns a normal reply.Tests
uv run --frozen pytest: 1989 passed, 41 skipped.ruff check .: clean.Three new tests cover the swap: ucode names its own file, it passes an existing
XDG_CONFIG_HOMEthrough unchanged, and it never adds that variable itself.