# {{APP_NAME}} — Development Guide

This guide is for development-mode agents editing this app's source code. For app operations and tools, see AGENTS.md.

## Framework Basics

**Shared auth entry, private app:** This app uses React Router v8 framework mode with `ssr: true`. The `/` route document-redirects to `/sign-in`. Authenticated app routes start at `/home` and render client-side behind the `ClientOnly` session gate in `root.tsx`; browser APIs are safe there.

**Do NOT fetch data server-side** in route loaders unless the page genuinely needs SEO/OG content. The standard pattern is: SSR renders the shell, client hydrates, and React reads/writes normal app data through actions with `useActionQuery` / `useActionMutation`.

## Adding a Page

Create a file in `app/routes/`. The filename determines the URL path:

```
app/routes/_index.tsx              → /
app/routes/home.tsx                → /home
app/routes/settings.tsx            → /settings
app/routes/inbox.tsx               → /inbox
app/routes/inbox.$threadId.tsx     → /inbox/:threadId
app/routes/$id.tsx                 → /:id (dynamic param)
```

## Mounted Workspace Routing

In a workspace, this app can be mounted under `/<app-id>`. React Router already receives `APP_BASE_PATH`/`VITE_APP_BASE_PATH` through `appBasePath()`, so route code stays app-local:

| Route file              | App-internal route | Mounted browser URL |
| ----------------------- | ------------------ | ------------------- |
| `app/routes/_index.tsx` | `/`                | `/<app-id>`         |
| `app/routes/home.tsx`   | `/home`            | `/<app-id>/home`    |
| `app/routes/review.tsx` | `/review`          | `/<app-id>/review`  |
| `app/routes/$id.tsx`    | `/:id`             | `/<app-id>/:id`     |

Use `<Link to="/review">` and `navigate("/review")` inside this app. Do not prefix React Router paths with `/<app-id>` or the URL can double-prefix, e.g. `/<app-id>/<app-id>/review`. Use `appPath()` for raw `href`s/static assets, `agentNativePath()` for `/_agent-native/*`, and `appApiPath()` only for legitimate route-only `/api/*` endpoints.

Each route file exports a default component and optional `meta()`:

```tsx
import MyPage from "@/pages/MyPage";

export function meta() {
  return [{ title: "My Page" }];
}

export default function MyPageRoute() {
  return <MyPage />;
}
```

The root route must use the shared sign-in landing loader; put authenticated
app UI and data loads under `/home` or another private route.

## Adding App Data

Normal app data starts as an action, not a custom route. Add `actions/<verb>-<resource>.ts` with `defineAction`, mark reads with `http: { method: "GET" }`, and call reads/writes from React with `useActionQuery` / `useActionMutation` from `@agent-native/core/client`. This keeps the UI and agent on one contract and lets mutating actions refresh action-backed queries automatically.

## Adding a Route-Only Endpoint

Use `server/routes/api/` only for protocols that cannot be modeled as JSON actions: multipart uploads, streaming/SSE/WebSocket, webhooks, OAuth callbacks/redirects, public SEO/OG endpoints, or binary/static asset serving. Do not add `/api/*` routes for normal CRUD, data queries, or pass-through wrappers around actions; the action endpoint already exists at `/_agent-native/actions/:name`.

Each route-only endpoint still exports a default `defineEventHandler`, but keep shared app logic in actions or server libraries so agent and UI behavior do not fork.

## Server Plugins

Startup logic (auth, SSE, etc.) lives in `server/plugins/`. Use `defineNitroPlugin` from core:

```ts
import { defineNitroPlugin } from "@agent-native/core";

export default defineNitroPlugin(async (nitroApp) => {
  // Runs once at server startup
});
```

## Key Imports

| Import                                       | Purpose                                                                    |
| -------------------------------------------- | -------------------------------------------------------------------------- |
| `defineNitroPlugin`                          | Define a server plugin (re-exported from Nitro)                            |
| `createDefaultSSEHandler`                    | Create SSE endpoint for DB change events (server)                          |
| `readAppState`, `writeAppState`              | Read/write application state (from `@agent-native/core/application-state`) |
| `readSetting`, `writeSetting`                | Read/write settings (from `@agent-native/core/settings`)                   |
| `readResource`, `writeResource`              | Read/write resources (from `@agent-native/core/resources`)                 |
| `defineEventHandler`, `readBody`, `getQuery` | H3 route handler utilities (re-exported)                                   |
| `sendToAgentChat`                            | Send or prefill messages in the agent chat from UI (client-side)           |
| Agent chat context state helpers             | Optional advanced helpers for two-way sync with staged context chips       |
| `agentChat`                                  | Send messages to agent from scripts (server-side)                          |

## Adding an Action

Create `actions/<verb>-<resource>.ts` with `defineAction`. Run with `pnpm action <name> --id value`; React callers should use `useActionQuery` for GET actions and `useActionMutation` for mutating actions, not a matching `/api/*` wrapper.

## Sending to Agent Chat

**From UI:**

```ts
import { sendToAgentChat } from "@agent-native/core/client";
sendToAgentChat({
  message: "Generate something",
  context: "...",
  submit: true,
});
```

For most UI handoffs, pass hidden context directly with `sendToAgentChat()`. Use
`submit: false` when the user should review the draft first. Use
`newTab: true, background: true, openSidebar: false` when a button should start
a full agent run without opening or focusing the sidebar. Use
`useAgentChatContext`, `setAgentChatContextItem`, `listAgentChatContext`,
`removeAgentChatContextItem`, and `clearAgentChatContext` only for advanced UI
that needs to read, mirror, stage, remove, or clear staged context chips as local
interface state.

**From scripts:**

```ts
import { agentChat } from "@agent-native/core";
agentChat.submit("Generate something");
```

**Server-side one-shot text transforms:**

```ts
import { completeText } from "@agent-native/core/server";

const result = await completeText({
  systemPrompt: "Return exactly one category label.",
  input: body,
  maxOutputTokens: 16,
  temperature: 0,
});
```

Use this only for narrow transforms that intentionally need no tools, chat
history, or run state. For user-facing operations, call it inside an action so
the UI and agent share the same capability.

## Database

Local development uses PGlite at `pglite:./data/pglite`, which provides
PostgreSQL semantics without a separate server. Containers, previews, and
serverless deploys can reset their filesystem, so production deployments must
set `DATABASE_URL` to a persistent PostgreSQL database such as Neon, Supabase,
Railway, or RDS.

Real credential values belong only in local `.env` files, deployment configuration, or registered secrets/settings UI. Never commit, document, log, return, paste, or include real keys, tokens, webhook URLs, signing secrets, or private data in examples; use empty values or obvious placeholders.

When adding app data, define tables with `@agent-native/core/db/schema` helpers and use Drizzle's PostgreSQL query builder for reads/writes. Do not write raw SQL in normal actions or handlers when Drizzle can express the query. Raw SQL belongs in additive migrations, health checks, or carefully scoped maintenance.

| Variable       | Required                     | Description                                                   |
| -------------- | ---------------------------- | ------------------------------------------------------------- |
| `DATABASE_URL` | Production yes, local dev no | PostgreSQL connection string (`pglite:./data/pglite` locally) |

## Tech Stack

- **Framework:** @agent-native/core + React Router v8 (framework mode)
- **Frontend:** React 19, Vite, TailwindCSS, shadcn/ui
- **Routing:** File-based via `flatRoutes()` — SSR shell + client rendering
- **Backend:** Nitro (via @agent-native/core) — file-based API routing, server plugins, deploy-anywhere presets
- **State:** SQL-backed (SSE for real-time updates)
- **Build:** `pnpm build` (React Router build — client + SSR + Nitro server)
- **Dev:** `pnpm dev` (Vite dev server with both React Router + Nitro plugins)
- **Start:** `node .output/server/index.mjs` (production)
