opencode-workspace-env
v0.1.2
Published
OpenCode plugin for per-workspace env injection via shell.env hook
Maintainers
Readme
opencode-workspace-env
Per-workspace environment injection for OpenCode.
opencode-workspace-env is an OpenCode plugin that injects per-workspace env vars into every shell execution via the shell.env hook. It lets one OpenCode server work across multiple repos, each with its own direnv or nix environment.
What This Does
OpenCode agents often need different toolchains per workspace — different Node, Python, or system packages. This plugin resolves the nearest env source from the current working directory, loads env vars, and injects them into the shell command that is about to run.
Two env source paths are supported:
.envrc(primary) — runsdirenv export json. The.envrccan contain anything direnv supports (use flake,layout python, plain exports, etc.).flake.nix(fallback) — runsnix print-dev-env --jsondirectly. No direnv needed.
Agent runs shell command
→ plugin resolves env source from cwd (bounded by git root)
→ .envrc found? → direnv export json
→ no .envrc, flake.nix found? → nix print-dev-env --json
→ result cached by source file + flake.lock fingerprint
→ shell.env injects output.env
→ command runs with workspace-specific PATH and env varsInstall
npm install opencode-workspace-envAdd it to opencode.json:
{
"plugin": ["opencode-workspace-env"]
}Prerequisites:
- direnv — Required for the
.envrcpath. Must be installed globally on the host, not inside the devShell. - nix — Required for the
flake.nixfallback path. Also needed if your.envrcusesuse flake.
Usage
With .envrc (recommended)
# in repo root
printf 'use flake\n' > .envrc
direnv allowWith flake.nix only (no direnv needed)
# just have a flake.nix with devShells.default — plugin detects it automatically
git add flake.nixWith the plugin enabled, any OpenCode shell command run inside that repo gets the exported environment for that workspace. Resolution walks up from cwd and stops at the git root, so a parent directory outside the repo is never used.
Architecture
src/
├── index.ts # Plugin entry. shell.env hook, dispatches envrc vs flake
├── resolve.ts # cwd → ResolvedEnvSource (.envrc first, flake.nix fallback)
├── direnv.ts # `direnv export json` → EnvExportResult
├── nix.ts # `nix print-dev-env --json` → EnvExportResult
├── filter.ts # Shared env key filter (DIRENV_*, NIX_BUILD_*, nix internals)
└── cache.ts # In-memory cache keyed by source path + SHA-256 fingerprint (max 50 entries, FIFO eviction)- Writes only to
output.env, neverprocess.env - Caches successful exports only — failed results are retried on next call
- Fails silent when no env source found or tooling unavailable
- Invalidates cache when source file or
flake.lockchanges - Filters nix build internals (
stdenv,builder,phases, etc.) from both direnv and nix outputs
Limitations
- Cache fingerprint tracks source file +
flake.lock, not files sourced by.envrc flake.nixmust begit added for nix to see itdirenvmust be globally installed, not inside the devShellnix print-dev-envcan be slow on first eval (~10s+), cached after- In-memory cache holds up to 50 workspaces; oldest entries are evicted first (FIFO)
License
MIT
