feat(mcp): update environment preferences#8728

closed5
agents/mcp-environment/read
agents/mcp-environment/preferences
openedAug 30, 2026byJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 3d ago

Problem

Agents could inspect current environment preferences but had no narrow, permission-aware way to update useful nonsecret server-owned defaults.

Change

Add t3_environment_preferences_update for an explicit typed allowlist: default thread environment mode, new-worktree origin behavior, provider update checks, normalized background-activity presets, and bounded source-control writing style.

Behavior

Omitted fields remain unchanged, explicit empty custom instructions clear them, and the result comes from normalized persisted settings rather than request inputs. Mutation requires a full-access/default caller. A fresh caller shell is checked under the canonical ThreadCommandExecutor lock held through settings persistence, so a concurrent V2 downgrade wins safely. Existing settings notifications continue to update web, desktop, and mobile clients. Provider configuration, credentials, paths, browser access, observability, and arbitrary settings remain excluded.

Focused validation

  • real settings persistence, notification, normalization, omission/clear, and Unicode code-point tests
  • Deferred-gated real V2 caller-downgrade race coverage
  • production HTTP tools/list, Claude read-only allowlist, and presentation coverage
  • 6 focused files / 18 tests passed across the complete native stack
  • server and contracts scoped typechecks, targeted formatting, and git diff --check

Dependency

Upper layer of native stack 8782. Depends on #8726 for the safe current-environment read foundation and preference projection.

Implemented by GPT-5.6-Sol via Codex in T3 Code.

Synced from GitHub

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: be30e0c9-f657-4a2e-902b-cf8e8d569c62

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


Comment @coderabbitai help to get the list of available commands.

Synced from GitHub

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for aae1adc.

This comment will update automatically after the next completed run.

MmacroscopeappBotreviewed · 1 inline threadAug 30, 2026
Synced from GitHub

Effect service conventions review: one deviation found in the new ThreadDispatchLockV2 service definition. The rest of the change (dependency acquisition via yield* Foo.Foo in EnvironmentMcpService.make, Layer.effect canonical layer, inline service interface, subpath namespace imports of effect/*, test-only Layer.succeed/Layer.mock/provideService seams) matches the conventions.

Posted via Macroscope — Effect Service Conventions

apps/server/src/orchestration-v2/KeyedSerialExecutor.tslines 60–66Outdated · fef7ed3Open thread
……@@ -53,3 +56,14 @@ export const makeKeyedSerialExecutor = <Key>(): Effect.Effect<KeyedSerialExecuto
63+ KeyedSerialExecutor<ThreadId>
64+>()("t3/orchestration-v2/KeyedSerialExecutor/ThreadDispatchLockV2") {}
65+
66+export const threadDispatchLockLayer = Layer.effect(
MmacroscopeappBoton lines 60–66Aug 30, 2026

The new ThreadDispatchLockV2 service exports its layer as threadDispatchLockLayer; the convention is a canonical export const layer for the module that owns a service (every other orchestration-v2 service module here does that, reserving suffixed names like layerMemory/layerWithLegacyImporter for alternative layers).

Suggested fix: move the tag plus its layer into a dedicated module (e.g. ThreadDispatchLock.ts) that exports layer, and consume it as a namespace at the six call sites (ThreadDispatchLock.ThreadDispatchLockV2, ThreadDispatchLock.layer). Renaming the export to layer in this file and importing * as KeyedSerialExecutor also satisfies the convention if you prefer to keep it colocated with the generic executor.

Posted via Macroscope — Effect Service Conventions

Fixed at 1c6dee0730b. ThreadDispatchLockV2 remains in KeyedSerialExecutor.ts with the exact existing Context service key; the layer export is now the canonical layer and every service consumer uses the KeyedSerialExecutor module namespace. No second lock or renamed service identity was introduced.

MmacroscopeappBotreviewed · 1 inline threadAug 30, 2026
Synced from GitHub

One convention finding on the new test module's service imports. The prior finding on threadDispatchLockLayer in KeyedSerialExecutor.ts still stands but is not re-posted.

Posted via Macroscope — Effect Service Conventions

apps/server/src/mcp/EnvironmentPreferencesMcpService.test.tslines 38–51Outdated · cfc5143Open thread
……@@ -0,0 +1,357 @@
48+ EnvironmentMcpService,
49+ layer as environmentMcpLayer,
50+ make as makeEnvironmentMcpService,
51+} from "./EnvironmentMcpService.ts";
MmacroscopeappBoton lines 38–51Aug 30, 2026

mcp/EnvironmentPreferencesMcpService.test.ts:51

These two service modules are imported with renamed member aliases (layer as threadManagementLayer, layer as environmentMcpLayer, make as makeEnvironmentMcpService), which erases the module namespace at a service boundary. The convention here is a namespace import so the module's public shape stays visible (ThreadManagement.ThreadManagementService / ThreadManagement.layer, EnvironmentMcp.EnvironmentMcpService / EnvironmentMcp.make / EnvironmentMcp.layer) — the sibling EnvironmentMcpService.test.ts already avoids aliasing.

Suggested fix: switch to import * as ThreadManagement from "../orchestration-v2/ThreadManagementService.ts"; and import * as EnvironmentMcp from "./EnvironmentMcpService.ts";, then update the four usages in this file (threadLayer, the environmentMcpLayer.pipe(...) provide, makeEnvironmentMcpService.pipe(...), and the yield* EnvironmentMcpService / yield* ThreadManagementService acquisitions) to the namespaced members.

No longer relevant as of 1c6dee0730ba0a8399e9b5b3b488507e729b89e0

Fixed at 1c6dee0730b. The integration test now imports ThreadManagementService and EnvironmentMcpService as module namespaces and accesses each service, layer, and make member through that namespace.

Synced from GitHub

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This adds a production MCP mutation that durably changes environment-wide defaults and operational behavior, including thread environments, background activity, provider checks, and source-control writing. Its shared orchestration locking and cross-client settings notifications make the blast radius broader than a small isolated option.

Notes:

  • Diff unchanged. Approvability was decided on eligibility alone.

No code changes detected at aae1adc. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

docs/internals/environment-mcp.mdlines 35–35Outdated · 7f56c9fOpen thread
……@@ -22,3 +22,17 @@ The preference projection is a literal allowlist. It must be extended field by
32+service remains responsible for normalization, durable storage, and existing
33+cross-client notifications.
34+
35+The mutation exposes preset background profiles, not arbitrary timing
MmacroscopeappBoton lines 35–35Aug 30, 2026

🟢 Low internals/environment-mcp.md:35

The documentation incorrectly states that the mutation exposes only preset background profiles, so consumers are led to believe the supported custom BackgroundActivityProfile value cannot be selected. Mention custom alongside the presets.

suggestion
1The mutation exposes preset and custom background profiles, not arbitrary timing
Also found in 1 other location(s)

docs/user/environment-mcp.md:29

The background-activity list says the update tool accepts only balanced, performance, or battery-saver, but its input schema accepts BackgroundActivityProfile, which also includes custom. Agents following this documentation will incorrectly believe they cannot select the supported custom profile.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
text
1In file @docs/internals/environment-mcp.md around line 35:
2
3The documentation incorrectly states that the mutation exposes only preset background profiles, so consumers are led to believe the supported `custom` `BackgroundActivityProfile` value cannot be selected. Mention `custom` alongside the presets.
4
5Also found in 1 other location(s):
6- docs/user/environment-mcp.md:29 -- The background-activity list says the update tool accepts only `balanced`, `performance`, or `battery-saver`, but its input schema accepts `BackgroundActivityProfile`, which also includes `custom`. Agents following this documentation will incorrectly believe they cannot select the supported `custom` profile.

No change is needed here. The update input intentionally uses BackgroundActivityProfile, whose only values are balanced, performance, and battery-saver (packages/contracts/src/settings.ts:629-634). custom belongs to the separate BackgroundActivityProfileSelection output/settings schema and requires timing overrides; this MCP surface deliberately does not accept arbitrary timing overrides. The current user and internal docs accurately describe the mutation boundary.

Added 5 commits

  • feat(mcp): update environment preferencesf766b33
  • test(mcp): retain preference service dependencies1d60044
  • chore(server): format environment rebaseaae1adc
  • fix(mcp): read preference policy from thread shelle1be142
  • chore(server): format replay harness compositione2bcbb9

Superseded as the active MCP proposal by #10560 in the rebuilt MCP stack, following the maintainer request to review thin service wrappers separately from service hardening.

This is not a full feature-parity replacement. Updates require a live full-access/default caller under the existing ThreadCommandExecutor. Provider configuration, secrets and admin controls are not exposed. No new settings store or lock service.

Closing this mixed proposal without merging. The remote branch agents/mcp-environment/preferences and exact head aae1adc5097ced03fa716e4222db448e6425310f are retained so the service changes can be extracted for separate review later.