===================================================================
--- a/app/components/layout/Layout.tsx
+++ b/app/components/layout/Layout.tsx
@@ -1,221 +1,28 @@
-import { useT } from "@agent-native/core/client/i18n";
-import {
- HeaderActionsProvider,
- useHeaderActions,
- useHeaderTitle,
-} from "@agent-native/toolkit/app-shell/header-actions";
-import {
- isAgentChatHomeHandoffActive,
- useAgentChatHomeHandoff,
- useAgentChatHomeHandoffLinks,
-} from "@agent-native/toolkit/app/chat/agentkit-chat/rail";
-import {
- RealtimeVoiceModeProvider,
- useRealtimeVoiceModeOptional,
-} from "@agent-native/toolkit/app/chat/composer";
-import { isSettingsPathname } from "@agent-native/toolkit/app/settings";
-import { lazy, Suspense, useEffect, useRef, useState } from "react";
-import { useLocation } from "react-router";
+import { HeaderActionsProvider } from "@agent-native/toolkit/app-shell";
-import {
- Sheet,
- SheetContent,
- SheetDescription,
- SheetTitle,
-} from "@/components/ui/sheet";
-import { APP_TITLE } from "@/lib/app-config";
-import { HOME_PATH, isChatPathname } from "@/lib/chat-paths";
-import { TAB_ID } from "@/lib/tab-id";
-
-// Not lazy() like Header: the inspector wraps the page, so a Suspense fallback
-// would mount the page once before its chunk loads and again after.
-// AgentSidebar already lazy-loads its own panel.
-import { AgentInspector } from "./AgentInspector";
-import { MobileAppBar } from "./MobileAppBar";
-import { Sidebar } from "./Sidebar";
-
-const Header = lazy(() =>
- import("./Header").then((module) => ({ default: module.Header })),
-);
-
interface LayoutProps {
children: React.ReactNode;
}
-const SIDEBAR_COLLAPSE_KEY = "chat.sidebar.collapsed";
-
-function routeOwnsToolbar(pathname: string): boolean {
- return (
- pathname === HOME_PATH ||
- isChatPathname(pathname) ||
- pathname === "/database" ||
- pathname.startsWith("/extensions")
- );
-}
-
/**
- * A voice chat follows the user into a chat thread, so Get started can hand
- * one off. Other pages show no controls for this session, so any other
- * navigation ends it rather than leave the microphone open with nothing to
- * stop it. The agent sidebar owns a separate session and keeps its own
- * controls on screen, so this leaves that one alone.
+ * Clean Agent-Native app shell: a single full-height canvas with no chat or
+ * agent UI mounted by default. The app already satisfies the Agent-Native
+ * contract (data in SQL, actions as the source of truth, application state for
+ * navigation, real-time sync) — the agent rail and chat are opt-in surfaces.
+ *
+ * To add the persistent agent rail when the user asks for it, wrap {children}
+ * in `AgentSidebar` from "@agent-native/core/client/agent-chat"
+ * (position="right", a stable storageKey, browserTabId={TAB_ID} from
+ * "@/lib/tab-id"). See the `agent-native-toolkit` skill for the full pattern.
*/
-function EndVoiceChatOutsideChat() {
- const { pathname } = useLocation();
- const end = useRealtimeVoiceModeOptional()?.end;
- const previousPathnameRef = useRef(pathname);
-
- useEffect(() => {
- if (previousPathnameRef.current === pathname) return;
- previousPathnameRef.current = pathname;
- if (!isChatPathname(pathname)) end?.();
- }, [end, pathname]);
-
- return null;
-}
-
export function Layout({ children }: LayoutProps) {
return (
-