Repository navigation
Effect Service Conventions: 1 issue found
apps/server/src/cli/app.ts — desktopAppCommandError is a stringly-typed error factory: it wraps a message in a manufactured Error as the cause of an untagged CliError.UserError, collapsing four semantically distinct failures (SSH session, unsupported platform, desktop unreachable, desktop-reported failure) into one error with the message as its only data. Available structural context (platform, socket address, the desktop response code) is discarded. Sibling CLI modules (cli/pair.ts, cli/theme.ts, cli/project.ts) declare one Schema.TaggedErrorClass per failure with structured attributes and a message derived from them.
Previously flagged items are resolved on this head: make is now exported from DesktopAppActivation.ts, the uid comes from HostProcessUserId in the Effect environment, and the socket failure is preserved as cause in the CLI reachability error.
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.
Files examined in scope: apps/desktop/src/app/DesktopAppActivation.ts, DesktopAppActivationBroker.ts, apps/desktop/src/app/DesktopApp.ts, apps/desktop/src/ipc/{DesktopIpcHandlers,channels,methods/appActivation}.ts, apps/desktop/src/main.ts, apps/desktop/src/preload.ts, apps/server/src/{bin,cli/app}.ts, apps/web/src/desktopAppActivation.ts, apps/web/src/components/desktop/DesktopAppActivationCoordinator.tsx, apps/web/src/state/entities.ts, packages/contracts/src/desktopAppActivation.ts, packages/shared/src/desktopAppControl.ts, plus the new tests.
Checked and considered acceptable:
DesktopAppActivationfollows the tag /make/layershape with an inline service interface, subpath namespace imports for Effect modules, and namespace imports for local service modules (ElectronWindow,DesktopWindow,DesktopEnvironment); consumers (main.ts,ipc/methods/appActivation.ts) use the module namespace.Effect.runPromiseWith(yield* Effect.context<never>())inmakebridges Electron/Node imperative callbacks and matches the existing desktop pattern (DesktopWindow.ts,DesktopClerk.ts,DesktopIpc.ts,DesktopApplicationMenu.ts); the broker it feeds is not an Effect service.startDesktopAppControlServerandDesktopAppActivationBrokerreceive callbacks and pure config, not service instances, so this is a callback strategy rather than fake dependency injection; the test seam passes only callbacks.DesktopAppActivationStartErrorusesSchema.TaggedErrorClasswithaddressplus a realcause, and derivesmessagefromaddress.Effect.catchinDesktopApp.tsintentionally handles the whole error channel at the bootstrap boundary.packages/shared/src/desktopAppControl.tsandapps/web/src/desktopAppActivation.tsare pure helper modules, so named imports are appropriate.
🔍 Agent activity — 13 tool calls
💭 The three previously flagged issues at f5f18e2 look resolved now at a4a86ca—the export, HostProcessUserId usage, and desktopAppCommandError with cause are all in place. I'm now checking the current diff for new violations, starting with the DesktopAppActivation.ts file's use of Context.Service, make, and layer ordering. Looking closer, the tag declaration appears after a large async function rather than following the canonical ordering, though this may just be file layout preference. I'm also flagging a potential concern with
Effect.runPromiseWithbeing used inside the service constructor to bridge into an imperative broker callback—this touches the runtime boundary rule about keeping runPromise-style calls out of service constructors, though it could be a legitimate adapter boundary since the broker callbacks come from Node/Electron's imperative layer. I want to check if there's an existing repo pattern for this kind of bridging before deciding whether to flag it. The tagged error class definition forDesktopAppActivationStartErrorlooks fine. Now I'm examining a helper functiondesktopAppCommandErrorin the CLI app that wraps a message into an Error and constructs aCliError.UserError—checking whether this counts as a prohibited "error factory" helper or whether it does enough real construction work to be legitimate, since it's used in four places and actually builds an Error object rather than just forwarding arguments. I'm also verifying thatisDesktopAppActivationRequestisn't wrapped in a redundant function—it's just an inline schema predicate, so that's fine. Then I move through the exports inpackages/contracts/src/index.ts, which look fine, and the React components inapps/web, which aren't Effect services. I land onwaitForProjectinapps/web/src/state/entities.ts, noting it's an imperative promise with a registry subscription. Now I'm checking imports inDesktopAppActivation.ts—a named import ofHostProcessUserIdas a service tag is allowed but not required to use namespace import, andresolveDesktopAppControlAddressis a pure helper import so it's fine. I'm also noting the named import ofDesktopAppActivationBroker. TheEffect.catchhandler in DesktopApp.ts that logs startup errors looks appropriate since the whole error channel is intentionally handled there. Now I want to verify the current head state of these files against the prior run and check repo conventions around CliError.UserError and runPromiseWith before drawing conclusions.
1. browse_code — apps/desktop/src/app/DesktopAppActivation.ts
2. browse_code — apps/server/src/cli/app.ts
💭 With the prior findings addressed, I want to check remaining potential issues—how other CLI commands construct CliError.UserError in this repo, and whether Effect.runPromiseWith inside a service's make function appears elsewhere in the desktop services.
3. git_tools — CliError.UserError
4. git_tools — runPromiseWith|ManagedRuntime.make|runPromiseExit
💭 I'm confirming that
Effect.runPromiseWithin service constructors fits an existing repo pattern for Electron callback boundaries, so it's not a concern. Then I'm checking how bin.ts wraps user errors withCliError.UserError, considering whether this wrapping constitutes a trivial pass-through helper that the rule against thin error-wrapping functions would flag—it seems like it does more than just forward arguments since it wraps a cause error with a message and options.
5. browse_code — apps/server/src/bin.ts
6. git_tools — UserError
💭 The helper wraps a message into an Error with cause chaining for CliError.UserError, which is legitimate behavior rather than a pointless wrapper, so I won't flag it—especially since the prior discarding-cause issue was already fixed. Now I want to check how other CLI commands handle errors. cli/project.ts might reveal a shared pattern, and if there's already a helper elsewhere like cli/errors.ts that this PR duplicated, that's worth flagging, so I'll grep for it.
7. git_tools — Effect.fail(new (CliError|.*Error)
8. git_tools — TaggedErrorClass
💭 I'm noticing that app.ts breaks from the repo's convention of using Schema.TaggedErrorClass with structured attributes—instead it collapses four distinct failure modes (SSH unsupported, unsupported platform, desktop unreachable, desktop failure) into one generic stringly-typed error helper, losing the type safety and semantic distinction the other files maintain. This does seem worth flagging: the unsupported-platform error should carry a
platformattribute, the SSH error is really a validation case, and the desktop-unreachable error should carryaddressandcauserather than a flat message. I want to verify whether domain errors from pair.ts and theme.ts surface directly to the CLI or get mapped intoCliError.UserErrorsomewhere, since that would confirm whether app.ts is breaking an established pattern — let me check how pair.ts's handler fails around line 71.
9. browse_code — apps/server/src/cli/pair.ts
💭 This confirms the repo's convention is to use Schema.TaggedErrorClass with structured attributes for per-failure errors, even in CLI modules, whereas the new app.ts relies on a stringly-typed helper instead. This is a genuine deviation worth flagging under the errors and predicates guidance. I'm weighing whether this overlaps with an already-flagged comment about a discarded cause on the same code, but this is a distinct issue about error modeling rather than cause propagation, so raising it separately feels justified. Technically these are CLI handler errors rather than strict "service failures," but since the repo already applies this convention broadly to other CLI commands, I'll surface it as a suggestion-style comment without a diff since it spans multiple hunks. Now I'm scanning for other candidates: whether
DesktopAppActivation.tsdeviates from the canonical file ordering (errors, tag, make, layer) since adapter helper functions sit between the error declarations and the tag, and checkingDesktopWindow.tsfor comparison; confirming the IPC method file andmain.tscorrectly use namespace imports for the activation layer; and starting to look at files underapps/web/src. Everything else looks fine — the React coordinator component doesn't involve an Effect service, the shared desktop app control helper is a plain module,waitForProjectuses ordinary Promises and throws a plain Error consistent with web-layer conventions, the service interface correctly requires a Scope, and the broker class intentionally uses an imperative callback pattern, which is an allowed strategy. I'm now checking DesktopWindow.ts's ordering to decide whether I need to flag a layout issue in DesktopAppActivation.ts.
10. git_tools — ^(export class|export const make|export const layer|class|function|export function|export async function|const { log)
11. git_tools — ^(export class|export const make|export const layer|const { log|export async function|async function)
💭 I notice DesktopAppActivation places helpers before the tag while DesktopWindow puts them after — a minor ordering inconsistency, but since it's just a style preference rather than a violation of the canonical structure, it's not worth flagging as a real issue. Checking other files: the desktop error class uses a simple defect schema with an address field, and the web layer's activation file uses plain object constructors without Effect, which seems appropriate for a plain TypeScript context. Now I want to verify how the CLI's project command surfaces these domain errors — whether they get mapped to a user-facing error type or just print as raw stack traces, since that would tell me if UserError was an intentional choice.
12. git_tools — Command.withHandler|catchTags|CliError|Effect.fail
💭 I'm noticing that other CLI commands use tagged domain errors rather than the stringly-typed UserError pattern app.ts introduces, so I'll flag lines 34-36 recommending structured tagged error classes consistent with pair.ts/theme.ts, while noting the existing tests checking
_tag: "UserError"would need updating too—so I won't propose an inline fix directly. I also want to point out thatdesktopAppCommandError(response.message)drops the structural failure code from the desktop response and only keeps the message string, which is worth mentioning as context that gets lost. I'll consolidate these into a single concise comment targeting the diff line, then check whether DesktopAppActivation's error handling in DesktopApp.ts is using catch patterns consistent with the rest of the codebase. Weighing whether to mark this review as a failure or a pass, I lean toward failure since I'm posting a genuine finding that matches an explicit repo convention rather than a stylistic preference, even though the general bias should be toward success absent clear violations.
13. modify_pr — One finding on the new t3 app CLI error modeling. The earlier comments on DesktopAppActivation.make/HostProcessUserId and the discarded socket cause are resolved.
Agent Credits: 106 credits
Token usage: 18 uncached input · 545,542 cache-read input · 78,903 cache-write input · 9,680 output
Agent Credits may also include non-token charges from external tools such as web research.