Skip to content

feat(codex): codexConnectorWrites toggle for ChatGPT-connector write tools#1322

Open
cyrusagent wants to merge 2 commits into
codex/fix-app-server-elicitation-rejectionfrom
codex/connector-writes-toggle
Open

feat(codex): codexConnectorWrites toggle for ChatGPT-connector write tools#1322
cyrusagent wants to merge 2 commits into
codex/fix-app-server-elicitation-rejectionfrom
codex/connector-writes-toggle

Conversation

@cyrusagent

Copy link
Copy Markdown
Contributor

Summary

Stacked on #1321. With elicitation auto-accept in place, mutating tools from ChatGPT-account connectors (the host-owned codex_apps MCP server — e.g. the bundled Linear connector) now silently succeed in Codex sessions. This adds the operator off switch: a codexConnectorWrites: "enabled" | "disabled" policy (default "enabled").

Semantics

"Disabled" does not decline approval prompts — it blocks the tools upstream. CodexConfigBuilder emits per-thread config overrides:

[apps._default]
destructive_enabled = false
open_world_enabled = false

Codex then refuses destructive/open-world connector tools before any approval flow, with a clear "MCP tool call blocked by app configuration" error the model can relay (vs. the misleading "user rejected" a decline would produce). Connector tools annotated read-only and all regular mcp_servers entries are unaffected. The _default key and snake_case fields match codex's AppsConfigToml exactly (it rejects unknown fields).

This also avoids a pooling conflict: the server-request handler lives on the pooled app-server process shared across sessions, so per-session policy belongs on thread/start config — the same channel as the per-thread sandbox profiles.

Configuration surface

Surface Scope Precedence
repositories[].codexConnectorWrites per-repo wins over everything
CYRUS_CODEX_CONNECTOR_WRITES env var (loaded from ~/.cyrus/.env) global wins over global config
top-level codexConnectorWrites in config.json global base value

Env parsing is strict (enabled/disabled, case-insensitive; anything else warns and is ignored), matching the CYRUS_HOST_EXTERNAL convention. Hot-reload is wired (ConfigManager merge whitelist + globalKeys). Chat sessions (repo-agnostic) get the global value via the createRunner injection with a live config read.

Validation

  • Real binary (0.137): thread/start with the apps._default override is accepted, and a regular mcp_servers mutating tool still executes with the override present — proving the block is scoped to codex_apps only. (A live connector-write block test was deliberately skipped: if the block failed, the test would mutate a real third-party account. The gate logic itself is codex's own unit-tested app_tool_policy_from_apps_config path.)
  • New unit tests: CodexConfigBuilder.connector-writes.test.ts (emission, default-off, merge preservation with caller-supplied apps overrides) and RunnerConfigBuilder.codex-connector-writes.test.ts (plumbing, codex-only).
  • Full pnpm test:packages:run green (722 edge-worker / 77 codex-runner / 137 core), pnpm typecheck clean, JSON schemas regenerated (generate:json-schema).

Follow-up (CYHOST)

cyrus-hosted needs the GUI toggle + config emission for cloud users — runner-settings section, not the /settings/tools tool catalog.

🤖 Generated with Claude Code

…tools

Adds a "enabled" | "disabled" policy (default "enabled") controlling
whether Codex sessions may use mutating tools from ChatGPT-account
connectors (the host-owned codex_apps MCP server, e.g. the Linear
connector). With the elicitation auto-accept fix, connector writes now
silently succeed under approvalPolicy "never"; this gives operators an
explicit off switch.

When disabled, CodexConfigBuilder emits
apps._default.destructive_enabled=false / open_world_enabled=false into
the per-thread config overrides. Codex then blocks destructive and
open-world connector tools BEFORE any approval flow, with a clear
"blocked by app configuration" error the model can relay. Tools
annotated read-only and regular mcp_servers entries are unaffected
(verified against the real 0.137 binary: a mutating mcp_servers tool
still executes with the override present).

Configuration surface:
- config.json: top-level codexConnectorWrites, overridable per
  repository (repo value wins)
- env: CYRUS_CODEX_CONNECTOR_WRITES (strict "enabled"/"disabled" parse
  with a warning on anything else; wins over the global config value,
  loses to an explicit per-repo value)
- hot-reload: wired into ConfigManager's merge whitelist + globalKeys
- chat sessions (repo-agnostic) get the global value via createRunner

JSON schemas regenerated for the new fields.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant