diff --git a/frontend/src/renderer/components/TerminalPane.test.tsx b/frontend/src/renderer/components/TerminalPane.test.tsx
new file mode 100644
index 0000000000..5be8fb7c2a
--- /dev/null
+++ b/frontend/src/renderer/components/TerminalPane.test.tsx
@@ -0,0 +1,96 @@
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import type { WorkspaceSession } from "../types/workspace";
+import { TerminalPane } from "./TerminalPane";
+
+vi.mock("./XtermTerminal", () => ({
+ XtermTerminal: () =>
,
+}));
+
+vi.mock("../hooks/useTerminalSession", () => ({
+ useTerminalSession: () => ({
+ attach: vi.fn(),
+ state: "idle",
+ error: undefined,
+ }),
+}));
+
+const worker = {
+ id: "sess-1",
+ workspaceId: "proj-1",
+ workspaceName: "my-app",
+ title: "do the thing",
+ provider: "claude-code",
+ kind: "worker",
+ branch: "ao/sess-1",
+ status: "working",
+ updatedAt: "2026-06-10T00:00:00Z",
+ prs: [],
+} satisfies WorkspaceSession;
+
+const orchestrator = {
+ ...worker,
+ id: "sess-orch",
+ title: "orchestrate",
+ kind: "orchestrator",
+} satisfies WorkspaceSession;
+
+function renderPane(session?: WorkspaceSession) {
+ const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
+ const previousAO = window.ao;
+ window.ao = {} as typeof window.ao;
+ const result = render(
+
+
+ ,
+ );
+ return {
+ ...result,
+ restore: () => {
+ window.ao = previousAO;
+ },
+ };
+}
+
+describe("TerminalPane empty states", () => {
+ it("shows a no-selection message when no session is selected", () => {
+ const view = renderPane();
+ try {
+ expect(screen.getByText("Agent Orchestrator")).toBeInTheDocument();
+ expect(screen.getByText("No session selected. Pick a worker to attach its terminal.")).toBeInTheDocument();
+ } finally {
+ view.restore();
+ }
+ });
+
+ it("shows a startup message when a selected session has no terminal handle yet", () => {
+ const view = renderPane(worker);
+ try {
+ expect(screen.getByText("Starting session")).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ "Preparing the worker terminal. This can take a moment while AO creates the worktree and starts the agent.",
+ ),
+ ).toBeInTheDocument();
+ expect(screen.queryByText("No session selected. Pick a worker to attach its terminal.")).not.toBeInTheDocument();
+ } finally {
+ view.restore();
+ }
+ });
+
+ it("shows orchestrator-specific startup copy for a pending orchestrator terminal", () => {
+ const view = renderPane(orchestrator);
+ try {
+ expect(screen.getByText("Starting session")).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ "Preparing the orchestrator terminal. This can take a moment while AO creates the worktree and starts the agent.",
+ ),
+ ).toBeInTheDocument();
+ expect(screen.queryByText(/worker terminal/i)).not.toBeInTheDocument();
+ } finally {
+ view.restore();
+ }
+ });
+});
diff --git a/frontend/src/renderer/components/TerminalPane.tsx b/frontend/src/renderer/components/TerminalPane.tsx
index 79367e1a38..126dc858b0 100644
--- a/frontend/src/renderer/components/TerminalPane.tsx
+++ b/frontend/src/renderer/components/TerminalPane.tsx
@@ -207,6 +207,12 @@ function AttachedTerminal({ session, theme, daemonReady, terminalTarget, fontSiz
const banner = bannerText(state, error);
const showEmptyState = !handleId;
const showExitedState = state === "exited";
+ const emptyStateTitle = session ? "Starting session" : "Agent Orchestrator";
+ const emptyStateMessage = session
+ ? session.kind === "orchestrator"
+ ? "Preparing the orchestrator terminal. This can take a moment while AO creates the worktree and starts the agent."
+ : "Preparing the worker terminal. This can take a moment while AO creates the worktree and starts the agent."
+ : "No session selected. Pick a worker to attach its terminal.";
return (
@@ -231,10 +237,8 @@ function AttachedTerminal({ session, theme, daemonReady, terminalTarget, fontSiz
{showEmptyState && (
-
Agent Orchestrator
-
- No session selected. Pick a worker to attach its terminal.
-
+
{emptyStateTitle}
+
{emptyStateMessage}
)}