diff --git a/apps/web/src/routes.tsx b/apps/web/src/routes.tsx
index 54ac0163..91a31700 100644
--- a/apps/web/src/routes.tsx
+++ b/apps/web/src/routes.tsx
@@ -1,13 +1,14 @@
// The route table: one entry per screen, consumed by the command palette
// (label) and the route switch (render), so navigation and pages cannot
// drift apart. The sidebar itself lists workbenches (conversations), not
-// routes — Files, Skills, Agents, Plugins, Insights, and Settings are
-// reached from its footer, and everything here also stays reachable by
-// deep link and the palette. Conversation deep links (`/w/:workbenchId`)
-// stay routable; `/` is the Myra land hop (ensure + open her conversation)
-// for a bench with a workbench already, or the guided first-workbench
-// describe screen for a bench with none (CL-6104) — never a Home
-// dashboard.
+// routes — the first-run footer reaches Routines, Files, Skills, and
+// Agents; Insights and Evals join that rail only given honest usage.
+// Plugins, Insights, Evals, and Settings stay reachable by deep link and
+// the palette even when they are off the rail. Conversation deep links
+// (`/w/:workbenchId`) stay routable; `/` is the Myra land hop (ensure +
+// open her conversation) for a bench with a workbench already, or the
+// guided first-workbench describe screen for a bench with none (CL-6104)
+// — never a Home dashboard.
// Approvals has no page — the Activity band owns them. Agents (CL-6354)
// and Skills (CL-6355) are their own rail destinations again — they spent
// a stretch as Settings sections (CL-5990) and `/settings/agents[/:id]` /
@@ -124,7 +125,7 @@ export const SETTINGS_PATH = "/settings";
* Navigation section), reachable by direct URL and the command palette
* like everything else, but deliberately off `NAV_ROUTES`: it isn't a
* roster to browse, it's the one destination the sidebar always pins in
- * view, the same way Plugins stays reachable without joining that list. */
+ * view. */
export const MISSION_CONTROL_PATH = "/mission-control";
/** The template picker (CL-6342) — every "+ New workbench" affordance
@@ -410,9 +411,8 @@ export const APP_ROUTES: readonly AppRoute[] = [
),
},
{
- // Reached from the sidebar footer and by deep link, never from
- // `NAV_ROUTES` — Plugins is deliberately absent from the palette's
- // Pages group.
+ // Reached by deep link and the command palette's Pages group — never
+ // from the first-run footer rail.
path: "/plugins",
label: "Plugins",
icon: ,
@@ -440,15 +440,17 @@ function routesInOrder(paths: readonly string[]): readonly AppRoute[] {
/**
* Everything the command palette treats as a product destination (its
- * "Pages" group). The sidebar footer reaches Files / Skills / Agents /
- * Plugins / Insights / Settings directly; the rest are palette- and
- * deep-link-reachable.
+ * "Pages" group). The first-run sidebar footer reaches Routines / Files /
+ * Skills / Agents (and Insights / Evals only given honest usage);
+ * Plugins, Insights, Evals, and Settings stay palette- and
+ * deep-link-reachable even when they are off the rail.
*/
export const NAV_ROUTES: readonly AppRoute[] = routesInOrder([
"/routines",
"/files",
"/skills",
"/agents",
+ "/plugins",
"/insights",
EVALS_PATH_PREFIX,
SETTINGS_PATH,
diff --git a/apps/web/src/shell/sidebar.tsx b/apps/web/src/shell/sidebar.tsx
index 00b41b86..befd02d4 100644
--- a/apps/web/src/shell/sidebar.tsx
+++ b/apps/web/src/shell/sidebar.tsx
@@ -1,16 +1,17 @@
// The one sidebar. Header: the brand mark, then create + search. Body: the
// workbench list — nothing page-scoped ever renders here. Footer: the
-// utility icon row (Files, Skills, Agents, Plugins, Insights, Evals —
-// CL-6353/CL-6354/CL-6355 moved the first three out of Settings and onto
-// this row; CL-6465 added Evals alongside Insights), and below it the
-// account row —
-// avatar + name, the whole row is the trigger for a menu that pops upward
-// with weekly usage, settings, feedback, and log out. Always present;
-// there is no collapse affordance and no second nav column. Approvals
-// belong in the conversation, not as a standing band here.
+// first-run rail is Routines, Files, Skills, Agents; Insights and Evals
+// join only when the existing usage / eval-run reads return real items
+// (never a fabricated row, never a new analytics store). Plugins is
+// reachable by URL and the command palette, not as a first-run tour
+// destination. Below the rail: the account row — avatar + name, the whole
+// row is the trigger for a menu that pops upward with weekly usage,
+// settings, feedback, and log out. Always present; there is no collapse
+// affordance and no second nav column. Approvals belong in the
+// conversation, not as a standing band here.
//
// Inbox is gone (CL-6151, owner decision: tasks + approvals don't flow
-// into workbenches) — Insights took its footer slot instead.
+// into workbenches).
//
// No bench switcher (CL-6089): a workbench IS an agent conversation now,
// one per account, so there is nothing to switch between in the common
@@ -40,7 +41,6 @@ import {
Lightning,
ListBullets,
Plus,
- PuzzlePiece,
Robot,
SignOut,
Repeat,
@@ -60,6 +60,7 @@ import {
import webPackage from "../../package.json";
import { useAPIQuery } from "../api";
import { useBench } from "../bench-context";
+import { EvalRunsResponseSchema, evalRunsPath } from "../evals-api";
import { OverallUsageSchema, insightsUsagePath } from "../insights-api";
import {
matchesRoute,
@@ -124,6 +125,20 @@ export function Sidebar({
readonly onNavigate: (to: string) => void;
readonly onSignOut: () => void;
}) {
+ const { selectedTenantId } = useBench();
+ const range = useMemo(() => createInsightsWindow(), []);
+ const usageQuery = useAPIQuery(
+ selectedTenantId === null ? "" : insightsUsagePath(selectedTenantId, range),
+ OverallUsageSchema,
+ );
+ const evalsQuery = useAPIQuery(
+ selectedTenantId === null ? "" : evalRunsPath(selectedTenantId, null),
+ EvalRunsResponseSchema,
+ );
+ const showInsights = usageQuery.kind === "ready" && usageQuery.data.turns > 0;
+ const showEvals =
+ evalsQuery.kind === "ready" && evalsQuery.data.runs.length > 0;
+
return (
{/* Mission Control is pinned above the footer rail as its own row
- (DESIGN.md's Shell & Navigation) — not a 7th button inside the
- rail below, which stays Routines/Files/Skills/Agents/Plugins/
- Insights exactly as it was. */}
+ (DESIGN.md's Shell & Navigation) — not a button inside the
+ first-run rail, which stays Routines/Files/Skills/Agents. */}