deepagents-architectur…
Guides architectural decisions for Deep Agents applications. Use when deciding between Deep Agents vs alternatives, choosing…
Remix v2 data loading and mutations. Use when writing loaders, actions, deferred data, revalidation logic, or pending state. Triggers on loader, action, useLoaderData, useActionData, json(), defer(), <Await>, shouldRevalidate, useRevalidator, useNavigation, useTransition (v1
Claude Code
$ npx -y skills add existential-birds/beagle --skill remix-v2-data-flow --agent claude-code
Codex
$ npx skills add existential-birds/beagle --skill remix-v2-data-flow -a codex -y
Cursor
$ npx skills add existential-birds/beagle --skill remix-v2-data-flow -a cursor -y
Gemini CLI
$ npx skills add existential-birds/beagle --skill remix-v2-data-flow -a gemini-cli -y
GitHub Copilot
$ npx skills add existential-birds/beagle --skill remix-v2-data-flow -a github-copilot -y
OpenCode
$ npx skills add existential-birds/beagle --skill remix-v2-data-flow -a opencode -y
Windsurf
$ npx skills add existential-birds/beagle --skill remix-v2-data-flow -a windsurf -y
name: remix-v2-data-flow description: Remix v2 data loading and mutations. Use when writing loaders, actions, deferred data, revalidation logic, or pending state. Triggers on loader, action, useLoaderData, useActionData, json(), defer(), <Await>, shouldRevalidate, useRevalidator, useNavigation, useTransition (v1 holdover).
**Loader + typed read**:
import { json, type LoaderFunctionArgs } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
export async function loader({ request }: LoaderFunctionArgs) {
const invoices = await db.invoice.findMany();
return json({ invoices });
}
export default function Invoices() {
// typeof loader is a type ANNOTATION (not assertion) — drives SerializeFrom<T>.
const { invoices } = useLoaderData<typeof loader>();
return <InvoiceList invoices={invoices} />;
}**Action + redirect-after-success (PRG)**:
import { json, redirect, type ActionFunctionArgs } from "@remix-run/node";
import { useActionData, Form } from "@remix-run/react";
export async function action({ request }: ActionFunctionArgs) {
const form = await request.formData();
const parsed = NewProject.safeParse(Object.fromEntries(form));
if (!parsed.success) return json({ errors: parsed.error.flatten().fieldErrors }, { status: 400 });
const project = await db.project.create({ data: parsed.data });
return redirect(`/projects/${project.id}`);
}Route modules export `loader` / `action`; components read results via `useLoaderData<typeof loader>()` and `useActionData<typeof action>()`. After every action, Remix automatically revalidates the loaders of all matching routes on the page, so the UI stays consistent with the server without manual cache invalidation.
Signatures:
Imports: `@remix-run/node` for server utilities (`json`, `redirect`, `defer`, type args) on Node; substitute `@remix-run/cloudflare` or `@remix-run/deno` for those targets. Hooks and components come from `@remix-run/react`.
`useLoaderData<typeof loader>()` is a **type annotation**, not a `as`-style assertion. The generic feeds `SerializeFrom<typeof loader>`, which models the wire-format transformation: `Date` becomes `string`, `Map`/`Set` collapse, `undefined` fields are stripped, class methods vanish. If you call `data.createdAt.getFullYear()` on a `Date` field, that's a runtime bug — the type already says `string`.
v2 did **not** change the underlying contract: loaders and actions must return a `Response`. `json()` is the ergonomic wrapper that sets `application/json` and lets you supply status / headers. Bare object returns work in v2 (Remix auto-wraps as `json()`), but `json()` is preferred for explicit status, headers, and clean `TypedResponse<T>` typing. Reach for `json()` whenever you need:
Throwing a `Response` from a loader or action exits the data function immediately. Use this for auth guards (`throw redirect("/login")`) and 404s (`throw new Response("Not Found", { status: 404 })` or `throw json({ message }, { status: 404 })`). Throwing a plain `Error` will not be classified as a route response by `useRouteError()` / `isRouteErrorResponse()`.
When a promise passed through `defer()` rejects, an `<Await errorElement={...}>` boundary catches it inline — without it, the rejection bubbles to the route's `ErrorBoundary` and tears down the whole page, defeating the streaming benefit. Inside the `errorElement`, call `useAsyncError()` (from `@remix-run/react`) to read the rejection value — this is the streaming analogue of `useRouteError()`.
function ReviewsError() {
const error = useAsyncError(); // typed as `unknown`
return <p>Failed to load reviews: {String(error)}</p>;
}
<Suspense fallback={<ReviewsSkeleton />}>
<Await resolve={reviews} errorElement={<ReviewsError />}>
{(r) => <ReviewList reviews={r} />}
</Await>
</Suspense>Everything returned from a loader travels to the browser as JSON. Project to a safe DTO (`{ id, email, name }`) before returning; never return the full Prisma `User`, password hashes, API keys, or internal flags. Loaders execute server-only — but the *return value* is shipped to the client wholesale.
Loaders run on every GET navigation and may be invoked speculatively by prefetch; they also re-run during automatic revalidation. Anything that mutates persistent state must live in `action`, reached via `<Form method="post">` or `useFetcher`. Calling `fetch()` directly from a component to hit a Remix route bypasses revalidation, pending state, and progressive enhancement — use `useFetcher().submit()` / `useFetcher().load()` instead.
Image: NASA, Public Domain. Source Beagle is an Agent Skills marketplace: framework-aware code review, documentation, testing, architectural analysis, and git workflows for any compatible coding agent.
Guides architectural decisions for Deep Agents applications. Use when deciding between Deep Agents vs alternatives, choosing…
Reviews Deep Agents code for bugs, anti-patterns, and improvements. Use when reviewing code that uses create_deep_agent,…
Implements agents using Deep Agents. Use when building agents with create_deep_agent, configuring backends, defining subagents,…
Guides architectural decisions for LangGraph applications. Use when deciding between LangGraph vs alternatives, choosing state…
Reviews LangGraph code for bugs, anti-patterns, and improvements. Use when reviewing code that uses StateGraph, nodes, edges,…
Implements stateful agent graphs using LangGraph. Use when building graphs, adding nodes/edges, defining state schemas,…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.