# Client Side Routing

How to add routes without remounting the app shell.

- Repository: https://github.com/BuilderIO/agent-native (7579 stars)
- Category: AI and agents
- License: MIT
- Last updated: 2026-11-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add BuilderIO/agent-native --skill client-side-routing -g -a claude-code -y`
Codex: `npx skills add BuilderIO/agent-native --skill client-side-routing -g -a codex -y`
Cursor: `npx skills add BuilderIO/agent-native --skill client-side-routing -g -a cursor -y`
Gemini CLI: `npx skills add BuilderIO/agent-native --skill client-side-routing -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add BuilderIO/agent-native`

## Description

How to add routes without remounting the app shell. Use when adding a new route, fixing agent sidebar reloads on navigation, or choosing between `root.tsx` layout and pathless `_app.tsx` layout patterns.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Client-Side Routing

## Rule

All templates are single-page apps using React Router. **Navigation must not remount the app shell.** The agent sidebar, document tree, and any other persistent chrome must survive route changes.

## Why

If the shell unmounts on every navigation, the agent chat reconnects/reloads, destroying in-progress work and hammering the backend.

## Hard Rule

**The app shell (AgentSidebar + any top-level navigation) must be mounted ONCE, above the `<Outlet />`.** Never wrap each page in its own `<AppLayout>` / `<Layout>`. React sees a different component at the outlet position on each nav and unmounts the entire subtree.

## Two Correct Patterns

### 1. All routes need the shell

Mount `<AppLayout>` in `root.tsx` around `<Outlet />`:

```tsx
// app/root.tsx
<AppLayout>
  <Outlet />
</AppLayout>
```

### 2. Mix of protected and public routes

Use a React Router **pathless layout route**:

```
app/routes/
  _app.tsx                  # renders <AppLayout><Outlet /></AppLayout>
  _app._index.tsx           # / → under AppLayout
  _app.settings.tsx         # /settings → under AppLayout
  _app.team.tsx             # /team → under AppLayout
  book.$slug.tsx            # /book/:slug → no layout (public)
  f.$.tsx                   # /f/* → no layout (public form filler)
```

The `_` prefix on `_app.tsx` makes it a **pathless** parent, it contributes the layout but no URL segment. Route files prefixed with `_app.` nest under it and share the layout instance across navigations.

## Anti-Pattern

```tsx
// ❌ BAD, each route wraps its own Layout, causing full remount on every nav
export default function Settings() {
  return (
    <AppLayout>
      <SettingsContent />
    </AppLayout>
  );
}
```

If a page needs per-route data (e.g. sidebar highlighting the active document), derive it inside the layout from `useParams()` / `useLocation()`, don't pass it as a prop through every route file.

## Chat-First Routes

The rest: https://github.com/BuilderIO/agent-native/blob/HEAD/.agents/skills/client-side-routing/SKILL.md
