Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
210 commits
Select commit Hold shift + click to select a range
4827214
Add Effect lint skills and diagnostics
RhysSullivan May 5, 2026
9a2afe8
Use Effect resource cleanup in schema test
RhysSullivan May 5, 2026
62de4e0
Scope Effect lint rules away from boundaries
RhysSullivan May 5, 2026
269f029
Add JSON parse schema boundary lint
RhysSullivan May 6, 2026
10d34f8
Add redundant primitive cast lint
RhysSullivan May 6, 2026
0bbd756
Clean up core OAuth discovery errors
RhysSullivan May 6, 2026
573ed37
Clean up MCP invocation boundaries
RhysSullivan May 6, 2026
0fab457
Clean up MCP manifest option handling
RhysSullivan May 6, 2026
ea3d682
Clean up MCP connection error messages
RhysSullivan May 6, 2026
253b011
Clean up execution engine tagged checks
RhysSullivan May 6, 2026
427d4e2
Ban Effect escape hatches
RhysSullivan May 6, 2026
fe37cf1
Use Effect assertions in connection tests
RhysSullivan May 6, 2026
b039b6e
Ban unsupported Effect APIs
RhysSullivan May 6, 2026
5393959
Use typed assertions in policy code
RhysSullivan May 6, 2026
74119c1
Use typed failures in OpenAPI multi-scope tests
RhysSullivan May 6, 2026
f9da4f3
Use typed boundaries in cloud MCP e2e
RhysSullivan May 6, 2026
1d616f6
Use typed keychain failures
RhysSullivan May 6, 2026
9c6a5c0
Use Effect assertions in executor tests
RhysSullivan May 6, 2026
83554b7
Keep tool invoker failures typed
RhysSullivan May 6, 2026
2cae07e
Use Effect assertions in OpenAPI plugin tests
RhysSullivan May 6, 2026
ff6dbd3
Use typed OAuth API boundaries
RhysSullivan May 6, 2026
fdb0bcc
Document WorkOS Vault test error boundary
RhysSullivan May 6, 2026
cf41ce1
Use typed boundaries in MCP OAuth tests
RhysSullivan May 6, 2026
33919dd
Use Effect boundaries in release smoke test
RhysSullivan May 6, 2026
cf3f937
Use promiseExit in GraphQL source UI
RhysSullivan May 6, 2026
c1c6430
Use Effect exit for local update check
RhysSullivan May 6, 2026
26475f9
Clarify shared UI and config boundaries
RhysSullivan May 6, 2026
15b056b
Use Effect cleanup in MCP worker transport
RhysSullivan May 6, 2026
f7e6ca4
Simplify tenant isolation assertions
RhysSullivan May 6, 2026
987638b
Use typed errors in postgres storage tests
RhysSullivan May 6, 2026
3e9f3d5
Clarify drizzle generator boundaries
RhysSullivan May 6, 2026
a02b3cc
Use stable blob store error messages
RhysSullivan May 6, 2026
b0d47df
Use inferred keychain extension type
RhysSullivan May 6, 2026
10308ec
Use typed config parse errors
RhysSullivan May 6, 2026
84e64a0
Parse plugin loader config with Schema
RhysSullivan May 6, 2026
58fbda2
Mark core boundary escape hatches
RhysSullivan May 6, 2026
85c78ab
Remove redundant OpenAPI credential casts
RhysSullivan May 6, 2026
4194ac6
Use typed OpenAPI OAuth test failures
RhysSullivan May 6, 2026
2445ee5
Use promiseExit in 1Password settings
RhysSullivan May 6, 2026
8fe0858
Clean daemon state test boundaries
RhysSullivan May 6, 2026
f157b80
Tighten MCP host test boundaries
RhysSullivan May 6, 2026
77e62f3
Clean OpenAPI invoke error handling
RhysSullivan May 6, 2026
868d4d4
Clean MCP probe shape boundaries
RhysSullivan May 6, 2026
d4dfc9d
Clean local server boundary cleanup
RhysSullivan May 6, 2026
4d96793
Parse MCP migration test config with Schema
RhysSullivan May 6, 2026
0545e1e
Clean cloud test worker boundaries
RhysSullivan May 6, 2026
586955b
Clean cloud service boundaries
RhysSullivan May 6, 2026
daa1763
Parse local migration test rows with Schema
RhysSullivan May 6, 2026
9f564b4
Use Effect timeouts in tool invoker tests
RhysSullivan May 6, 2026
976f585
Stabilize GraphQL extraction errors
RhysSullivan May 6, 2026
f534b9d
Clean cloud auth and org test failures
RhysSullivan May 6, 2026
46d1c24
Clean local server tooling boundaries
RhysSullivan May 6, 2026
ffc1374
Parse OpenAPI migration test rows with Schema
RhysSullivan May 6, 2026
3b01c46
Remove MCP cross-user redundant casts
RhysSullivan May 6, 2026
1e26fe2
Normalize WorkOS Vault errors
RhysSullivan May 6, 2026
d401d65
Clean cloud auth and Autumn boundaries
RhysSullivan May 6, 2026
78035f2
Clean local DB migration boundaries
RhysSullivan May 6, 2026
9812c24
Clean core API observability errors
RhysSullivan May 6, 2026
f2f8721
Mark JSON schema adapter boundaries
RhysSullivan May 6, 2026
432ae96
Clean plugin API handler tests
RhysSullivan May 6, 2026
9e84f99
Use a typed chart payload guard
RhysSullivan May 6, 2026
c61c7f0
Fix storage typed boundary lint
RhysSullivan May 6, 2026
110adf1
Parse GraphQL store rows with Schema
RhysSullivan May 6, 2026
de48f2d
Fix Google Discovery SDK test boundaries
RhysSullivan May 6, 2026
1858ea2
Use promiseExit in source UI boundaries
RhysSullivan May 6, 2026
70d01de
Fix core OAuth typed boundaries
RhysSullivan May 6, 2026
23439e6
Use promiseExit in OAuth popup flow
RhysSullivan May 6, 2026
89bc9c9
Fix storage test boundary lint
RhysSullivan May 6, 2026
4256b95
Fix OpenAPI plugin typed boundaries
RhysSullivan May 6, 2026
b91524b
Fix MCP SDK store and test boundaries
RhysSullivan May 6, 2026
418b096
Update OAuth refresh reauth assertion
RhysSullivan May 6, 2026
44315a8
Fix executor typed boundary lint
RhysSullivan May 6, 2026
fcae413
Fix cloud MCP boundary lint
RhysSullivan May 6, 2026
7130b7d
Fix GraphQL plugin boundary lint
RhysSullivan May 6, 2026
81e97c3
Fix OnePassword plugin boundary lint
RhysSullivan May 6, 2026
2aa25fb
Fix core OAuth boundary lint
RhysSullivan May 6, 2026
9494cb4
Fix OpenAPI boundary lint
RhysSullivan May 6, 2026
ed17ac4
Fix Google Discovery boundary lint
RhysSullivan May 6, 2026
9a04145
Fix MCP plugin boundary lint
RhysSullivan May 6, 2026
5ad3094
Fix local MCP host boundary lint
RhysSullivan May 6, 2026
707e5c2
Use typed WorkOS Vault plugin failures
RhysSullivan May 6, 2026
0b34498
Use schema guards for page tagged errors
RhysSullivan May 6, 2026
9352af4
Clean typed test boundary assertions
RhysSullivan May 6, 2026
71332e7
Keep config write failures typed
RhysSullivan May 6, 2026
a995f28
Normalize cloud startup boundaries
RhysSullivan May 6, 2026
ff422a5
Handle all-plugins entrypoint failures in Effect
RhysSullivan May 6, 2026
14060d6
Keep cloud API errors typed
RhysSullivan May 6, 2026
139dd5c
Validate cloud JWT boundaries with schema
RhysSullivan May 6, 2026
489f9f6
Parse file secrets with schema
RhysSullivan May 6, 2026
20c8ac6
Keep keychain boundaries typed
RhysSullivan May 6, 2026
b953a1f
Clean core API typed boundaries
RhysSullivan May 6, 2026
c403f48
Use Effect UI mutation boundaries
RhysSullivan May 6, 2026
025cdf6
Keep kernel core failures typed
RhysSullivan May 6, 2026
e9fd11a
Use schema in OpenAPI preview boundaries
RhysSullivan May 6, 2026
fcd022c
Clean SDK typed test boundaries
RhysSullivan May 6, 2026
e393aed
Mark local app runtime boundaries
RhysSullivan May 6, 2026
df6f374
Clean CLI and host test boundaries
RhysSullivan May 6, 2026
09e9ef6
Clean small package lint boundaries
RhysSullivan May 6, 2026
1476896
Clean remaining cloud lint boundaries
RhysSullivan May 6, 2026
719c5ea
Clean execution runtime lint boundaries
RhysSullivan May 6, 2026
6220d9f
Remove OpenAPI summary casts
RhysSullivan May 6, 2026
7656b2e
Clean MCP per-user auth test boundaries
RhysSullivan May 6, 2026
de10d6d
Use promiseExit in MCP edit source
RhysSullivan May 6, 2026
e8422d2
Document React scope context boundaries
RhysSullivan May 6, 2026
83b84eb
Use typed GraphQL invocation boundaries
RhysSullivan May 6, 2026
72e83f3
Use typed Google Discovery invocation boundaries
RhysSullivan May 6, 2026
8f91606
Add OpenAPI parse boundary tests
RhysSullivan May 6, 2026
dc75098
Merge remote-tracking branch 'origin/codex/effect-lint-cloud-db-schem…
RhysSullivan May 6, 2026
fbcc52b
Merge remote-tracking branch 'origin/codex/effect-lint-core-sdk-oauth…
RhysSullivan May 6, 2026
bec0b0a
Merge remote-tracking branch 'origin/codex/effect-lint-keychain-bound…
RhysSullivan May 6, 2026
4a99018
Merge remote-tracking branch 'origin/codex/effect-lint-mcp-invoke' in…
RhysSullivan May 6, 2026
2d588fc
Merge remote-tracking branch 'origin/codex/effect-lint-mcp-connection…
RhysSullivan May 6, 2026
b9a25b4
Merge remote-tracking branch 'origin/codex/effect-lint-mcp-manifest' …
RhysSullivan May 6, 2026
ed4a5d7
Merge remote-tracking branch 'origin/codex/effect-lint-execution-engi…
RhysSullivan May 6, 2026
f089a2d
Merge remote-tracking branch 'origin/codex/effect-lint-core-connectio…
RhysSullivan May 6, 2026
a92bfe2
Merge remote-tracking branch 'origin/codex/effect-lint-core-policies'…
RhysSullivan May 6, 2026
568373b
Merge remote-tracking branch 'origin/codex/effect-lint-openapi-multis…
RhysSullivan May 6, 2026
c318de5
Merge remote-tracking branch 'origin/codex/effect-lint-cloud-miniflar…
RhysSullivan May 6, 2026
88f874d
Merge remote-tracking branch 'origin/codex/effect-lint-core-executor-…
RhysSullivan May 6, 2026
60627a9
Merge remote-tracking branch 'origin/codex/effect-lint-execution-tool…
RhysSullivan May 6, 2026
eb2f5a4
Merge remote-tracking branch 'origin/codex/effect-lint-openapi-plugin…
RhysSullivan May 6, 2026
e03dd71
Merge remote-tracking branch 'origin/codex/effect-lint-core-api-oauth…
RhysSullivan May 6, 2026
33cce43
Merge remote-tracking branch 'origin/codex/effect-lint-workos-vault-t…
RhysSullivan May 6, 2026
9e61781
Merge remote-tracking branch 'origin/codex/effect-lint-mcp-oauth-test…
RhysSullivan May 6, 2026
75ec915
Merge remote-tracking branch 'origin/codex/effect-lint-release-smoke-…
RhysSullivan May 6, 2026
ab4880f
Merge remote-tracking branch 'origin/codex/effect-lint-graphql-react-…
RhysSullivan May 6, 2026
3ad5333
Merge remote-tracking branch 'origin/codex/effect-lint-local-shell-up…
RhysSullivan May 6, 2026
a8c4b45
Merge remote-tracking branch 'origin/codex/effect-lint-shared-boundar…
RhysSullivan May 6, 2026
85ff2a7
Merge remote-tracking branch 'origin/codex/effect-lint-cloud-mcp-work…
RhysSullivan May 6, 2026
282e7c6
Merge remote-tracking branch 'origin/codex/effect-lint-cloud-tenant-i…
RhysSullivan May 6, 2026
d56487f
Merge remote-tracking branch 'origin/codex/effect-lint-storage-postgr…
RhysSullivan May 6, 2026
28901d9
Merge remote-tracking branch 'origin/codex/effect-lint-cli-drizzle-ge…
RhysSullivan May 6, 2026
1a269ea
Merge remote-tracking branch 'origin/codex/effect-lint-blob-store-err…
RhysSullivan May 6, 2026
45f0734
Merge remote-tracking branch 'origin/codex/effect-lint-keychain-exten…
RhysSullivan May 6, 2026
d296179
Merge remote-tracking branch 'origin/codex/batch10-config-load-error'…
RhysSullivan May 6, 2026
ba6f976
Merge remote-tracking branch 'origin/codex/batch10-config-plugin-load…
RhysSullivan May 6, 2026
83e756b
Merge remote-tracking branch 'origin/codex/batch10-core-boundary-supp…
RhysSullivan May 6, 2026
a1200b1
Merge remote-tracking branch 'origin/codex/batch10-openapi-credential…
RhysSullivan May 6, 2026
86d576a
Merge remote-tracking branch 'origin/codex/batch10-openapi-oauth-test…
RhysSullivan May 6, 2026
9ff4452
Merge remote-tracking branch 'origin/codex/batch10-onepassword-promis…
RhysSullivan May 6, 2026
af548c5
Merge remote-tracking branch 'origin/codex/batch10-daemon-state-bound…
RhysSullivan May 6, 2026
d437854
Merge remote-tracking branch 'origin/codex/batch10-mcp-host-test-boun…
RhysSullivan May 6, 2026
402178c
Merge remote-tracking branch 'origin/codex/batch11-openapi-invoke-err…
RhysSullivan May 6, 2026
b6cb20a
Merge remote-tracking branch 'origin/codex/batch11-mcp-probe-shape-bo…
RhysSullivan May 6, 2026
0237029
Merge remote-tracking branch 'origin/codex/batch11-local-server-bound…
RhysSullivan May 6, 2026
73f312b
Merge remote-tracking branch 'origin/codex/batch11-local-mcp-migratio…
RhysSullivan May 6, 2026
d9ba70c
Merge remote-tracking branch 'origin/codex/batch11-cloud-test-worker-…
RhysSullivan May 6, 2026
a38c46f
Merge remote-tracking branch 'origin/codex/batch12-cloud-service-boun…
RhysSullivan May 6, 2026
fe94822
Merge remote-tracking branch 'origin/codex/batch12-local-migration-sc…
RhysSullivan May 6, 2026
501aabf
Merge remote-tracking branch 'origin/codex/batch12-tool-invoker-timeo…
RhysSullivan May 6, 2026
a81992a
Merge remote-tracking branch 'origin/codex/batch12-graphql-extract-er…
RhysSullivan May 6, 2026
4cc98a6
Merge remote-tracking branch 'origin/codex/batch13-cloud-auth-org-tes…
RhysSullivan May 6, 2026
5b49a1e
Merge remote-tracking branch 'origin/codex/batch13-local-server-tooli…
RhysSullivan May 6, 2026
a41dd4c
Merge remote-tracking branch 'origin/codex/batch13-local-openapi-migr…
RhysSullivan May 6, 2026
f8e48b1
Merge remote-tracking branch 'origin/codex/batch13-mcp-cross-user-cas…
RhysSullivan May 6, 2026
1468797
Merge remote-tracking branch 'origin/codex/batch13-workos-vault-error…
RhysSullivan May 6, 2026
d8abc3d
Merge remote-tracking branch 'origin/codex/batch14-cloud-auth-autumn-…
RhysSullivan May 6, 2026
6a9df08
Merge remote-tracking branch 'origin/codex/batch14-local-db-migrate-c…
RhysSullivan May 6, 2026
4dd070c
Merge remote-tracking branch 'origin/codex/batch14-core-api-observabi…
RhysSullivan May 6, 2026
7dcf5de
Merge remote-tracking branch 'origin/codex/batch14-kernel-json-schema…
RhysSullivan May 6, 2026
9b540fd
Merge remote-tracking branch 'origin/codex/batch14-plugin-api-handler…
RhysSullivan May 6, 2026
abe685b
Merge remote-tracking branch 'origin/codex/batch14-react-chart-payloa…
RhysSullivan May 6, 2026
e609843
Merge remote-tracking branch 'origin/codex/batch15-storage-typed-boun…
RhysSullivan May 6, 2026
635056c
Merge remote-tracking branch 'origin/codex/batch15-graphql-schema-tes…
RhysSullivan May 6, 2026
e9a58c1
Merge remote-tracking branch 'origin/codex/batch15-google-discovery-t…
RhysSullivan May 6, 2026
5d78d34
Merge remote-tracking branch 'origin/codex/batch15-ui-promise-exit-bo…
RhysSullivan May 6, 2026
e5b1196
Merge remote-tracking branch 'origin/codex/batch16-core-oauth-boundar…
RhysSullivan May 6, 2026
2745940
Merge remote-tracking branch 'origin/codex/batch16-react-oauth-popup-…
RhysSullivan May 6, 2026
d516810
Merge remote-tracking branch 'origin/codex/batch16-storage-test-bound…
RhysSullivan May 6, 2026
f887e4c
Merge remote-tracking branch 'origin/codex/batch16-openapi-plugin-bou…
RhysSullivan May 6, 2026
2c0751c
Merge remote-tracking branch 'origin/codex/split-openapi-parse-tests-…
RhysSullivan May 6, 2026
36b20f5
Merge remote-tracking branch 'origin/codex/batch16-mcp-sdk-test-bound…
RhysSullivan May 6, 2026
cd10e67
Merge remote-tracking branch 'origin/codex/batch17-core-executor-boun…
RhysSullivan May 6, 2026
3a85629
Merge remote-tracking branch 'origin/codex/batch17-cloud-mcp-boundari…
RhysSullivan May 6, 2026
0477d35
Merge remote-tracking branch 'origin/codex/batch17-graphql-plugin-bou…
RhysSullivan May 6, 2026
422a424
Merge remote-tracking branch 'origin/codex/batch17-onepassword-bounda…
RhysSullivan May 6, 2026
3f7841a
Merge remote-tracking branch 'origin/codex/batch18-core-oauth-boundar…
RhysSullivan May 6, 2026
7257c89
Merge remote-tracking branch 'origin/codex/batch18-openapi-boundaries…
RhysSullivan May 6, 2026
bb6490c
Merge remote-tracking branch 'origin/codex/batch18-google-discovery-b…
RhysSullivan May 6, 2026
4077874
Merge remote-tracking branch 'origin/codex/batch18-mcp-plugin-boundar…
RhysSullivan May 6, 2026
20ebf61
Merge remote-tracking branch 'origin/codex/batch18-local-host-mcp-bou…
RhysSullivan May 6, 2026
95464b7
Merge remote-tracking branch 'origin/codex/batch19-workos-vault-plugi…
RhysSullivan May 6, 2026
2488306
Merge remote-tracking branch 'origin/codex/batch19-react-tagged-error…
RhysSullivan May 6, 2026
5c899cc
Merge remote-tracking branch 'origin/codex/batch19-test-boundary-clea…
RhysSullivan May 6, 2026
bac06dd
Merge remote-tracking branch 'origin/codex/batch19-config-write-error…
RhysSullivan May 6, 2026
e851713
Merge remote-tracking branch 'origin/codex/batch19-cloud-startup-boun…
RhysSullivan May 6, 2026
86edf61
Merge remote-tracking branch 'origin/codex/batch19-all-plugins-entryp…
RhysSullivan May 6, 2026
2831e92
Merge remote-tracking branch 'origin/codex/batch20-cloud-api-error-bo…
RhysSullivan May 6, 2026
27ec18d
Merge remote-tracking branch 'origin/codex/batch20-cloud-jwt-boundari…
RhysSullivan May 6, 2026
db3ee82
Merge remote-tracking branch 'origin/codex/batch20-file-secrets-schem…
RhysSullivan May 6, 2026
33c2bd1
Merge remote-tracking branch 'origin/codex/batch20-keychain-boundarie…
RhysSullivan May 6, 2026
1423723
Merge remote-tracking branch 'origin/codex/batch20-core-api-boundarie…
RhysSullivan May 6, 2026
ed046ae
Merge remote-tracking branch 'origin/codex/batch20-react-ui-boundarie…
RhysSullivan May 6, 2026
23c5c4e
Merge remote-tracking branch 'origin/codex/batch21-kernel-core-bounda…
RhysSullivan May 6, 2026
995c396
Merge remote-tracking branch 'origin/codex/batch21-openapi-small-boun…
RhysSullivan May 6, 2026
1875c13
Merge remote-tracking branch 'origin/codex/batch21-sdk-test-boundarie…
RhysSullivan May 6, 2026
ad94c1d
Merge remote-tracking branch 'origin/codex/batch21-local-app-boundari…
RhysSullivan May 6, 2026
bd71269
Merge remote-tracking branch 'origin/codex/batch21-cli-host-test-boun…
RhysSullivan May 6, 2026
2b74de9
Merge remote-tracking branch 'origin/codex/batch21-small-package-boun…
RhysSullivan May 6, 2026
8673012
Merge remote-tracking branch 'origin/codex/batch22-cloud-remaining-bo…
RhysSullivan May 6, 2026
39cf6ac
Merge remote-tracking branch 'origin/codex/batch22-execution-runtime-…
RhysSullivan May 6, 2026
01234a3
Merge remote-tracking branch 'origin/codex/batch22-openapi-source-sum…
RhysSullivan May 6, 2026
6c44b34
Merge remote-tracking branch 'origin/codex/batch23-mcp-per-user-auth-…
RhysSullivan May 6, 2026
2194f3d
Merge remote-tracking branch 'origin/codex/split-mcp-edit-source-prom…
RhysSullivan May 6, 2026
ae26cdc
Merge remote-tracking branch 'origin/codex/split-react-scope-context-…
RhysSullivan May 6, 2026
944fd4e
Merge remote-tracking branch 'origin/codex/split-graphql-invoke-bound…
RhysSullivan May 6, 2026
911d156
Merge remote-tracking branch 'origin/codex/split-google-discovery-inv…
RhysSullivan May 6, 2026
eddcffc
Resolve OAuth refresh integration assertion
RhysSullivan May 6, 2026
8e18c36
Integrate Effect lint cleanups
RhysSullivan May 6, 2026
54c0545
Merge remote-tracking branch 'origin/main' into codex/effect-lint-bas…
RhysSullivan May 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .agents/skills/wrdn-effect-atom-reactivity-keys/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
name: wrdn-effect-atom-reactivity-keys
description: Add reactivityKeys to effect-atom write mutation calls. Use when lint flags a useAtomSet mutation call that mutates data without invalidation keys.
allowed-tools: Read Grep Glob Bash
---

Effect-atom write mutations must say which reads they invalidate.

## Fix Shape

- Find the `useAtomSet(...)` write mutation call.
- Add `reactivityKeys` to the mutation payload at the call site.
- Use the narrowest keys that cover the rows/lists affected by the write.
- Keep read-only probe/preview OAuth flows out of this pattern.
- If the mutation should update UI immediately, check whether `wrdn-effect-atom-optimistic` also applies.

## Good

```ts
await updateSource({
params: { scopeId, sourceId },
payload,
reactivityKeys: [["sources", scopeId]],
});
```
115 changes: 115 additions & 0 deletions .agents/skills/wrdn-effect-promise-exit/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
name: wrdn-effect-promise-exit
description: Replace React/effect-atom mutation handlers that use promise-mode plus try/catch with promiseExit and explicit Exit handling. Use when lint or review flags try/catch around useAtomSet mutation calls, especially UI handlers that set error/busy state after a failed mutation.
allowed-tools: Read Grep Glob Bash
---

You fix one pattern: a React handler awaits an effect-atom mutation in `mode: "promise"` and catches failures with `try/catch`.

The preferred UI boundary is `mode: "promiseExit"` plus `Exit.isFailure`. This keeps mutation failures as values, matches Effect's error model, and prevents optimistic mutation cleanup from depending on thrown exceptions.

## Trace before changing

1. **Find the mutation setter.** Look for `const doX = useAtomSet(<mutationAtom>, { mode: "promise" })`.
2. **Confirm it is an effect-atom mutation boundary.** The setter should come from `@effect/atom-react` and a mutation atom from `./atoms`, `../api/atoms`, or plugin React atoms.
3. **Find thrown-control handling.** The same handler has `try { await doX(...) } catch (e) { ... }`, usually setting error text, resetting `adding`/`saving`, or showing a toast.
4. **Check for non-mutation async work in the same block.** If the block also awaits follow-up mutations, convert those to `promiseExit` too or keep a narrow boundary only around truly non-effect APIs.
5. **Do not rewrite unrelated local async code.** Probe requests, OAuth popup helpers, `fetch`, and browser APIs may need a different skill unless the lint finding specifically points at the mutation call.

## Fix shape

- Change the setter to `{ mode: "promiseExit" }`.
- Import `* as Exit from "effect/Exit"` if missing.
- Import `* as Option from "effect/Option"` only when extracting an optional error.
- Replace `try/catch` around the mutation with:
- `const exit = await doX(args);`
- `if (Exit.isFailure(exit)) { ...; return; }`
- success work after the failure branch.
- Use `Exit.findErrorOption(exit)` when preserving an existing error message or typed error branch.
- Keep existing typed error handling when present, e.g. `SecretInUseError`, `ConnectionInUseError`.

## Bad

```tsx
const doAdd = useAtomSet(addGraphqlSource, { mode: "promise" });

const handleAdd = async () => {
setAdding(true);
setAddError(null);
try {
await doAdd({
params: { scopeId },
payload,
reactivityKeys: sourceWriteKeys,
});
props.onComplete();
} catch (e) {
setAddError(e instanceof Error ? e.message : "Failed to add source");
setAdding(false);
}
};
```

## Good

```tsx
import * as Exit from "effect/Exit";
import * as Option from "effect/Option";

const doAdd = useAtomSet(addGraphqlSource, { mode: "promiseExit" });

const handleAdd = async () => {
setAdding(true);
setAddError(null);
const exit = await doAdd({
params: { scopeId },
payload,
reactivityKeys: sourceWriteKeys,
});
if (Exit.isFailure(exit)) {
const error = Exit.findErrorOption(exit);
setAddError(
Option.isSome(error) && error.value instanceof Error
? error.value.message
: "Failed to add source",
);
setAdding(false);
return;
}
props.onComplete();
};
```

## Follow-up mutation chains

If success work depends on the mutation result, read it after the failure branch:

```tsx
const exit = await doAdd(args);
if (Exit.isFailure(exit)) {
setAdding(false);
return;
}

const sourceId = exit.value.namespace;
```

If a follow-up effect-atom mutation can fail and the UI treats that as add failure, make that setter `promiseExit` too and branch the same way. Do not put the follow-up mutation in `try/catch` just because the first mutation now returns `Exit`.

## What not to report

- `try/catch` around non-effect APIs such as `new URL`, `JSON.parse`, raw `fetch`, or browser popup code. Those may be real lint findings, but they need a different remediation skill.
- `useAtomSet(..., { mode: "promise" })` with no local failure handling and no lint finding. Some call sites intentionally let callers decide the boundary.
- Tests or SDK/server Effect code. This skill is for React/effect-atom UI mutation handlers.
- Manual optimistic placeholder cleanup. Use `wrdn-effect-atom-optimistic` for that; if both patterns appear together, fix optimistic plumbing first, then use `promiseExit` for the remaining mutation boundary.

## Output requirements

When reviewing, report:

- **File and line** of the `useAtomSet(..., { mode: "promise" })` or `try/catch`.
- **Mutation** being called.
- **Why** it should return `Exit` at this UI boundary.
- **Fix**: the exact setter mode and the failure branch to add.

When editing, keep changes local to the handler and imports unless a follow-up mutation in the same success path must also become `promiseExit`.
44 changes: 44 additions & 0 deletions .agents/skills/wrdn-effect-schema-boundaries/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: wrdn-effect-schema-boundaries
description: Normalize unknown or loosely typed data at boundaries with Effect Schema, named guards, or typed adapters. Use when lint flags double casts, inline object assertions, unknown shape probing, or ad hoc property checks on unknown values.
allowed-tools: Read Grep Glob Bash
---

You fix one pattern: domain code is asserting or probing an unknown shape instead of parsing it once at the boundary.

## Fix Shape

- Prefer `Schema.decodeUnknownEffect(MySchema)(value)` for untrusted input.
- Prefer `Schema.decodeUnknownEffect(Schema.fromJsonString(MySchema))(text)` or
`Schema.decodeUnknownOption(Schema.parseJson())(text)` for JSON strings.
- Keep domain code typed after the decode; do not keep `unknown` and probe it repeatedly.
- Replace `JSON.parse`, `value as string`, `as unknown as X`, `as Record<string, unknown>`, inline object assertions, `"field" in value`, and `Reflect.get` with a schema, typed adapter, or named guard.
- A named guard is acceptable only when parsing is not the right abstraction and the guard has a precise return type.

## Good

```ts
const ParsedConfig = Schema.Struct({
endpoint: Schema.String,
});

const config = yield * Schema.decodeUnknownEffect(ParsedConfig)(raw);
```

```ts
const config = yield * Schema.decodeUnknownEffect(Schema.fromJsonString(ParsedConfig))(rawText);
```

## Bad

```ts
const config = raw as unknown as { endpoint: string };
```

```ts
const config = JSON.parse(rawText) as { endpoint: string };
```

```ts
const pattern = updated.pattern as string;
```
107 changes: 107 additions & 0 deletions .agents/skills/wrdn-effect-schema-inferred-types/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
name: wrdn-effect-schema-inferred-types
description: Replace duplicated TypeScript shape declarations next to Effect Schema definitions with schema-derived types. Use when lint or review flags an interface/type alias that repeats fields already described by a nearby Schema.Struct, Schema.Union, Schema.TaggedStruct, or other Effect Schema model.
allowed-tools: Read Grep Glob Bash
---

You fix one pattern: a runtime `Schema` and a manual TypeScript type describe the same shape.

The preferred boundary is schema-first. Define the schema once, export `type X = typeof XSchema.Type` or `type X = Schema.Schema.Type<typeof XSchema>`, and make domain code consume the inferred type. This prevents drift between parsing and static types.

## Trace before changing

1. **Find the runtime schema.** Look for `Schema.Struct`, `Schema.Union`, `Schema.TaggedStruct`, `Schema.Record`, `Schema.Array`, or `Schema.decodeTo`.
2. **Find the duplicate static shape.** A nearby `interface X` or `type X = { ... }` repeats the same fields, nullability, optionality, or literals.
3. **Check export consumers.** If callers import the type, keep the exported type name stable and change only its definition.
4. **Confirm the schema is the source of truth.** If the manual type is wider/narrower than runtime parsing, decide whether the schema or consumers are wrong before replacing it.
5. **Handle recursion narrowly.** Recursive schemas may need one private recursive helper type to annotate `Schema.suspend`; keep exported domain types inferred from the schema.

## Fix shape

- Move the schema before the exported type alias when needed.
- Replace duplicated exported interfaces with aliases derived from the schema:

```ts
export const SourceSchema = Schema.Struct({
id: SourceId,
name: Schema.String,
enabled: Schema.Boolean,
});

export type Source = typeof SourceSchema.Type;
```

- Use `Schema.Schema.Type<typeof XSchema>` when it reads better for non-exported or generic schemas:

```ts
type IntrospectionResult = Schema.Schema.Type<typeof IntrospectionResultModel>;
```

- If using `Schema.decodeTo`, infer the domain type from the decoded/domain schema, not from the raw transport schema.
- Do not keep a manual interface solely for documentation. Add schema annotations or comments only when they clarify behavior the schema cannot express.

## Bad

```ts
export interface StoredSource {
readonly id: string;
readonly url: string;
readonly headers: readonly Header[];
}

export const StoredSourceSchema = Schema.Struct({
id: Schema.String,
url: Schema.String,
headers: Schema.Array(HeaderSchema),
});
```

## Good

```ts
export const StoredSourceSchema = Schema.Struct({
id: Schema.String,
url: Schema.String,
headers: Schema.Array(HeaderSchema),
});

export type StoredSource = typeof StoredSourceSchema.Type;
```

## Recursive schemas

Use a private helper only where TypeScript needs an annotation for self-reference:

```ts
interface TypeRefRecursive {
readonly kind: string;
readonly ofType: TypeRefRecursive | null;
}

const TypeRefSchema: Schema.Codec<TypeRefRecursive> = Schema.Struct({
kind: Schema.String,
ofType: Schema.NullOr(Schema.suspend(() => TypeRefSchema)),
});

export type TypeRef = typeof TypeRefSchema.Type;
```

The exported domain type is still schema-derived. The private helper exists only to satisfy the recursive schema definition.

## What not to report

- Domain types that intentionally do not have a runtime schema.
- Input builder types where the schema parses a different transport representation.
- Branded IDs or opaque aliases that are used by schemas but are not themselves duplicate object shapes.
- Private recursive helper types used only to type `Schema.suspend`, as long as exported consumer-facing types are inferred.

## Output requirements

When reviewing, report:

- **File and line** of the duplicated manual type.
- **Schema** that already owns the shape.
- **Why** the manual type can drift.
- **Fix**: the exact inferred alias to use.

When editing, keep exported type names stable unless every caller is updated in the same change.
Loading
Loading