Skip to content

feat: add Pi provider integration via RPC

MacroscopeApp / Macroscope - Effect Service Conventions failed Jul 23, 2026 in 3m 3s

Effect Service Conventions: 1 issue found

Found 1 convention violation in the changed scope.

  • apps/server/src/textGeneration/PiTextGeneration.ts (line 142): recovers the known SchemaError tagged failure with Effect.catchTag. The conventions require Effect.catchTags({ ... }) for statically known tagged failures, including single-tag recovery. Every sibling text-generation implementation (CursorTextGeneration.ts, ClaudeTextGeneration.ts, GrokTextGeneration.ts, CodexTextGeneration.ts, etc.) already uses catchTags for this same SchemaError mapping, so this is both a convention violation and an inconsistency. An inline suggestion with the fix was posted.

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: new/changed TypeScript for the Pi provider (drivers, adapters, RPC client, provider snapshot, text generation, contracts settings/runtime).

Items checked and found compliant:

  • Effect module imports use subpath namespaces (import * as Effect from "effect/Effect", etc.); @t3tools/contracts correctly kept as named imports.
  • Services/PiAdapter.ts follows the established adapter-shape anchor pattern used by CursorAdapter.ts/OpenCodeAdapter.ts (not a Context.Service), so the FooShape guidance does not apply.
  • makePiAdapter / makePiTextGeneration acquire dependencies from the environment (yield* ServerConfig, yield* ChildProcessSpawner.ChildProcessSpawner, yield* FileSystem.FileSystem, yield* Crypto.Crypto); the makeTransport override is a legitimate test seam. No ManagedRuntime.make, .runPromise, Layer.succeed, or hidden runtimes introduced.
  • Errors use existing Schema.TaggedErrorClass types with structured attributes and preserve real cause; PiTextGeneration correctly passes through existing TextGenerationError at the translation boundary and uses Schema.is(TextGenerationError).
  • The detail: "Failed to build Pi snapshot: ...cause.message..." construction in PiDriver.ts mirrors the identical idiom in all eight other drivers (Codex, Claude, Cursor, Grok, OpenCode, Copilot, Kiro, OpenRouter); not flagged to avoid demanding a repository-wide change that would leave Pi inconsistent with its family.

Only concrete violation: Effect.catchTag in PiTextGeneration.ts.


🔍 Agent activity — 1 tool call

💭 Looking at the PR structure for the Pi provider implementation, I need to examine how it follows the Effect service conventions across the adapter interface, layer implementations, RPC client, and driver files. Checking the PiAdapterShape interface—it extends ProviderAdapterShape which is an existing pattern used by other adapters like Cursor. The convention warns against standalone FooShape interfaces, but this follows the established codebase pattern where all adapters use a Shape convention, so I need to determine if this is a violation specific to this PR or just consistent with existing code. Looking at the imports in the driver files, they're using namespaced imports from effect modules like Deferred, Effect, Crypto, and Duration, which aligns with the convention. For error handling, the PR constructs errors like TextGenerationError with an operation discriminator and a detail field that contains descriptive strings rather than copying the cause message directly, which follows the established pattern. Looking at dependency acquisition, both makePiAdapter and makePiTextGeneration properly yield from the environment to get their required services like ServerConfig, Crypto, ChildProcessSpawner, and FileSystem. The options?.makeTransport parameter is being examined next. I'm seeing a violation of the error handling convention here — the detail field is copying cause.message directly into the string, which violates the rule against embedding the cause's message into structural fields. The wrapper's message should derive only from stable structural attributes, not from the cause itself. Now I need to check if this pattern is consistent with how other drivers in the codebase construct ProviderDriverError, since the convention only flags violations introduced or retained in the PR's changed scope. Let me look at existing drivers like OpenCodeDriver to see if this is an established pattern or something new. I need to correct the function call. I need to adjust the URL parameter formatting to use proper JSON structure instead of the nested format I tried before. Looking at how the PiDriver handles errors, it's wrapping the cause message into the detail field when building snapshots fail, following the established pattern for error construction. But the convention explicitly warns against this—detail shouldn't just copy cause.message, and the wrapper's message should derive only from stable structural attributes, not from the underlying cause. The cause itself should be preserved separately. This looks like it might be an anti-pattern that's already in place, so I should check how other drivers like OpenCodeDriver or ClaudeDriver handle this to see if it's a widespread issue or a newly introduced violation. The PiDriver follows the same pattern as all the other drivers in the codebase, so flagging this would be asking for repository-wide cleanup rather than addressing a concrete issue in the pull request's scope. Now I'm examining the actual service definitions in PiAdapter.ts and comparing the Layers pattern against how other adapters like Cursor handle their shapes to see if there are any genuine convention violations. PiAdapter.ts follows the CursorAdapterShape pattern correctly as a Services adapter, not a Context.Service, which aligns with the codebase conventions and the FooShape naming pattern for driver bundle anchors. Now I'm looking at the Effect service conventions in the new code, particularly around driver and adapter patterns. Since this PR mirrors the existing Cursor/OpenCode driver, adapter, and provider structure, most conventions are already consistent. I'm checking the error handling in PiRpcClient which uses Effect.Effect<void> with Effect.ignore — that's appropriate. The makePiRpcTransport doesn't declare errors, which is fine. PiProvider.ts uses Effect.fn and Effect.catchCause correctly. Looking at PiTextGeneration, the error handling translates boundaries properly by passing through existing TextGenerationError instances while wrapping unknown errors into the domain error type — this follows the right pattern for structured error handling. But I'm spotting a genuine convention violation: the code uses Effect.catchTag("SchemaError", ...) instead of the preferred Effect.catchTags({ SchemaError: ... }) pattern. The convention explicitly states to use catchTags with an object for statically known tagged failures, even when handling just one tag, and to avoid catchTag entirely. I need to check whether other TextGeneration implementations in the codebase follow the same pattern with catchTag to determine if this is actually a violation or just consistent with the existing convention. I'm noticing the new implementation uses a different error handling pattern than all the other TextGeneration variants—it's calling Effect.catchTag for individual errors instead of Effect.catchTags with a grouped object, which breaks the established convention. I should check how the sibling implementations handle this to provide the right fix. I'm spotting an inconsistency in error handling patterns between the two files—CursorTextGeneration.ts uses Effect.catchTags with multiple error handlers while PiTextGeneration.ts switches to Effect.catchTag for a single error, which breaks the established convention in the codebase. Looking at where this happens in the new file with the schema decoding logic. Line 142 is using Effect.catchTag, which violates the established convention. Looking at the TextGenerationShape pattern, it's actually consistent with how the sibling implementations handle it—they all reference it the same way through TextGenerationShape["generateCommitMessage"], so that's not an issue. Let me scan through the new provider files to see if there are any other catchTag or catchIf violations I should flag. The only concrete violation I've found is the Effect.catchTag in PiTextGeneration.ts line 142 — it's a genuine convention breach that was introduced in the changed code and stands out as inconsistent with the rest of the codebase. I'm preparing an inline suggestion to replace it with Effect.catchTags using the proper object syntax, which will align it with the established pattern across all sibling implementations. Writing the catchTags replacement...

1. modify_pr — Effect Service Conventions: one issue found. PiTextGeneration.ts recovers a known tagged failure with Effect.catchTag, which the conventions disallow (and which diverges from every sibling text-generation implementation that uses Effect.catchTags).

💭 I need to generate the final JSON result for the check-run, marking it as a failure and including the appropriate title and summary.


Agent Credits: 208 credits