Skip to content

fix(server): refresh Windows PATH for providers

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 28, 2026 in 2m 53s

Effect Service Conventions: 1 issue found

apps/server/src/provider/Drivers/CodexDriver.ts (also ClaudeDriver.ts, CursorDriver.ts, GrokDriver.ts, OpenCodeDriver.ts) — the driver create effects now acquire HostProcessPlatform from the Effect environment but leave the host environment implicit, relying on mergeProviderInstanceEnvironment's baseEnv = process.env default. That keeps a runtime dependency in a module global while HostProcessEnvironment exists as a service (and is provided by this PR's own ProviderRegistry test), so an overridden environment is silently bypassed. Suggested fix posted inline: yield* HostProcessEnvironment and pass it as the third argument, matching GrokAdapter, UsageService, ResourceMonitorBinary, and os-jank.ts.

Details

Note

Your check run agent prompt is: .macroscope/check-run-agents/effect-service-conventions.md
More information about how Check Run Agents work can be found in our Help Center.

Reviewed in scope: the five provider drivers, ProviderInstanceEnvironment.ts, ProviderRegistry.ts (+ tests), and packages/shared/src/shell.ts (+ tests).

No other convention violations found:

  • All touched files use effect/* subpath namespace imports; no consolidated named imports from "effect".
  • HostProcessPlatform, HostProcessEnvironment, WindowsShellEnvironment, and CommandAvailability are Context.Reference values used with named imports, consistent with the existing @t3tools/shared/hostProcess and shell modules.
  • ProviderRegistryLive acquires FileSystem, Path, and HostProcessPlatform via yield*; the Effect.provideService calls around fixPath() are needed to keep the returned service methods requirement-free, not fake injection.
  • Layer.succeed usages in ProviderRegistry.test.ts are legitimate test seams; no ManagedRuntime.make, runPromise, or runPromiseExit introduced.
  • No new errors/predicates introduced, so the error-modeling rules do not apply; the added tests cover real behavior changes (Windows PATH rehydration, override normalization) rather than a mechanical refactor.
  • packages/shared/src/shell.ts changes are confined to a pure command-builder function and its options plumbing.

🔍 Agent activity — 13 tool calls

💭 I'm reviewing the changed files to check Effect service conventions, starting with ProviderRegistry.ts and its use of Semaphore, FileSystem, Path, and fixPath, then checking how HostProcessPlatform is imported to see if it follows the expected service module pattern.

1. browse_code — apps/server/src/provider/ProviderInstanceEnvironment.ts

2. browse_code — packages/shared/src/hostProcess.ts

💭 I'm noting that hostProcess being part of Context.References is fine with existing import conventions. I'm also checking whether mergeProviderInstanceEnvironment defaulting to process.env conflicts with the "no hidden globals" convention, but since it's pre-existing behavior and drivers already pass platform without environment, it seems consistent rather than a new violation. Now I'm turning my attention to the ProviderRegistry.ts changes.

3. browse_code — apps/server/src/provider/Layers/ProviderRegistry.ts

4. browse_code — apps/server/src/os-jank.ts

💭 I'm noticing something odd in ProviderRegistry.ts—fixPath() explicitly provides FileSystem and Path services even though those requirements would already be satisfied by the layer's environment, making it seem redundant rather than an actual violation. Also checking whether HostProcessPlatform and HostProcessEnvironment matter here, but since they're Context.Reference with defaults, they don't add requirements. The import ordering with Semaphore after Stream looks like a style nitpick rather than an Effect convention issue, so I'll skip that. More importantly, I want to verify whether effect/Semaphore is even a real module with a make function in this version of Effect, or if the semaphore API lives elsewhere like Effect.makeSemaphore.

5. git_tools — effect/Semaphore|makeSemaphore|Semaphore.

💭 Now I'm checking the refresh functions in ProviderRegistry.ts around lines 460-530 to evaluate the added empty-sources early return and where refreshWindowsPath is placed.

6. browse_code — apps/server/src/provider/Layers/ProviderRegistry.ts

💭 I'm checking whether manually re-providing FileSystem and Path services after already acquiring them from the environment counts as a convention violation—it seems redundant but not actually wrong since the requirements are still exposed properly. Looking further, I notice fixPath mutates HostProcessEnvironment imperatively, which is pre-existing behavior. The bigger concern is that the driver's environment-merging helper defaults to process.env as a module global rather than pulling from HostProcessEnvironment consistently, which could hide a dependency in production service construction—worth flagging since it undermines the PR's goal of ensuring PATH hydration reaches driver env objects. I want to check whether other callers of mergeProviderInstanceEnvironment pass in a base environment sourced from HostProcessEnvironment during production, to see if this inconsistency shows up elsewhere.

7. git_tools — mergeProviderInstanceEnvironment

💭 I notice drivers implicitly rely on process.env while the platform uses the Effect environment's HostProcessEnvironment service, which fixPath mutates directly. That's inconsistent: if tests or callers override HostProcessEnvironment, drivers would still read stale env values since they bypass the service. This looks like a genuine hidden-dependency issue worth flagging with an inline comment. The default baseEnv = process.env was pre-existing, so this hidden global isn't strictly new — but the PR did touch this signature and its callers when adding platform, so it's arguably in scope. I want to check the test file's import conventions to see how strict the codebase is about pulling dependencies from the Effect environment versus module globals before deciding how pedantic to be here.

8. browse_code — apps/server/src/provider/Layers/ProviderRegistry.test.ts

💭 The imports look fine with subpath namespaces, and the test's use of Layer.succeed for the provider registry, Windows shell environment, and command availability services are legitimate test seams. Now I'm checking whether resolveWindowsEnvironment actually uses these new WindowsShellEnvironment and CommandAvailability services, looking specifically at how buildWindowsEnvironmentCaptureCommand was changed. I'm confirming the WindowsEnvironmentProbeOptions type and its usage in readEnvironmentFromWindowsShell look correct, then moving on to review the broader shell.ts changes for correctness and consistent service conventions.

9. browse_code — packages/shared/src/shell.ts

💭 I'm confirming that the Windows shell environment reference and the semaphore-guarded path refresh logic are being reused correctly without any convention issues, then checking how FileSystem service is being provided in that effect chain. Since the ProviderRegistryShape's methods must have R = never, providing the FileSystem service inline is actually necessary rather than an antipattern -- so that pattern checks out fine. I'm now looking at whether the large test file added in the PR is justified given that it's tied to an actual behavior change, not just a mechanical refactor. The registry test builds its own provider environment manually rather than routing through actual drivers, essentially acting as a test double for driver behavior, which seems like an acceptable simplification rather than mocking core logic. What catches my attention more is that drivers pull HostProcessPlatform while implicitly relying on process.env, meaning the Effect-provided HostProcessEnvironment gets bypassed in production -- that looks like a hidden module-level dependency worth flagging. I'm weighing whether to raise a single finding across the five driver files, suggesting they explicitly acquire HostProcessEnvironment from the environment and merge it with the platform, since fixPath mutates that object anyway so passing it through directly would be more correct. I'm trying to gauge how serious this convention violation really is, since the check tends to default toward failure unless everything is clearly clean. I'm also grappling with the response format — the check says the final answer should be exactly "All clear" if nothing's wrong, but the system schema expects structured JSON, so I'll need to reconcile that by using "All clear" as the title/summary with a success state, and marking failure if the finding holds. Now I'm scrutinizing whether mergeProviderInstanceEnvironment really counts as hidden service injection, since platform reads like pure configuration and the default baseEnv might just be a convenience fallback rather than a true dependency violation. The PR clearly threads platform through the Effect service pattern deliberately, but leaves process.env reads implicit in those same helper functions, which does look like an inconsistency worth flagging — probably a single, proportionate inline comment on one line rather than a broader complaint, though I'm still weighing whether this rises to the level of a real convention violation that should fail the check versus something more like a soft suggestion. Given the ambiguity — legacy code, default parameters — I'm inclined toward a neutral posture unless I find clearer evidence, but the guidance leans toward defaulting to failure unless things are genuinely clean. Let me check whether the drivers actually spawn processes using process.env and see if HostProcessEnvironment is used elsewhere in the server drivers, searching for its usage across apps/server.

10. git_tools — HostProcessEnvironment

💭 I'm noting that the established pattern elsewhere in the codebase is to pull the host environment via yield* HostProcessEnvironment, but these drivers only source platform from the environment while letting baseEnv fall back to process.env — a real inconsistency with convention and the rule against hiding dependencies in module globals, right on the lines being changed. I'll flag this as a single comment. Rather than posting five nearly identical comments across all the affected drivers, I'll post one focused inline comment on CodexDriver noting that the same pattern repeats in the Claude, Cursor, Grok, and OpenCode drivers. Let me verify GrokAdapter really does use hostEnvironment when spawning provider processes, and confirm mergeProviderInstanceEnvironment falls back to returning the live process.env object when the merged environment is empty. Now I'm locating the exact line numbers in CodexDriver.ts where the platform and processEnv are computed so I can anchor the comment precisely. I'm confirming the diff's added lines correspond to the platform and merge-call lines, and I'm putting together a suggested fix that pulls in HostProcessEnvironment alongside HostProcessPlatform and passes it into the merge function, along with a note that the import statement needs to be extended to include it.

11. browse_code — apps/server/src/provider/Drivers/CodexDriver.ts

12. browse_code — apps/server/src/provider/Layers/GrokAdapter.ts

💭 Since the same violation shows up in all five driver files, I'm weighing whether to leave five separate comments or consolidate. Five identical remarks feels noisy, so I'll settle on one detailed comment on CodexDriver.ts that also lists the other four affected files. For status, the check explicitly says to default to failure when there's a clear convention violation, so I'll mark this as failure rather than defaulting to success — hiding process.env as a module global instead of using the established HostProcessEnvironment pattern is a real, actionable issue. Line 127 is part of the diff, so I'll post the comment there.

13. modify_pr — One convention issue found: the driver create effects now take HostProcessPlatform from the Effect environment but still let mergeProviderInstanceEnvironment fall back to the process.env module global instead of HostProcessEnvironment. See the inline comment for the suggested fix (applies to all five touched drivers).


Agent Credits: 99 credits