Skip to content

Merge origin/main into fix/grok-adapter-reliability

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 20, 2026 in 5m 57s

Effect Service Conventions: 1 issue found

1 finding

  • apps/server/src/provider/acp/XAiAcpExtension.ts (lines 328, 330): the new isGrokPlanMarkdownPath helper reads process.platform from the module global instead of the injected HostProcessPlatform reference. The repo enforces this as an error (t3code/no-global-process-runtime in vite.config.ts), and these are the only unsuppressed occurrences in the tree. The neighbouring grokPlanSessionPrefixes() similarly reads process.env.HOME / USERPROFILE / GROK_HOME directly, while UsageService in this same PR correctly resolves GROK_HOME through HostProcessEnvironment.

Suggested fix: resolve the platform/environment in the Effect caller (GrokAdapter) via yield* HostProcessPlatform / yield* HostProcessEnvironment (both are Context.References with defaults, so no extra layer is required) and pass them into the helpers. This also removes the need for the new test to mutate process.env.

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.

Scope reviewed: changed .ts/.tsx files under apps/**, packages/**, infra/**, plus directly affected call sites.

Checked and clean

  • Imports: new Effect imports (effect/Clock, effect/Duration, effect/Queue, effect/Option, effect/Result) use subpath namespace form; no consolidated from "effect" imports were introduced. Named imports from @t3tools/contracts, @t3tools/shared/model, @t3tools/shared/shell, and effect/unstable/process match the established repo-wide convention.
  • Service definitions: no new Context.Service was added. AcpSessionRuntime's inline interface was extended (setSessionModel(modelId, meta)) without reintroducing a standalone shape type. GrokSkills.ts is a plain helper module (pure parser + Effect.fn probe), not a service, so make/layer naming rules do not apply.
  • Dependency acquisition: GrokDriver acquires cwd from ServerConfig in the environment and passes it as a plain value; UsageService acquires HostProcessEnvironment from the environment. No ManagedRuntime.make, runPromise, or runPromiseExit was introduced in domain/service code; the only new Layer.succeed is a ChildProcessSpawner test seam in GrokSkills.test.ts.
  • Errors: no new error classes were introduced. settleXAiPromptCompletion uses the existing EffectAcpErrors.AcpRequestError (structured code + errorMessage) and its internalError static factory; the rate-limit failure originates from a protocol notification with no underlying error, so an absent cause is correct. No new catchTag/predicate-based catchIf recovery of known tags. The Effect.catch(() => Effect.void) on the watchdog fiber intentionally handles the whole channel.
  • File layout: no service module moves or compatibility shims; no obsolete domain/Services + domain/Layers pairs left behind.
  • Change discipline: added tests cover new backend behavior (watchdog liveness, permission-option fallback, plan capture, Grok usage parsing) rather than proving a mechanical refactor.

🔍 Agent activity — 1 tool call

💭 I'm reviewing the diff for Effect service convention violations, checking the new GrokSkills.ts file and changes across the Grok adapter, provider, and runtime files. I'm looking at the imports in GrokSkills.ts to see how Effect, Option, Result, and the process modules are being used. I'm checking whether the named imports from effect/unstable/process violate the namespace import convention, and whether the environment parameter in discoverGrokSkills represents a hidden dependency similar to the existing checkGrokProviderStatus pattern. I'm also scanning the test file's use of ChildProcessSpawner and the XAiAcpExtension's error handling to see if they follow existing conventions in the repo. That import style matches the repo-wide standard, so that's fine. The default parameter referencing the module-level process.env mirrors what the sibling checkGrokProviderStatus function does, so I want to check how other skill discovery functions, like the Claude skills discovery one, handle this for consistency. I'm checking the GrokAdapter and XAiAcpExtension changes, noting they reuse an existing AcpRequestError class from effect-acp rather than defining a new tagged error, which seems acceptable since the rate limit error doesn't need to preserve an underlying cause. Now I'm looking at how UsageService imports its dependencies. I want to verify whether using NodeOS.homedir() directly for the .grok config path matches how the claude and codex directories are resolved elsewhere in the codebase. I should check whether NodeOS is already imported in UsageService, since it's likely used elsewhere in the file. I notice a discrepancy between what I saw earlier and this grep result — the line I'm looking at now uses a different override mechanism than the grokHomeEnv logic I viewed before, so I need to reconcile which version is actually current in the file. That grep line was likely stale, so I'll trust the actual file view instead. Since this PR is feature work rather than a service refactor, I'm checking it against review conventions: there don't seem to be new service definitions since GrokSkills is just plain functions, and errors are handled via the existing AcpRequestError pattern rather than new error classes. Now I want to check the touched files for Layer.succeed, ManagedRuntime.make, and runPromise usage across GrokAdapter, GrokProvider, GrokDriver, GrokSkills, AcpRuntimeModel, AcpSessionRuntime, GrokAcpSupport, XAiAcpExtension, GrokTextGeneration, UsageService, and the usage/web/mobile files — let me grep for those patterns. Those consolidated imports aren't in any touched files, which is good. Now I'm checking whether the diff introduces actual convention violations, looking through GrokAdapter.ts and GrokProvider.ts to see if their factory functions and status checks follow existing patterns. The added cwd param flows cleanly from ServerConfig into checkGrokProviderStatus, which seems fine since it's just passing a configuration value. I'm also checking AcpSessionRuntime.ts, where a new optional meta field was added to the setSessionModel interface — that's a minor addition to an existing Context.Service and shouldn't be an issue. Now I'm looking at XAiAcpExtension.ts, where new helper functions read environment variables and platform info directly rather than going through the existing HostProcessEnvironment and HostProcessPlatform services used elsewhere in the codebase — this could be a violation of the convention against hiding dependencies in module-level globals or closures over singleton services. I'm weighing whether this is a real violation worth flagging, since these are plain helper functions rather than Effect services, and the review guidance says not to demand unrelated repo-wide cleanup or flag things outside the PR's changed scope. I want to check whether there's existing precedent in the repo for reading process.env directly outside of the HostProcessEnvironment service before deciding how to call this out. Since other non-test files already read process.env directly, this isn't an unusual violation worth flagging, especially since it's a pure helper rather than a service. I should focus on what's more likely the intended finding for this PR—checking Effect Service Conventions, I want to look at how the new error is constructed in the XAiAcpExtension file. Checking through the rest: the rate-limited error creation looks fine without a cause since there's no underlying failure, the static factory usage for internal errors follows conventions, and the watchdog's catch-all error handling seems appropriate since it's intentionally meant to prevent the fiber from crashing. I want to grep the touched files for catchTag, Schema.is, Schema.Defect, and TaggedError usage to be thorough. This PR doesn't introduce anything new around errors, so I'm checking whether there's a genuine violation by scanning the GrokAdapter diff more closely, looking at the session runtime's model-setting interface and other provider-related pieces for anything problematic. Going through the remaining imports, they all look like allowed patterns: named imports for pure helpers from shared subpaths, namespace imports for effect modules, and contract types pulled in explicitly. The one thing that catches my eye is UsageService importing HostProcessEnvironment as a named import rather than a namespace import, which seems like it might deserve a closer look since it's a service tag. The named import pattern seems established. I'm noticing there's an oxlint rule against global process runtime access, which could flag process.env reads like the one in XAiAcpExtension—worth checking if that rule relates to hiding dependencies in module globals, even though it's outside the scope of the Effect service convention check. I notice the new code in XAiAcpExtension.ts checks process.platform directly twice to handle case-insensitive comparisons on Windows, which directly violates the repo's own lint rule banning raw platform checks in favor of the HostProcessPlatform service. This is a concrete introduced violation within scope. I should verify the actual head file content for those lines to confirm. I've confirmed process.platform is used directly in production server code, which should be banned by the repo's lint rule favoring HostProcessPlatform injection. That's odd since CI should catch this, so I want to check whether the file is excluded in the oxlint config and scan for other non-test source files using process.platform directly. I've confirmed that t3code/no-global-process-runtime is an error-level rule, and the only unsuppressed violations in the repo are the two new lines in XAiAcpExtension.ts from this PR—the runtime platform needs to come from HostProcessPlatform rather than the module global. I also notice isGrokPlanMarkdownPath is a plain function rather than Effect-based, which affects how I need to fix this. Properly fixing this requires threading the platform through, since the caller extractGrokPlanMarkdownFromToolCallData is invoked from GrokAdapter in an Effect context—I'll suggest accepting platform as a parameter or reading it from HostProcessPlatform in the Effect caller, flagged as a comment rather than an inline suggestion since it spans multiple hunks/files. I'm also noticing grokPlanSessionPrefixes() reads process.env directly while UsageService in this same PR correctly uses HostProcessEnvironment for GROK_HOME—an inconsistency within the PR itself that reinforces the same underlying issue, even though the lint rule itself only covers platform/arch, not env vars. I'll fold this into the same comment as a secondary point alongside the primary platform finding. Let me check a few other things: the mutable closure for sessionAllowAll in GrokAdapter.ts looks like a behavior concern rather than a convention issue, the meta type change in AcpSessionRuntime using EffectAcpSchema.SetSessionModelRequest["_meta"] looks fine, and recordTurnActivity's use of Effect.fn with try/finally around yields seems fine too. I want to verify whether discoverGrokSkills's Effect.fn.Return typing correctly declares its error and requirement types, since resolveSpawnCommand might need more context than just ChildProcessSpawner—I should check its signature to be sure. I'm noting that resolveSpawnCommand relies on HostProcessPlatform, a Context.Reference with a default value, so it can be accessed via yield* anywhere without needing to provide it explicitly since references with defaults don't add to the requirements type. This points toward how to fix the XAiAcp issue. For extending isGrokPlanMarkdownPath, I'm considering either passing platform/env as parameters or converting it to an Effect that pulls from HostProcessPlatform. Since extractGrokPlanMarkdownFromToolCallData is already called within an Effect.gen block in GrokAdapter, making it Effect-based seems feasible but would touch multiple places, so I'll flag it with a no-diff comment instead. I want to check hostProcess.ts to confirm HostProcessPlatform is indeed set up as a Reference. There's an isHostWindows helper confirming this pattern. My main finding is a concrete violation: direct process.platform reads in XAiAcpExtension.ts bypass the repo's injected HostProcessPlatform convention, which the lint rule enforces as an error. I'm also considering whether to flag the similar process.env.HOME/USERPROFILE/GROK_HOME usage in grokPlanSessionPrefixes() since it falls under the same convention family. I'm weighing whether to combine these into one inline comment or split them — since they're in neighboring code and share the same fix (threading HostProcessPlatform/HostProcessEnvironment from the caller), I'll anchor a single comment at the platform lines and mention the env reads there too, to avoid noise from duplicate comments. I just need to confirm these lines are actually part of the diff so the inline comment position is valid. This is a clear violation of the repo's rule against hiding runtime dependencies in module globals within Effect code, so I'm setting the check result to failure and writing up the single inline comment before posting the review.

1. modify_pr — One convention issue found: new host-runtime reads in apps/server/src/provider/acp/XAiAcpExtension.ts bypass the injected HostProcess* references that this repo requires in Effect code.


Agent Credits: 239 credits