diff --git a/packages/effect-view/AGENTS.md b/packages/effect-view/AGENTS.md
new file mode 100644
index 0000000..acb9d7e
--- /dev/null
+++ b/packages/effect-view/AGENTS.md
@@ -0,0 +1,52 @@
+# effect-view
+
+`effect-view` lets a React function component be described as an Effect program: yield services, create scoped resources, subscribe to reactive state, and turn Effects into React callbacks inside a component body, then convert that description into a normal React function component at a React boundary.
+
+Requires Effect v4 (RC) and React 19.2+. Peer dependencies: `effect`, `react`, `@types/react`. Not tied to `react-dom` — any React renderer works.
+
+When writing effect-view code, use the actual current source and tests in `src/` as ground truth over anything remembered from training — the API is pre-1.0 and still moving. The files below are a concise reference to how each module fits together; read the linked one(s) before writing code that uses that module.
+
+## Core model
+
+1. `ReactRuntime` builds the Effect services available to the UI and exposes them through React context.
+2. `Component.make` defines a component body as an Effect generator.
+3. `Component.withContext` converts a `Component` into a normal React component at a React boundary (app root, router, third-party library). Apply it only there — never between two effect-view components.
+4. Inside another effect-view component, compose children by yielding their `.use` Effect.
+5. Every rendered component instance owns a root `Scope.Scope`, opened on mount and closed on unmount; regular component setup must complete **synchronously** during render unless the component is wrapped with `Async.async`.
+
+## Module index
+
+| Module | Covers |
+|---|---|
+| [ReactRuntime.md](./ai-docs/ReactRuntime.md) | building and providing the application's Effect runtime |
+| [Component.md](./ai-docs/Component.md) | defining components, lifecycle hooks, running Effects from event handlers, providing services |
+| [Async.md](./ai-docs/Async.md) | components that suspend on an asynchronous Effect before rendering |
+| [Memoized.md](./ai-docs/Memoized.md) | skipping re-render/re-computation via `React.memo` |
+| [Lens.md](./ai-docs/Lens.md) | the core read/write state primitive, focusing, where to store state |
+| [View.md](./ai-docs/View.md) | the read-only side of state, `View.useAll` |
+| [Query.md](./ai-docs/Query.md) | cached, reactive, TanStack-Query-style server reads |
+| [QueryClient.md](./ai-docs/QueryClient.md) | the shared cache service backing `Query` |
+| [Mutation.md](./ai-docs/Mutation.md) | user-triggered writes with pending/error state |
+| [Form.md](./ai-docs/Form.md) | the shared schema-driven form model and input hooks |
+| [MutationForm.md](./ai-docs/MutationForm.md) | forms that submit a valid value to a `Mutation` |
+| [LensForm.md](./ai-docs/LensForm.md) | forms that keep a target `Lens` synchronized with a valid draft |
+| [PubSub.md](./ai-docs/PubSub.md) | bridging React-tracked values into an Effect `PubSub` |
+| [Stream.md](./ai-docs/Stream.md) | consuming a raw Effect `Stream` as React state |
+| [SetStateAction.md](./ai-docs/SetStateAction.md) | resolving `React.SetStateAction` values |
+| [ScopeRegistry.md](./ai-docs/ScopeRegistry.md) | internal — component scope lifecycle bookkeeping |
+| [Refreshable.md](./ai-docs/Refreshable.md) | internal — hot-reload integration for dev-server tooling |
+
+## Choosing between async integrations
+
+- One-off async read before rendering → `Async.async`.
+- Cached/shared/refreshable server reads → `Query`.
+- User-triggered writes with observable pending/error state → `Mutation`.
+- Async work in an event handler with no need for `Mutation` state → `Component.useRunPromise`/`useCallbackPromise`.
+- Subscriptions or background work tied to component lifecycle → a scoped fiber forked from `Component.useReactEffect`.
+
+## Common pitfalls
+
+- Never yield an asynchronous Effect directly from a regular (non-`Async`) component body.
+- effect-view hooks are still React hooks under the hood: call them unconditionally, at the top level, in a stable order — never in branches, loops, or after a suspend point.
+- Keep `ReactRuntime` instances and `Layer` references stable; building them during render creates new resources and a new React context every time.
+- `Component.withContext` requires a matching `ReactRuntime.Provider` above it in the tree.
diff --git a/packages/effect-view/ai-docs/Async.md b/packages/effect-view/ai-docs/Async.md
new file mode 100644
index 0000000..f8392a8
--- /dev/null
+++ b/packages/effect-view/ai-docs/Async.md
@@ -0,0 +1,39 @@
+# Async
+
+Components run synchronously by default (the body must complete without suspending during render). `Async.async` lifts a component so its body may await an asynchronous Effect before returning JSX; React Suspense handles the wait.
+
+```tsx
+import { Effect } from "effect"
+import { Async, Component } from "effect-view"
+
+export const UserCard = Component.make("UserCard")(function* ({ userId }: { readonly userId: string }) {
+ const user = yield* Component.useOnChange(() => loadUser(userId), [userId])
+ return
Loading user...
})) +``` + +## Rules + +- **Hook ordering**: place every React hook and effect-view hook helper *before* the first operation that may suspend. After a suspend point, the generator continuation runs outside React's synchronous render phase, so no hooks may follow it. +- An async computation restarts on every render of the component unless memoized: pipe `Memoized.memoized` after `Async.async` to skip re-running when props haven't changed (see `Memoized.md`). +- The `promise` prop name is reserved on async components (used internally) — do not declare a prop with that name. +- Async components compare props with `Object.is` by default under `Memoized`, ignoring `fallback`; use `Async.defaultPropsEquivalence` or `Equal.asEquivalence()` for structural comparison when props contain freshly-allocated objects/arrays. + +## When to reach for Async vs alternatives + +- One-off asynchronous read before rendering → `Async.async`. +- Cached/shared/refreshable server reads → `Query` (see `Query.md`). +- User-triggered writes with pending/error state → `Mutation` (see `Mutation.md`). +- Async work in an event handler with no need for `Mutation` state → `useRunPromise`/`useCallbackPromise` (see `Component.md`). +- Subscriptions or background work tied to lifecycle → a scoped fiber forked from `useReactEffect`. diff --git a/packages/effect-view/ai-docs/Component.md b/packages/effect-view/ai-docs/Component.md new file mode 100644 index 0000000..c783460 --- /dev/null +++ b/packages/effect-view/ai-docs/Component.md @@ -0,0 +1,103 @@ +# Component + +Defines a React function component as an Effect program. A `Component` is a description, not yet a React component — cross into React with `Component.withContext` or `.use`. + +## Define + +```tsx +import { Effect } from "effect" +import { Component } from "effect-view" + +export const HelloView = Component.make("HelloView")(function* (props: { readonly name: string }) { + const message = yield* Effect.succeed(`Hello, ${props.name}`) + returnLoading...
:Not loaded.
, + onFailure: ({ cause, previousSuccess, waiting }) => (/* cause: Cause