diff --git a/apps/web/src/pages/agents-page.tsx b/apps/web/src/pages/agents-page.tsx
index eefe7b812..7a096b3a4 100644
--- a/apps/web/src/pages/agents-page.tsx
+++ b/apps/web/src/pages/agents-page.tsx
@@ -26,9 +26,9 @@ import type { ReactNode } from "react";
import type { AgentDefinition, AgentInstance } from "../agents-api";
import type { AgentDirectoryData } from "../agents-api";
-import { PrincipalsSchema, useAPIQuery } from "../api";
import type { APIQuery } from "../api";
import { useAgentDirectory } from "../agents-api";
+import { useBench } from "../bench-context";
import { countProp } from "../optional-props";
import { QueryView } from "../query-view";
import { CreateAgentDialog } from "./create-agent-dialog";
@@ -275,6 +275,8 @@ export function AgentsPage({
const [createOpen, setCreateOpen] = useState(false);
const isReady = directory.kind === "ready";
+ const canCreate =
+ directory.kind === "ready" && directory.data.tenantId !== "";
return (
<>
@@ -299,7 +301,7 @@ export function AgentsPage({
@@ -434,7 +436,7 @@ export function AgentsPage({
}}
- {isReady && (
+ {canCreate && (
=
- principals.kind !== "ready"
- ? principals
- : membership === undefined
+ memberships.kind !== "ready"
+ ? memberships
+ : selectedTenantId === null
? {
kind: "ready",
data: {
diff --git a/apps/web/src/pages/routines-page.tsx b/apps/web/src/pages/routines-page.tsx
index 09c872239..8933c5d32 100644
--- a/apps/web/src/pages/routines-page.tsx
+++ b/apps/web/src/pages/routines-page.tsx
@@ -1,8 +1,8 @@
// The Routines screen: named automations over workflow runs. Follows
// runs-page.tsx / library-page.tsx's shape (pure `*Page` components fed
-// `APIQuery` props, a `*Route` container that resolves data) plus
-// chat-page.tsx's tenant-resolution convention — the account's first
-// bench membership, since this app has no bench switcher yet.
+// `APIQuery` props, a `*Route` container that resolves data). The active
+// bench comes from `useBench()` — the shell's one source of truth — never
+// a page-local `/api/me/principals` fetch that ignores the switcher.
//
// The create flow's trigger picker is workbench-specific composition
// (`RoutineTrigger`'s exact shape, including the raw-cron escape hatch)
@@ -41,9 +41,11 @@ import type { BadgeTone } from "@corbits/react-ui";
import { Clock, Plus } from "lucide-react";
import { useState } from "react";
-import { PrincipalsSchema, RunsSchema, useAPIQuery } from "../api";
+import { RunsSchema, useAPIQuery } from "../api";
import type { APIQuery, WorkflowRun } from "../api";
+import { useBench } from "../bench-context";
import { countProp } from "../optional-props";
+
import { QueryView } from "../query-view";
import { approximateNextRun, cadenceLabel } from "../routine-trigger";
import {
@@ -645,12 +647,11 @@ export function RoutinesRoute({
readonly path: string;
readonly navigate: (to: string) => void;
}) {
- const principals = useAPIQuery("/api/me/principals", PrincipalsSchema);
+ // BenchProvider owns the active tenant. Never re-fetch principals and take
+ // memberships[0] — that ignores the shell's bench switcher.
+ const { selectedTenantId } = useBench();
const allRuns = useAPIQuery("/api/me/workflows/runs", RunsSchema);
- const tenantId =
- principals.kind === "ready"
- ? (principals.data.data[0]?.tenantId ?? null)
- : null;
+ const tenantId = selectedTenantId;
// Bumped after a mutation (create/toggle) so the affected queries
// re-run without a full page reload — `useTenantQuery`'s effect keys
diff --git a/apps/web/test/pages.test.tsx b/apps/web/test/pages.test.tsx
index c0e847037..d2635ce77 100644
--- a/apps/web/test/pages.test.tsx
+++ b/apps/web/test/pages.test.tsx
@@ -212,6 +212,25 @@ describe("live data", () => {
expect(markup).toContain("No agents yet");
});
+ test("agents disables Create when no bench is selected", () => {
+ const markup = renderToStaticMarkup(
+ undefined}
+ />,
+ );
+ expect(markup).toMatch(
+ /disabled[^>]*>[\s\S]*Create agent|Create agent[\s\S]*disabled/,
+ );
+ // Dialog must not mount without a real tenant — no create form markup.
+ expect(markup).not.toContain("Define a new agent");
+ });
+
test("home counts what the hub reports", () => {
const markup = renderToStaticMarkup(