Skip to content

refactor(core): resolve database and websearch config through Effect Config - #34846

Closed
kitlangton wants to merge 3 commits into
devfrom
config-ownership
Closed

kitlangton wants to merge 3 commits into
devfrom
config-ownership

Conversation

@kitlangton

@kitlangton kitlangton commented Jul 2, 2026 •

Copy link
Copy Markdown
Contributor

First slice of moving core runtime config off import-time process.env snapshots and onto Effect Config, with config ownership distributed to the services that consume it. ConfigProvider becomes the single test seam.

What changed

WebSearch (packages/core/src/tool/websearch.ts)

  • defaultConfigLayer decodes one Config.all({...}) when the layer is built, instead of reading process.env directly at module scope.
  • Parsing deliberately keeps the legacy lenient grammar via a shared truthyConfig helper (truthy's case-insensitive true/1, missing or malformed → false). This layer builds at Location boot, where a strict-decode defect would surface as opaque session failures; OPENCODE_EXPERIMENTAL=TRUE keeps meaning enabled. An invalid OPENCODE_WEBSEARCH_PROVIDER logs a warning and is ignored, matching the old behavior.

Flag (packages/core/src/flag/flag.ts)

  • One truthiness grammar, two readers: truthy(name) reads the environment at call time, truthyConfig(name) reads the same grammar through Effect Config so layer builds can be steered by a ConfigProvider.
  • OPENCODE_DB is removed from the Flag snapshot; database config now lives in the database module.

Database (packages/core/src/database/database.ts)

  • Placement was baked at module import (layerFromPath(path()) evaluated on import, reading the Flag env snapshot). There is now exactly one public placement value: Database.configuredPath, an Effect that resolves OPENCODE_DB / OPENCODE_DISABLE_CHANNEL_DB through Effect Config. The node layer is Layer.unwrap(Effect.map(configuredPath, layerFromPath)), built per runtime instead of per import.
  • Database.path() is deleted rather than kept as a V1 compat shim. Its V1 consumers were already Effect-shaped, so they now yield configuredPath directly: opencode db / opencode db path (packages/opencode/src/cli/cmd/db.ts) and the resetDatabase test fixture (packages/opencode/test/fixture/db.ts). This removes the last skew surface — previously path() read the live environment while the layer read the frozen first-use snapshot, so late env mutation could make opencode db path disagree with the running app. Now every consumer resolves through the same Config read.

Tests

  • New packages/core/test/database-path.test.ts exercises configuredPath through ConfigProvider.fromUnknown (explicit :memory:, absolute, relative, channel-default cases) and proves the layer seam: the preload sets OPENCODE_DB=":memory:" in the environment, and the test shows a provider override wins at layer build.
  • tool-websearch.test.ts gains decoding tests driven entirely by ConfigProvider.fromUnknown — including regression cases for the lenient grammar (TRUE enables, banana disables, invalid provider ignored).
  • sdk-next/test/embedded.test.ts previously mutated Flag.OPENCODE_DB per test and relied on dynamic import ordering. That was already broken on dev locally: the path baked at first import, test 1 deleted its directory in finally, and the remaining 3 tests failed with SQLITE_CANTOPEN. Since the default ConfigProvider.fromEnv() snapshots the process environment on first use, placement is process-wide; the file now points all embedded hosts at one shared temp database up front and cleans it in afterAll. All 4 tests pass now (previously 1/4 locally).
  • httpapi-exercise/environment.ts drops the now-redundant Flag.OPENCODE_DB mutation and documents the must-run-before-first-Config-read ordering contract.

Design notes

  • Deliberately not a central RuntimeConfig/Flag service: config values are inputs owned by their consuming services, read once at layer build. Flag shrinks by attrition as remaining keys migrate (OPENCODE_MODELS_*, OTLP, etc. are follow-ups).
  • Lenient vs strict parsing was reviewed explicitly: strict Config.boolean would have turned 7 previously-tolerated env values (including uppercase TRUE) into startup/Location-boot defects. Strictness may be worth revisiting per-variable, but as an explicit decision — not a side effect of the migration.
  • Config.schema(...) was evaluated for these call sites and skipped: it shines when reusing an existing domain schema with strict failure semantics, but both call sites here need the lenient legacy grammar (and the provider field needs warn-and-ignore, which Config.option can't express since it only swallows missing data). Good candidates for it are future migrations like OPENCODE_MODELS_URL as Config.url.
  • Behavior invariant: two env-driven builds in one process always resolve the same database path, because the default provider's env snapshot is cached process-wide. Only an explicit ConfigProvider (see follow-up PR) can differ.
  • Considered porting V1's ConfigService helper (packages/opencode/src/effect/config-service.ts) but skipped it here: both call sites already have a natural home, and the helper's generated test layer wouldn't be used by the existing tests. Worth revisiting once more config-backed services exist in core (it could also unify ServerAuth.Config and V1 RuntimeFlags).

Verification

  • bun typecheck across the workspace (29/29 packages)
  • Full packages/core suite: 1071 pass / 0 fail
  • packages/sdk-next suite: 5 pass / 0 fail (embedded tests were 1/4 on clean dev locally)
  • packages/opencode script/httpapi-exercise.ts --mode coverage: 208 pass / 0 fail, plus focused V1 tests using the resetDatabase fixture
  • oxlint + Prettier on changed files
  • Three-agent simplify/safety review pass (reuse, quality, efficiency); findings addressed in follow-up commits

@kitlangton

Copy link
Copy Markdown
Contributor Author

Superseded by #34935 — this work belongs on the v2 branch, so both PRs were consolidated there.

@kitlangton kitlangton closed this Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant