Skip to content

feat: configurable plans directory and opt-out for plugin dependency installs - #49502

Open
log0u7 wants to merge 3 commits into
anomalyco:devfrom
log0u7:fix/opencode-pollution
Open

log0u7 wants to merge 3 commits into
anomalyco:devfrom
log0u7:fix/opencode-pollution

Conversation

@log0u7

@log0u7 log0u7 commented Sep 17, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #46189

Closes #27786

Closes #28174 (closed feature request for a configurable plans directory, implemented here)

Closes #30337 (closed startup-hang report; the root cause is removed because new projects no longer get a node_modules tree to scan)

Type of change

  • New feature
  • Bug fix
  • Refactor / code improvement
  • Documentation

What does this PR do?

Opening opencode in a git project and using plan mode creates <project>/.opencode/plans/. On the next start, that directory is picked up as a config directory and gets an automatic @opencode-ai/plugin dependency install, plus generated package manifest, lockfile and .gitignore files. Every project plan mode was used in ends up with its own copy, and ~/.config/opencode gets one too when it is a git repo. There is currently no way to opt out (details and code refs in #46189).

This PR adds three opt-outs/fixes, all default-preserving:

  • plans_directory config key (supports ~): plan files are written to the configured directory instead of the worktree/global defaults, e.g. the global data dir, so project trees stay untouched. The plan agent's built-in edit/external_directory allows were extended to the configured directory so plan mode keeps working.
  • OPENCODE_DISABLE_PLUGIN_DEPS=1 env flag: skips the per-directory dependency install and the generated files. Config discovery (agents, commands, plugins) is unaffected.
  • XDG relocation of dependency installs ([Bug]: XDG Base Directory Spec violation — node_modules installed in ~/.config instead of ~/.local/share #27786): installs now target a per-directory store under ~/.local/share/opencode/deps/<hash>/ (package manifest, lockfile, node_modules), and each config directory only gets a node_modules symlink pointing there. Bare import "@opencode-ai/plugin" from local plugin files keeps resolving through parent-directory traversal, while the dependency mass leaves ~/.config and project trees. Installs fall back to the previous in-place behavior when symlinks are unavailable (e.g. unprivileged Windows) or when a real node_modules directory already exists in the config dir, so existing setups keep working untouched.
  • Conditional install: the dependency install only runs for config directories that actually have plugins (declared in their opencode.json or discovered under plugin(s)/). Plugin-less directories keep just the generated .gitignore, so opening opencode in a project without plugins writes nothing but that one file.
  • Plan files start with a Project: <path> first line listing the project root path(s) they belong to, so a shared plans_directory stays navigable when several projects use it.

Default behavior is unchanged when neither plans_directory nor the env flag is set, except that new installs land in the XDG data dir instead of the config dirs.

How did you verify your code works?

  • Unit tests for Session.plan(): default paths (git / non-git), plans_directory override (absolute, ~, bare ~, relative)
  • Config loader tests: symlink target under ~/.local/share/opencode/deps/<hash>, OPENCODE_DISABLE_PLUGIN_DEPS writing nothing, existing real node_modules dirs left untouched
  • bun run typecheck clean; bun test test/config/config.test.ts 110/110 and bun test test/session/plan.test.ts 7/7 on bun 1.3.14
  • Manual e2e with the fork build in a throwaway git repo: plan file lands in the configured directory, no .opencode directory is created in the project

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Supersedes #46199 (auto-closed by the compliance bot after a body edit broke the template section header; same branch, same commits).

log0u7 and others added 2 commits August 29, 2026 22:36
…installs

Plan files were hardcoded to <worktree>/.opencode/plans for git projects,
and every discovered .opencode config directory got an automatic
@opencode-ai/plugin dependency install plus generated package manifest,
lockfile and .gitignore files. This pollutes every project plan mode
is used in, with no way to opt out.

- add plans_directory config key to relocate plan files (supports ~)
- add OPENCODE_DISABLE_PLUGIN_DEPS=1 to skip the per-directory
  dependency install and generated files
- extend the plan agent built-in edit/external_directory permissions
  to cover the configured plans directory

Refs anomalyco#46189
Per-directory dependency installs used to write package manifest, lockfile
and node_modules directly into config directories (~/.config/opencode and
every project .opencode), violating the XDG base directory spec (anomalyco#27786)
and polluting project trees.

Installs now target a per-directory store under
~/.local/share/opencode/deps/<hash>/, and config dirs only get a
node_modules symlink pointing there so bare imports from local plugins
keep resolving through parent-directory traversal. Installs fall back to
the config dir when symlinks are unavailable (e.g. unprivileged Windows)
or when a real node_modules directory already exists there.

Also documents plans_directory, OPENCODE_DISABLE_PLUGIN_DEPS and the new
install location in the website docs.

Refs anomalyco#46189, closes anomalyco#27786
…lugins

The per-directory dependency install used to run for every config
directory unconditionally, so plugin-less projects and state
directories still got a node_modules symlink and an XDG store entry.

The install now only runs for directories that actually have plugins,
either declared in their opencode.json or auto-discovered under
plugin(s)/. Plugin-less directories keep just the generated
.gitignore.

Plan files also start with a "Project: <path>" first line listing the
project root(s) they belong to, so a shared plans_directory stays
navigable when several projects write plans to the same directory.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment