diff --git a/src/design-system/layout/AppShell/AppShell.module.css b/src/design-system/layout/AppShell/AppShell.module.css
new file mode 100644
index 0000000..866a9cd
--- /dev/null
+++ b/src/design-system/layout/AppShell/AppShell.module.css
@@ -0,0 +1,13 @@
+.app {
+ display: flex;
+ height: 100vh;
+ overflow: hidden;
+}
+
+.main {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ min-width: 0;
+}
diff --git a/src/design-system/layout/AppShell/AppShell.tsx b/src/design-system/layout/AppShell/AppShell.tsx
new file mode 100644
index 0000000..8083e52
--- /dev/null
+++ b/src/design-system/layout/AppShell/AppShell.tsx
@@ -0,0 +1,20 @@
+import styles from './AppShell.module.css'
+import type { ReactNode } from 'react'
+
+interface AppShellProps {
+ sidebar: ReactNode
+ children: ReactNode
+ detail?: ReactNode
+}
+
+export function AppShell({ sidebar, children, detail }: AppShellProps) {
+ return (
+
+ {sidebar}
+
+ {children}
+
+ {detail}
+
+ )
+}
diff --git a/src/design-system/layout/Sidebar/Sidebar.module.css b/src/design-system/layout/Sidebar/Sidebar.module.css
new file mode 100644
index 0000000..045fae7
--- /dev/null
+++ b/src/design-system/layout/Sidebar/Sidebar.module.css
@@ -0,0 +1,319 @@
+.sidebar {
+ width: 220px;
+ flex-shrink: 0;
+ background: var(--sidebar-bg);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+/* Logo */
+.logo {
+ padding: 16px 18px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
+ flex-shrink: 0;
+}
+
+.brand {
+ font-family: var(--font-mono);
+ font-weight: 600;
+ font-size: 15px;
+ color: var(--amber-light);
+ letter-spacing: -0.3px;
+}
+
+.version {
+ font-family: var(--font-mono);
+ font-size: 10px;
+ color: var(--sidebar-muted);
+ margin-left: 4px;
+}
+
+/* Search */
+.searchWrap {
+ padding: 10px 12px;
+ flex-shrink: 0;
+}
+
+.searchInner {
+ position: relative;
+}
+
+.searchInput {
+ width: 100%;
+ background: rgba(255, 255, 255, 0.06);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ border-radius: var(--radius-sm);
+ padding: 6px 10px 6px 28px;
+ color: var(--sidebar-text);
+ font-family: var(--font-body);
+ font-size: 12px;
+ outline: none;
+ transition: border-color 0.15s;
+}
+
+.searchInput::placeholder {
+ color: var(--sidebar-muted);
+}
+
+.searchInput:focus {
+ border-color: rgba(198, 130, 14, 0.4);
+}
+
+.searchIcon {
+ position: absolute;
+ left: 9px;
+ top: 50%;
+ transform: translateY(-50%);
+ color: var(--sidebar-muted);
+ display: flex;
+ align-items: center;
+}
+
+/* Scrollable nav area */
+.navArea {
+ flex: 1;
+ overflow-y: auto;
+ min-height: 0;
+}
+
+/* Section headers */
+.section {
+ padding: 14px 12px 5px;
+ font-size: 10px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 1.2px;
+ color: var(--sidebar-muted);
+}
+
+/* Items container */
+.items {
+ padding: 0 6px;
+}
+
+/* Nav item */
+.item {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 7px 12px;
+ border-radius: var(--radius-sm);
+ color: var(--sidebar-text);
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.12s;
+ border-left: 3px solid transparent;
+ margin-bottom: 1px;
+ user-select: none;
+}
+
+.item:hover {
+ background: var(--sidebar-hover);
+ color: #e8dfd4;
+}
+
+.item.active {
+ background: var(--sidebar-active);
+ color: var(--amber-light);
+ border-left-color: var(--amber);
+}
+
+.item.active .itemCount {
+ background: rgba(198, 130, 14, 0.2);
+ color: var(--amber-light);
+}
+
+/* Indented route items */
+.indented {
+ padding-left: 22px;
+}
+
+.routeArrow {
+ color: var(--sidebar-muted);
+ font-size: 10px;
+}
+
+/* Item sub-elements */
+.itemInfo {
+ flex: 1;
+ min-width: 0;
+}
+
+.itemName {
+ font-weight: 500;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.itemMeta {
+ font-size: 11px;
+ color: var(--sidebar-muted);
+ font-family: var(--font-mono);
+}
+
+.itemCount {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ color: var(--sidebar-muted);
+ background: rgba(255, 255, 255, 0.06);
+ padding: 1px 6px;
+ border-radius: 10px;
+ flex-shrink: 0;
+}
+
+/* Health dots */
+.healthDot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+
+.healthLive {
+ background: #5db866;
+ box-shadow: 0 0 6px rgba(93, 184, 102, 0.4);
+}
+
+.healthStale {
+ background: var(--warning);
+}
+
+.healthDead {
+ background: var(--sidebar-muted);
+}
+
+/* Divider */
+.divider {
+ height: 1px;
+ background: rgba(255, 255, 255, 0.06);
+ margin: 6px 12px;
+}
+
+/* Agents header */
+.agentsHeader {
+ padding: 14px 12px 6px;
+ font-size: 10px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 1.2px;
+ color: var(--sidebar-muted);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-shrink: 0;
+}
+
+.agentBadge {
+ font-family: var(--font-mono);
+ font-size: 10px;
+ padding: 1px 6px;
+ border-radius: 10px;
+ background: rgba(93, 184, 102, 0.15);
+ color: #5db866;
+}
+
+/* Agents list */
+.agentsList {
+ padding: 0 0 6px;
+ overflow-y: auto;
+ max-height: 180px;
+ flex-shrink: 0;
+}
+
+.agentItem {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 12px;
+ margin: 0 6px 2px;
+ border-radius: var(--radius-sm);
+ font-size: 11px;
+ color: var(--sidebar-text);
+ transition: background 0.1s;
+}
+
+.agentItem:hover {
+ background: var(--sidebar-hover);
+}
+
+.agentDot {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+
+.agentInfo {
+ flex: 1;
+ min-width: 0;
+}
+
+.agentName {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ font-weight: 500;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.agentDetail {
+ font-size: 10px;
+ color: var(--sidebar-muted);
+}
+
+.agentStats {
+ text-align: right;
+ font-family: var(--font-mono);
+ font-size: 10px;
+ color: var(--sidebar-muted);
+}
+
+.agentTps {
+ color: var(--sidebar-text);
+}
+
+.agentLastSeen {
+ color: var(--sidebar-muted);
+}
+
+.agentError {
+ color: var(--error);
+}
+
+/* Bottom links */
+.bottom {
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
+ padding: 6px;
+ flex-shrink: 0;
+}
+
+.bottomItem {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 7px 12px;
+ border-radius: var(--radius-sm);
+ color: var(--sidebar-muted);
+ font-size: 12px;
+ cursor: pointer;
+ transition: all 0.12s;
+ border-left: 3px solid transparent;
+ margin-bottom: 1px;
+}
+
+.bottomItem:hover {
+ background: var(--sidebar-hover);
+ color: var(--sidebar-text);
+}
+
+.bottomIcon {
+ font-size: 13px;
+ width: 18px;
+ text-align: center;
+}
diff --git a/src/design-system/layout/Sidebar/Sidebar.tsx b/src/design-system/layout/Sidebar/Sidebar.tsx
new file mode 100644
index 0000000..d974280
--- /dev/null
+++ b/src/design-system/layout/Sidebar/Sidebar.tsx
@@ -0,0 +1,241 @@
+import { useState } from 'react'
+import styles from './Sidebar.module.css'
+
+export interface App {
+ id: string
+ name: string
+ agentCount: number
+ health: 'live' | 'stale' | 'dead'
+ execCount: number
+}
+
+export interface Route {
+ id: string
+ name: string
+ execCount: number
+}
+
+export interface Agent {
+ id: string
+ name: string
+ service: string
+ version: string
+ tps: string
+ lastSeen: string
+ status: 'live' | 'stale' | 'dead'
+ errorRate?: string
+}
+
+interface SidebarProps {
+ apps: App[]
+ routes: Route[]
+ agents: Agent[]
+ activeItem?: string
+ onItemClick?: (id: string) => void
+}
+
+function HealthDot({ status }: { status: 'live' | 'stale' | 'dead' }) {
+ return (
+
+ )
+}
+
+// Camel SVG silhouette
+function CamelIcon() {
+ return (
+
+ )
+}
+
+export function Sidebar({
+ apps,
+ routes,
+ agents,
+ activeItem,
+ onItemClick,
+}: SidebarProps) {
+ const [search, setSearch] = useState('')
+
+ const liveCount = agents.filter((a) => a.status === 'live').length
+ const agentBadge = `${liveCount}/${agents.length} live`
+
+ const filteredApps = search
+ ? apps.filter((a) => a.name.toLowerCase().includes(search.toLowerCase()))
+ : apps
+
+ return (
+
+ )
+}
diff --git a/src/design-system/layout/TopBar/TopBar.module.css b/src/design-system/layout/TopBar/TopBar.module.css
new file mode 100644
index 0000000..e66a8ea
--- /dev/null
+++ b/src/design-system/layout/TopBar/TopBar.module.css
@@ -0,0 +1,110 @@
+.topbar {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 0 24px;
+ height: 48px;
+ flex-shrink: 0;
+ background: var(--bg-surface);
+ border-bottom: 1px solid var(--border);
+}
+
+/* Breadcrumb area - left side */
+.breadcrumb {
+ flex-shrink: 0;
+}
+
+/* Center search trigger */
+.search {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 5px 12px;
+ border: 1px solid var(--border);
+ border-radius: var(--radius-sm);
+ background: var(--bg-raised);
+ color: var(--text-muted);
+ font-size: 12px;
+ font-family: var(--font-body);
+ cursor: pointer;
+ transition: border-color 0.15s;
+ min-width: 280px;
+ flex: 1;
+ max-width: 400px;
+ text-align: left;
+}
+
+.search:hover {
+ border-color: var(--text-faint);
+}
+
+.searchIcon {
+ display: flex;
+ align-items: center;
+ color: var(--text-faint);
+ flex-shrink: 0;
+}
+
+.searchPlaceholder {
+ flex: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.kbd {
+ font-family: var(--font-mono);
+ font-size: 10px;
+ background: var(--bg-surface);
+ border: 1px solid var(--border);
+ padding: 0 4px;
+ border-radius: 3px;
+ color: var(--text-faint);
+ flex-shrink: 0;
+ line-height: 1.6;
+}
+
+/* Right section */
+.right {
+ margin-left: auto;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ flex-shrink: 0;
+}
+
+.env {
+ font-family: var(--font-mono);
+ font-size: 10px;
+ font-weight: 600;
+ padding: 3px 10px;
+ border-radius: 10px;
+ background: var(--success-bg);
+ color: var(--success);
+ border: 1px solid var(--success-border);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.shift {
+ font-family: var(--font-mono);
+ font-size: 10px;
+ padding: 3px 10px;
+ border-radius: 10px;
+ background: var(--running-bg);
+ color: var(--running);
+ border: 1px solid var(--running-border);
+}
+
+.user {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 12px;
+ color: var(--text-secondary);
+}
+
+.userName {
+ color: var(--text-secondary);
+ font-size: 12px;
+}
diff --git a/src/design-system/layout/TopBar/TopBar.tsx b/src/design-system/layout/TopBar/TopBar.tsx
new file mode 100644
index 0000000..abd165d
--- /dev/null
+++ b/src/design-system/layout/TopBar/TopBar.tsx
@@ -0,0 +1,66 @@
+import styles from './TopBar.module.css'
+import { Breadcrumb } from '../../composites/Breadcrumb/Breadcrumb'
+import { Avatar } from '../../primitives/Avatar/Avatar'
+
+interface BreadcrumbItem {
+ label: string
+ href?: string
+}
+
+interface TopBarProps {
+ breadcrumb: BreadcrumbItem[]
+ environment?: string
+ shift?: string
+ user?: { name: string }
+ onSearchClick?: () => void
+ className?: string
+}
+
+export function TopBar({
+ breadcrumb,
+ environment,
+ shift,
+ user,
+ onSearchClick,
+ className,
+}: TopBarProps) {
+ return (
+
+ {/* Left: Breadcrumb */}
+
+
+ {/* Center: Search trigger */}
+
+
+ {/* Right: env badge, shift, user */}
+
+ {environment && (
+
{environment}
+ )}
+ {shift && (
+
Shift: {shift}
+ )}
+ {user && (
+
+ )}
+
+
+ )
+}
diff --git a/src/design-system/layout/index.ts b/src/design-system/layout/index.ts
new file mode 100644
index 0000000..b911ccd
--- /dev/null
+++ b/src/design-system/layout/index.ts
@@ -0,0 +1,4 @@
+export { AppShell } from './AppShell/AppShell'
+export { Sidebar } from './Sidebar/Sidebar'
+export type { App, Route, Agent } from './Sidebar/Sidebar'
+export { TopBar } from './TopBar/TopBar'