Expose project provider skills in chat#3982
herever cause.message. Detis the actI-pattern.'ve identified. Let me verify there are no other similar issues by checking the broader error and confirm my understanding is right.
Message copies from cause into a detail
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.
I'll submit the review. Simconfident about the one finding. Let me submit it.enteredThe rest looks conventions-compliant.]
🔍 Agent activity — reasoning, no tool calls
💭 I'm examining the diff to see how it aligns with the Effect service conventions, starting with the key files that were added or modified: the new GrokSkillDiscovery module, refactored probe function in CodexProvider, listSkills options in GrokAdapter, registry updates, and error classes in the contracts. Let me check the implementation details against the established patterns. Checking how the
detailfield is used in error cases to ensure it's not just copyingcause.message... all the detail strings are static descriptions tied to each operation type, which aligns with the convention. The error class uses a single service-level error with a multi-valueoperationdiscriminator rather than creating separate error classes for each case. The message template uses operation as a discriminator but doesn't switch on it to select different user-facing messages, so this follows the pattern of a single service-level error with a multi-value operation discriminator. Now I'm looking at theparseGrokInspectSkillsfunction... The CodexProvider'sprobeCodexAppServerProvideris exported and uses Effect.fn, which is fine. In the GrokAdapter'ssendTurnmethod, I'm seeing error handling that wraps failures into a ProviderAdapterRequestError with the provider name, method, and a descriptive detail message about failing to resolve Grok skill references. Now looking at GrokDriver's error handling, it's mapping errors into a ProviderDriverError where the detail field is being set directly tocause.message. This looks like it might violate the convention against copying cause.message into detail — I need to check whether ProviderDriverError's message getter derives from the detail field, which would make this redundant. Comparing with CodexDriver's approach, it's interpolating cause.message into detail with a descriptive prefix like "Failed to list Codex skills". This is a more common pattern in the codebase, but I should examine how ProviderDriverError actually uses these fields to determine if either approach is problematic. I'm wrapping errors from GrokSkillDiscoveryError into ProviderDriverError by extracting the cause's message as the detail field, preserving the structured error information through the transformation. The key difference is that Codex wraps the message with context ("Failed to list Codex skills: "), while Grok just copies it directly—that's the anti-pattern the convention flags. Since the cause is already preserved separately, duplicating its message into detail is redundant and violates the guideline. I should check the exact GrokDriver code to pinpoint where this happens. I'm noticing that GrokDriver's listSkills is wrapping the error in an anti-pattern way—it just copies the cause message into the detail field rather than adding meaningful context. The other error wrappers do this better, like the one at line 169 that prefixes with "Failed to build Grok snapshot:" or CodexDriver's approach with "Failed to list Codex skills:". Line 125 needs to follow that same pattern. The convention explicitly flags "merely copies" as the anti-pattern, so adding descriptive context aroundcause.messageis acceptable. This is a legitimate violation worth flagging as an inline comment since it matches the named anti-pattern, even if it's somewhat borderline. Now I'm checking whether thedetailfield inGrokSkillDiscoveryErroris redundant with theoperationfield, since the message already incorporates both. Thedetailfield provides sub-context within each operation value, so it's not just copying the cause message—it's adding meaningful context. The operation discriminator drives message selection for the caller, and since these errors share the same semantics (skill discovery failure), they don't need separate error classes. I'm also verifying that the details don't leak unsafe content like command output or arguments, and they don't—they're static strings and safe exit codes. Now I'm checking the imports across the touched files and confirming thatprobeCodexAppServerProvideris properly exported from CodexProvider for use in CodexDriver. I'm also searching for other instances of thedetail: cause.messagepattern to see if this is an isolated case or part of a broader pattern, and reviewing whether it truly violates the convention about not copying cause.message into a detail field that's then used to construct the wrapper message. The GrokDriver case is a clear violation — the detail field directly copies cause.message, and that same message gets repeated in the wrapper. The fix would be to add contextual framing like a prefix to the cause message, which provides reusable context rather than just duplicating it. I'll add an inline suggestion to replace that line with a template string that prefixes the cause message with "Failed to list Grok skills: ", matching the pattern used elsewhere in CodexDriver. This is a straightforward fix that warrants failing the check. I'm ready to submit the review with an inline comment included.