# Live end-to-end tests (opencode 2.0.15) `tests/e2e/` drives the **real** opencode 2.0.15 CLI against the plugin, with real model calls. These tests are opt-in: they cost money (about $0.20 per full run) and take about 2 minutes. ```sh OPENCODE_E2E=1 npx bun test tests/e2e --timeout 600000 # everything (OPENAI_API_KEY must be set) OPENCODE_E2E=1 npx bun test tests/e2e/stop.test.ts --timeout 600000 npx bun test tests/e2e/harness.test.ts # offline harness tests, always run ``` Without `OPENCODE_E2E=1` (or without `OPENAI_API_KEY`), the live suites are skipped. Only the offline `harness.test.ts` runs. The opt-in exists because a bare `bun test` at the repo root would otherwise pick these files up and spend money. Optional env: `OPENCODE_E2E_MODEL` sets the parent model (default `openai/gpt-5.4-mini`). With a free `opencode/*` model (for example `opencode/space-bunny-free` or `opencode/nemotron-3-ultra-free`; children default to a free model too) no provider key is used, but `OPENAI_API_KEY` must still be set to enable the suites (`OPENAI_API_KEY=unused`). `OPENCODE_E2E_BIN` sets the CLI binary. ## How the harness works (`tests/e2e/harness.ts`) - **Isolation.** Every process gets `XDG_DATA_HOME/CONFIG/STATE/CACHE` under `.sandbox/e2e-*`, so your real opencode data is never touched. Run data (transcript dirs) ends up in `.sandbox/e2e-data/opencode/workflows///`. Worktrees end up in `.sandbox/e2e-data/opencode/worktree/`. It also sets `OPENCODE_TEST_HOME=.sandbox`: opencode loads every `AGENTS.md` from the project up to the home directory (or to the project root when the project is outside home), so a sandbox inside this repo would otherwise give the live models this repo's contributor `AGENTS.md`. With the home moved to `.sandbox`, the walk stops there. Never put an `AGENTS.md` in `.sandbox/` itself. - **Project.** `createProject(name, files)` makes a fresh `git init` repo under `.sandbox/e2e--`. The plugin is loaded from `.opencode/plugins/workflows.js`, which contains one line: `export { default } from "/src/index.ts"`. The loader is **committed**, so worktrees created by `isolation:'worktree'` load the plugin too (tools are registered per location; see OPENCODE-API-NOTES.md). - **Long-lived server.** `startServer()` spawns `opencode serve --port 0 --hostname 127.0.0.1` with `OPENCODE_PASSWORD` set, then parses `server listening on ` from its output. The prompts are sent with `opencode run --server --auto --format json -m [--session id]`. The server log is written to `.sandbox/e2e-serve-