This repository was archived by the owner on Nov 7, 2026. It is now read-only.
Repository navigation
fix(core): load env-supplied config in V2 config - #347
Merged
Merged
Conversation
) Plan for swxtchio/swx-abbe#1952. Root cause: the V2 Config layer (packages/core/src/config.ts) reads only the global config directory and discovered project files. It ignores OPENCODE_CONFIG and OPENCODE_CONFIG_CONTENT. The jail supplies its whole config through those two variables (Dockerfile.jail sets OPENCODE_CONFIG, opencode_server.py renders OPENCODE_CONFIG_CONTENT), so the V2 catalog never sees the swxtch-egress provider or a configured default model. V1 (packages/opencode/src/config/config.ts) reads both, which is why V1 turns run on the egress provider. Change: - Config takes explicit file and content sources, defaulting to Flag.OPENCODE_CONFIG and Flag.OPENCODE_CONFIG_CONTENT, with a layerWith seam for tests (mirrors Global.layerWith and upstream's Config.Options file/content from 43c0838). - Precedence matches V1 and upstream: global directory, then the OPENCODE_CONFIG file, then project files, then project .opencode directories, then OPENCODE_CONFIG_CONTENT last. - V1-format sources migrate through the existing loader path. Tests: - Config loader orders explicit file and content entries. - A jail-shaped V1 config supplied as content reaches the catalog and SessionRunnerModel resolves the named swxtch-egress model to an OpenAI-compatible route at the proxy URL. Claude-Session: https://claude.ai/code/session_01HGGfNzV3BHB7W49PTT9MVp
Author
|
Session ID: 34738ff3-3dcf-4587-8fde-7c58d5478796 |
The V2 Config layer read only the global config directory and discovered project files, ignoring OPENCODE_CONFIG and OPENCODE_CONFIG_CONTENT. The OpenCode jail supplies its whole config through those variables, so the V2 runner's catalog never held the swxtch-egress provider or the configured default model: a named egress model failed with ModelUnavailableError and an unnamed one fell to another provider (swxtchio/swx-abbe#1952). Config now takes explicit file and content sources, defaulting to the two flags, and orders them as V1 does: global directory, explicit file, project files, .opencode directories, then inline content. V1-format sources migrate through the existing loader path. Config.nodeWith names the sources directly for tests. Tests drive the real loader: precedence of every source, and the jail's V1 config (placeholder file plus rendered content) through the config provider plugin and catalog to SessionRunnerModel, for a named model and for the configured default against a competing provider. Claude-Session: https://claude.ai/code/session_01HGGfNzV3BHB7W49PTT9MVp
Review round 1: with the env-config fix alone, a location-only V2 session in the jail (create_session_v2 names no model, and the jail config sets none) still resolved a credential-free catalog model such as opencode/hy3-free ahead of the config-declared swxtch-egress model, so egress turns still failed. V1's Provider.defaultModel takes its default from the config-declared providers when no model is configured. The V2 catalog now does the same: the config provider plugin records the declared providers in config order, and Catalog.model.default picks the newest available model of the first one that has any, before its newest-available fallback. An explicit session model or configured `model` still wins. The preference registers on the internal catalog under the plugin's scope, because the public plugin catalog API has no such hook. Tests: the jail path through the production location runtime (every internal plugin, the recorded models.dev corpus, the jail config via OPENCODE_CONFIG and OPENCODE_CONFIG_CONTENT) resolves a location-only session to the egress model; and the preference skips an unavailable declared provider and beats a newer undeclared model. Both are red without the preference. Claude-Session: https://claude.ai/code/session_01HGGfNzV3BHB7W49PTT9MVp
brentyates-swx
marked this pull request as ready for review
October 23, 2026 15:24
brentyates-swx
added a commit
that referenced
this pull request
Oct 23, 2026
Run 39983517672 (harness and source 774d90c) built and probed the clean source natively; artifact 12515386562. Also retain the focused small-model and #347 config test runs at the release source. Claude-Session: https://claude.ai/code/session_01PTFci7pw9AaruJDJoHDsPr
This was referenced Oct 23, 2026
brentyates-swx
added a commit
that referenced
this pull request
Oct 23, 2026
* docs(release): plan source-pinned release cut for 774d90c Record pickup identity and ancestry for release v1.18.32-swxtch.774d90c7, which carries #347 for Abbe B-16.10, and the native build/publish plan. Claude-Session: https://claude.ai/code/session_01PTFci7pw9AaruJDJoHDsPr * docs(release): retain native x64 candidate evidence for 774d90c Run 39983517672 (harness and source 774d90c) built and probed the clean source natively; artifact 12515386562. Also retain the focused small-model and #347 config test runs at the release source. Claude-Session: https://claude.ai/code/session_01PTFci7pw9AaruJDJoHDsPr * docs(release): retain native arm64 candidate evidence for 774d90c Built and probed natively on vm14-001 under firstmate's grant and the single ACTIVE lease (acquired 16:35:05Z, released 16:41:03Z, no task processes left). Claude-Session: https://claude.ai/code/session_01PTFci7pw9AaruJDJoHDsPr * docs(release): add release body for v1.18.32-swxtch.774d90c7 Claude-Session: https://claude.ai/code/session_01PTFci7pw9AaruJDJoHDsPr * docs(release): retain publication read-back for v1.18.32-swxtch.774d90c7 Claude-Session: https://claude.ai/code/session_01PTFci7pw9AaruJDJoHDsPr * docs(release): record release-cut-3 evidence, delivery and changeset Claude-Session: https://claude.ai/code/session_01PTFci7pw9AaruJDJoHDsPr
brentyates-swx
added a commit
that referenced
this pull request
Oct 23, 2026
* docs(release): plan the cd3f0ce source-pinned release cut Records the pickup identity and ancestry for source cd3f0ce (#350 on top of #347) and the execution plan, including Abbe's jail V2 egress rig as a publication gate on the unpublished packaged bytes. Claude-Session: https://claude.ai/code/session_01NKeH8jbkJT2c3st6wJmeM1 * chore(release): record v1.18.32-swxtch.cd3f0ce2 native, jail-rig and publication evidence Adds the published release body and the raw arm64 (vm14-001) and x64 (Actions run 40015678366) build and probe observations, the lease receipts, the focused test runs, the Abbe jail V2 egress rig run on the unpublished arm64 candidate, and the publication read-back and downloaded-byte checks. Claude-Session: https://claude.ai/code/session_01NKeH8jbkJT2c3st6wJmeM1 * docs(release): record cd3f0ce release evidence, delivery and changeset entry Adds RELEASE-CUT-4-EVIDENCE.md and the raw-evidence index, the SaaS wake-log append receipt and peer outbox record, the unestablished Abbe B-16.10 recipient, and the #351 CHANGESET entry. Claude-Session: https://claude.ai/code/session_01NKeH8jbkJT2c3st6wJmeM1 * docs(release): record the Abbe handoff as delivered by firstmate Firstmate relayed the cd3f0ce release notice to Abbe through its peer channel after this task's own sends were refused. The evidence now cites and retains that relay, noting that it points to the published checksum companions rather than quoting the digests. Claude-Session: https://claude.ai/code/session_01NKeH8jbkJT2c3st6wJmeM1 * docs(release): record Abbe's acknowledgment and bump-brief citation as the handoff read-back Abbe ruled that peer homes never write each other's runtime state, which withdrew the task wake-log append. The evidence now records the two read-back receipts Abbe named: acknowledgment p1792786679-2709706-0cf3 and the bump brief's verbatim citation of the relay, plus the ruling's proof. Claude-Session: https://claude.ai/code/session_01NKeH8jbkJT2c3st6wJmeM1 * docs(release): complete the cd3f0ce delivery receipt chain Appends the delivery record to this task's producer wake log and keeps its read-back receipt and verbatim copy. Records firstmate's disposition that the Abbe captain's ruling waived the Abbe task wake-log append, and keeps the rerun relay identity check against the archived and delivered copies. Claude-Session: https://claude.ai/code/session_01NKeH8jbkJT2c3st6wJmeM1
brentyates-swx
added a commit
that referenced
this pull request
Oct 24, 2026
* docs(release): plan the d7f7888 source-pinned release cut Records the pickup identity and ancestry for source d7f7888 (#354 on top of #350 and #347), the brief's #353 discrepancy, and the execution plan: x64 via the release-candidate job, arm64 and Abbe's jail V2 egress rig (with the compact mode) on vm14-001 under the lease, as the publication gate. Claude-Session: https://claude.ai/code/session_013Se6FG9EEPtmFRtg1hLDMm * chore(release): record v1.18.32-swxtch.d7f78881 native, jail-rig and publication evidence Adds the published release body and the raw arm64 (vm14-001) and x64 (Actions run 40052511379) build and probe observations, the three lease laps' receipts, the focused test runs, Abbe's jail V2 egress rig in all four modes (including compact) on the unpublished arm64 candidate, with the two setup-failed laps kept as found, and the publication read-back and downloaded-byte checks. Claude-Session: https://claude.ai/code/session_013Se6FG9EEPtmFRtg1hLDMm * docs(release): record d7f7888 release evidence and changeset entry Adds RELEASE-CUT-5-EVIDENCE.md and the raw-evidence index, and the #357 CHANGESET entry. Records the brief's #353 discrepancy, the three lease laps, the arm64 jail rig pass in all four modes with the x64 caveat, why the V2 turn modes' completed waits say nothing about #352, and that delivery is firstmate's. Claude-Session: https://claude.ai/code/session_013Se6FG9EEPtmFRtg1hLDMm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs swxtchio/swx-abbe#1952
Root cause
The V2 core
Configlayer (packages/core/src/config.ts) read only the global config directory and discovered project files. It ignoredOPENCODE_CONFIGandOPENCODE_CONFIG_CONTENT. The OpenCode jail supplies its whole config through those two variables:Dockerfile.jailsetsOPENCODE_CONFIG=/jail/opencode.json, andopencode_server.py::configure_runtime_configrenders the proxy URL and capability intoOPENCODE_CONFIG_CONTENT. So the V2 catalog never heldswxtch-egressor a configuredmodel, andSessionRunnerModel.locationLayerfailed a named egress model withModelUnavailableErroror picked another provider. V1 (packages/opencode/src/config/config.ts) reads both variables, which is why V1 turns reached the egress provider.Change
Configtakes explicitfileandcontentsources, which default toFlag.OPENCODE_CONFIGandFlag.OPENCODE_CONFIG_CONTENT.Config.nodeWith(sources)is the test seam, in the same shape asGlobal.layerWith.43c08387f1: global directory, then the explicit file, then project files, then.opencodedirectories, with inline content last. In the jail, the rendered content therefore overrides the file's{env:…}placeholders. V2 has no{env:}substitution, and it doesn't need one here.ConfigMigrateV1).Tests (red on the reverted loader)
test/config/config.test.ts: checks the order of every source and that inline content wins.test/config/environment.test.ts: runs the jail's own V1 config (the placeholder file plus the rendered content) through the real loader, the config provider plugin, the catalog andSessionRunnerModel.locationLayer:swxtch-egress/accounts/fireworks/models/deepseek-v4p1-flashresolves to the rendered proxybaseURLwithBearer <capability>. On the reverted loader this test fails with the issue'sModelUnavailableError.modelconfigured, selects egress over a competing global provider that would otherwise sort first. On the reverted loader it picks the other provider.Review round 1: default for a session that names no model
On the env-config fix alone, a location-only V2 session in the jail still resolved a credential-free catalog model (
opencode/hy3-freeagainst the recorded models.dev corpus), becauseCatalog.model.default()fell back to the newest available model. V1'sProvider.defaultModelinstead takes its default from the config-declared providers when nomodelis configured. V2 now does the same:ConfigProviderPluginrecords the config-declared providers, in config order, through a new internalCatalogdraft hook,model.default.prefer. The public plugin catalog API has no such hook, so the plugin registers the preference on the internalCatalog.Serviceunder its own plugin scope.Catalog.model.default()takes the newest available model of the first preferred provider that has one, and otherwise falls back to the newest available model. An explicit session model or a configuredmodelstill takes precedence.Tests (red without the preference):
test/location-layer.test.tsruns the actual jail path: the production location runtime with every internal plugin, the recorded models.dev corpus (packages/opencode/test/tool/fixtures/models-api.json), and the jail config supplied throughOPENCODE_CONFIGandOPENCODE_CONFIG_CONTENT. A location-only session resolves toswxtch-egress/accounts/fireworks/models/deepseek-v4p1-flashat the rendered proxy. Without the preference it resolvesopencode/hy3-freewhen no provider credentials are set, or the newest credentialed model when some are.test/config/provider.test.ts: the preference skips a declared provider that has no credentials and beats a newer model from an undeclared provider.Abbe side
No producer change is required. With this PR, a location-only
create_session_v2session in the jail resolves to the egress model. B-16.7 (anomalyco#1792), which sends the model on create, also resolves now.🤖 Generated with Claude Code