Skip to content

[FEATURE]: Add content-only configuration authority for embedded runtimes #45492

Open

Description

@nonassa

Feature hasn't been suggested before.

  • I verified that this exact feature has not been suggested before.

Describe the enhancement you want to request

I run OpenCode as a child process and pass the whole config through
OPENCODE_CONFIG_CONTENT. I expected that to be the final config, but it
isn't. Account config, managed files or preferences, and discovered config
directories are loaded later, so they can change the provider or add plugins.

Could there be an opt-in flag that treats OPENCODE_CONFIG_CONTENT as the only
config source? In that mode OpenCode would skip the usual config discovery and
dependency install. It shouldn't touch existing config files, and launches
without the flag should behave as they do now.

#43227 is close, but --bare intentionally keeps managed configuration and
only covers opencode run. #21264 only disables global config. I'm looking for
the same kind of isolation when OpenCode is embedded as a child process.

Activity

  1. bukatea commented on Oct 17, 2026

    @bukatea

    Design proposal: invocation-owned configuration

    The source-level cause is broader than filesystem discovery: cached DB well-known documents still enter Config, external plugin modules can load before a later removal, and Console independently registers MCP/websearch. Empty inline plugin lists or post-load filtering cannot establish content authority. This is related to #45058, but proposes a new opt-in contract, not restoration of --pure.

    Proposed API: OPENCODE_CONFIG_ISOLATED=true, propagated to ServerOptions.config.isolated; direct Core callers have Config.Options.isolated for document loading only. Unset/false keeps ordinary behavior; other explicit env values fail without echoing their value. No new CLI flag.

    • Require nonblank, valid inline JSON/JSONC without normalization diagnostics; reject OPENCODE_CONFIG and nonempty plugin directives (including removals). No ambient fallback; explicit inline substitutions remain allowed; Config updates are unavailable.
    • In the standard owning server graph, exclude system/MDM, global, project, compatibility and stored well-known Config, their discovery/watch/refresh, and boot/config-discovery instructions. Replace WellKnown and ConfigPluginSource before graph/plugin loading, including lazy private instances. No external config-plugin-origin import/install/activation/watch; no account MCP/websearch registration. Builtins and explicit inline MCP remain available. Trusted host replacements can override this composition.
    • Admit CLI ownership at the shared handler and direct owner boundaries before service/connection/child activity: require explicit --standalone and no remote server for clients. Foreground/leased-stdio serve are explicit owners; managed serve rejects before settings/incumbent discovery. Pairing, service commands, ACP and the V1 run bridge are unsupported and reject early rather than silently using an existing server.

    Retained trust/policy exceptions: same datastore/credentials, provider/account executable authority (including provider/model packages, endpoints, authentication/refresh), and connected Console organization policy with existing load/error/refresh semantics. Same-connection transient failure retains loaded policy; this adds no cold-start fail-closed guarantee. Authored global/well-known/system/MDM policies and well-known providers are excluded, not migrated. Deployments requiring mandatory policy through those excluded channels are unsupported. Nested use-triggered instructions, session/resumed/subagent permissions and OS capabilities are unchanged: not a sandbox, zero-ambient-execution promise, pure equivalence, installed 2.0.25 capability, native acceptance or adoption claim.

    For concrete source review, the 18-path, two-commit prototype is pinned to base 180fd9d622c6855ef6ea36fd81314de6406af054: configuration/composition, then CLI admission. Current dev has advanced; this is not a current-dev compatibility claim or an automatic rebase.

    Recorded local source checks (Bun 1.4.2, 744846f84; not CI/native results), run from owning package directories:

    core:   bun run test test/config/isolation.test.ts                         # 18 pass
    cli:    bun run test test/config-isolation-options.test.ts test/config-isolation-ownership.test.ts # 115 pass
    server: bun run test test/config-isolation.test.ts                         # 1 pass
    

    CLI is 40 existing option cases + 75 ownership cases, not 115 native scenarios. Core also recorded seven selected ordinary-config regressions. Complete core/server/CLI bun run typecheck --singleThreaded and scoped formatting/lint checks recorded exit 0 (ast-grep disclosed its runtime-resolution warning). Unchanged core/server proof was rebound to final blobs, not rerun for publication; CLI and composition were rerun for the ownership correction. Composition exercises the real graph plus a second lazy instance with fake external I/O, executable-provider fields, effective Console denial/refresh retention and excluded-plugin boundary traps. Whole-suite/root-wide checks and native behavior remain unqualified; CI status is not established.

    Design decision requested: are these option semantics, retained executable-provider/Console-policy exceptions, and explicit unsupported-policy-deployment boundary acceptable, or should the contract change? Per CONTRIBUTING, I will not open an implementation PR without explicit maintainer design approval.

  2. bukatea commented on Oct 17, 2026

    @bukatea

    Design refinement: a functional, rejecting invocation-safety requirement

    The three opt-in proposals need a coherent caller contract: configuration authority here, permission maximum in #56351, and backend-proven file boundary in #56363. Environment transport alone cannot make an older CLI enforce new options it ignores. This refines the earlier “no new CLI flag” proposal for callers that require the combined guarantees.

    Proposed, not released: one typed --require-invocation-safety=v1 option on run, explicit-ID session export/delete, and foreground/leased-stdio serve. This is a functional requirement, not a version marker or permission grant. The actual historical 2.0.25 parser rejects the unknown option before loading a command handler when it precedes --; newly invented environment variables do not provide that refusal. This does not promise zero generic startup I/O or attest arbitrary executable wrappers.

    Required profiles would be:

    • Every profile requires explicit ownership, isolated nonblank valid inline configuration with no normalization diagnostics or explicit config-file selector, and a valid deny-first permission maximum. Unsupported managed/remote ownership rejects rather than converting or falling back.
    • run additionally requires the file boundary to match the actual Location/root. Resumed sessions do not acquire broader authority or silently remap roots.
    • Explicit-ID export/delete use an all-DENY maximum and no file boundary: session lifecycle is not a file-tool grant or database authorization fence. Leased serve accepts that lifecycle profile; any maximum containing ALLOW requires a boundary. All-DENY with a boundary remains a valid tools profile. A maximum ALLOW never overrides native/organization DENY.

    Snapshot and copy/freeze the strict inputs together at the owning preflight, before connection/service selection; preserve them through normal and lazy/private graphs. Forward the same typed requirement to the existing standalone child, before option termination, with explicit frozen security/config-selector environment overrides, then revalidate at child admission. Parsing the requirement while dropping its inputs is not compliance.

    Default-unset behavior stays unchanged. No extra engine, help/version probe, capability autodetection, alternate endpoint, second execution, or weaker fallback. Existing executable-provider/plugin trust and Console policy load/error/refresh exceptions remain; this is not an OS sandbox or race-free filesystem confinement claim.

    A reviewed private source prototype and producer-to-real-consumer fixture proof are available through a permitted review channel. Recorded local proof covers 16 scenarios/48 command vectors, real schema/parser/owner and normal/private tool graphs with synthetic external I/O; final focused packets recorded core 212 pass/6 inherited skips and CLI 97 pass. The separate historical-parser packet recorded 9 pass. These are not independent native scenarios, full-suite/CI results, actual lifecycle execution, provider/model confinement, or released-artifact qualification. CI is not established. No installed release is claimed compatible.

    Would this rejecting requirement and the two lifecycle/tools profiles fit the proposed ownership APIs? Per CONTRIBUTING, implementation publication/PR remains gated on explicit maintainer design approval and appropriate disclosure clearance; the private source proof does not replace either, or later release/native qualification.

  3. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed request, @nonassa!

    To restate it: you'd like an opt-in mode for embedded or child-process use where OPENCODE_CONFIG_CONTENT is the only config source. In that mode OpenCode would skip account/wellknown config, managed files and preferences, global/project directory discovery and dependency installation. Normal launches would stay as they are.

    Right now this ordering is on purpose. OPENCODE_CONFIG_CONTENT overrides global, OPENCODE_CONFIG and project config, but managed settings load after it so they always win, and account config is still loaded too. The existing flags (OPENCODE_CONFIG_DIR, OPENCODE_DISABLE_PROJECT_CONFIG, OPENCODE_DISABLE_CLAUDE_CODE) only turn off parts of discovery. A plugin can't do this either, because plugins are themselves loaded from the discovered config. So it would need a change in OpenCode itself. The maintainers will consider it, including how it should interact with managed policies, which are meant to be impossible to bypass.

    Related issues:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions