diff --git a/backend/__tests__/unit/config/scoutWelcome.test.js b/backend/__tests__/unit/config/scoutWelcome.test.js
index 90c839059d..2d432219ca 100644
--- a/backend/__tests__/unit/config/scoutWelcome.test.js
+++ b/backend/__tests__/unit/config/scoutWelcome.test.js
@@ -36,8 +36,20 @@ describe('Scout welcome locale', () => {
it('keeps the start labels in English, since Scout reads them', () => {
expect(SCOUT_STARTS.map((s) => s.label)).toEqual([
+ 'Show me what you can do',
'Connect an agent I already use',
'Start a pod for a project',
]);
});
+
+ // Staging walk 2026-11-02: a start that asks for nothing leads the sent
+ // starts, and Scout's prompt says how to answer it.
+ it('leads the sent starts with the one that asks nothing, and tells Scout how to answer it', () => {
+ expect(SCOUT_STARTS[0]).toEqual({ id: 'ask-scout', label: 'Show me what you can do' });
+ // eslint-disable-next-line global-require
+ const { scoutApp } = require('../../../config/native-agents/scout');
+ expect(scoutApp.systemPrompt).toContain('For "Show me what you can do", answer in two or three short sentences');
+ expect(scoutApp.systemPrompt).toContain('For "Connect an agent I already use", find out which tool they run');
+ expect(scoutApp.systemPrompt).toContain('For "Start a pod for a project", ask what the project is');
+ });
});
diff --git a/backend/__tests__/unit/controllers/authController.guideIdentity.test.js b/backend/__tests__/unit/controllers/authController.guideIdentity.test.js
index bb3cec8095..cb8c99c8cb 100644
--- a/backend/__tests__/unit/controllers/authController.guideIdentity.test.js
+++ b/backend/__tests__/unit/controllers/authController.guideIdentity.test.js
@@ -123,6 +123,7 @@ describe('workspace onboarding guide identity fork (2026-08-13)', () => {
expect(welcome.payload).toEqual({
kind: 'starts',
starts: [
+ { id: 'ask-scout', label: 'Show me what you can do' },
{ id: 'connect-agent', label: 'Connect an agent I already use' },
{ id: 'start-pod', label: 'Start a pod for a project' },
],
diff --git a/backend/config/native-agents/scout.ts b/backend/config/native-agents/scout.ts
index 735444d648..2da10e8b97 100644
--- a/backend/config/native-agents/scout.ts
+++ b/backend/config/native-agents/scout.ts
@@ -28,10 +28,17 @@ import UI_CARD_REVISION from '../uiCardCatalogueRevision.json';
* the start a new person picked (services/onboardingMarks.ts, by id).
*/
export const SCOUT_STARTS = [
+ // The one start that asks nothing of the person (staging walk, 2026-11-02):
+ // the other starts each ask for a tool or a project before a first message.
+ { id: 'ask-scout', label: 'Show me what you can do' },
{ id: 'connect-agent', label: 'Connect an agent I already use' },
{ id: 'start-pod', label: 'Start a pod for a project' },
] as const;
+const startLabel = (id: typeof SCOUT_STARTS[number]['id']): string => (
+ SCOUT_STARTS.find((start) => start.id === id)?.label ?? id
+);
+
/**
* The start that leads the welcome where the instance can host (QA walk 3,
* 2026-10-16): nothing to install, so it goes first. Unlike SCOUT_STARTS it
@@ -97,12 +104,15 @@ export const scoutApp = {
+ 'page in between; only if that cannot run does it open Bring your own with '
+ '"Run it here" chosen. Either way it sends you nothing. The others send the start as '
+ 'the person\'s own message: '
- + `"${SCOUT_STARTS[0].label}" and "${SCOUT_STARTS[1].label}". For `
- + `"${SCOUT_STARTS[0].label}", find out which tool they run `
+ + `"${startLabel('ask-scout')}", "${startLabel('connect-agent')}" and "${startLabel('start-pod')}". `
+ + `For "${startLabel('ask-scout')}", answer in two or three short sentences: `
+ + 'name what you can do for them here, then offer one thing you can do right '
+ + 'now in this pod, such as putting their first task on the board. '
+ + `For "${startLabel('connect-agent')}", find out which tool they run `
+ '(Claude Code or Codex) and their operating system, one question per turn, '
+ 'then propose the connect card when the card rule below allows it; in that first reply, also say in one short '
+ 'clause that if they would rather install nothing, Commonly can run one here. '
- + `For "${SCOUT_STARTS[1].label}", ask what the project is if `
+ + `For "${startLabel('start-pod')}", ask what the project is if `
+ 'they have not said, then propose create_pod with a short name for it. '
+ 'Set create_pod params.locale to the person\'s language (en or zh-CN). '
+ 'Once they approve it, reply with the exact one-line wording in the '
diff --git a/docs/design/artboards/d215/index.html b/docs/design/artboards/d215/index.html
index 82e646114d..f43790ab0a 100644
--- a/docs/design/artboards/d215/index.html
+++ b/docs/design/artboards/d215/index.html
@@ -1306,23 +1306,25 @@
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Message Northwind
Needs you 0Agents 1Files 0Who can join
-
Dialog · waiting · 1440step 2 not connected yet
Search pods⌘K
NWNorthwind1now
Northwind
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Message Northwind
Needs you 0Agents 1Files 0Who can join
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
1
Connect your agentGenerate its private runtime token and copy the setup command for your tool.Open connection setup
2
Start your agentWaiting for your agent to connect…
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.
+
Scout welcome · 1440new pod, first message
Search pods⌘K
NWNorthwind1now
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Needs you 0Agents 1Files 0Who can join
+
Dialog · waiting · 1440step 2 not connected yet
Search pods⌘K
NWNorthwind1now
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Needs you 0Agents 1Files 0Who can join
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
1
Connect your agentGenerate its private runtime token and copy the setup command for your tool.Open connection setup
2
Start your agentWaiting for your agent to connect…
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.
-
Dialog · connected · 1440steps 1–2 done
Search pods⌘K
NWNorthwind1now
Northwind
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Message Northwind
Needs you 0Agents 1Files 0Who can join
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
Connect your agentGenerate its private runtime token and copy the setup command for your tool.
Start your agentConnected
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.
-
Dialog · hello failed · 1440room did not open
Search pods⌘K
NWNorthwind1now
Northwind
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Message Northwind
Needs you 0Agents 1Files 0Who can join
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
Connect your agentGenerate its private runtime token and copy the setup command for your tool.
Start your agentConnected
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.Could not open your 1:1 yet. Try again.
+
Dialog · connected · 1440steps 1–2 done
Search pods⌘K
NWNorthwind1now
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Needs you 0Agents 1Files 0Who can join
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
Connect your agentGenerate its private runtime token and copy the setup command for your tool.
Start your agentConnected
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.
+
Dialog · hello failed · 1440room did not open
Search pods⌘K
NWNorthwind1now
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Needs you 0Agents 1Files 0Who can join
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
Connect your agentGenerate its private runtime token and copy the setup command for your tool.
Start your agentConnected
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.Could not open your 1:1 yet. Try again.
- Scout welcome · 390
Northwind
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Message Northwind
Pods
Needs you
Team
Settings
- Dialog · waiting · 390
Northwind
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Message Northwind
Pods
Needs you
Team
Settings
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
1
Connect your agentGenerate its private runtime token and copy the setup command for your tool.Open connection setup
2
Start your agentWaiting for your agent to connect…
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.
+ Scout welcome · 390
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Pods
Needs you
Team
Settings
+ Dialog · waiting · 390
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Pods
Needs you
Team
Settings
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
1
Connect your agentGenerate its private runtime token and copy the setup command for your tool.Open connection setup
2
Start your agentWaiting for your agent to connect…
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.
-
Two doors, one pod. Scout's welcome is the first offer and needs no dialog: three starts under one message. Run an agent here is the one ink key; the other two are bordered. The dialog is the longer route for someone who wants to bring their own tool.
+
Two doors, one pod. Scout's welcome is the first offer and needs no dialog: four starts under one message. Run an agent here is the one ink key; the other three are bordered. Show me what you can do asks nothing of you: one tap sends it as your first message. Where there is no hosting, or once you hold a hosted agent, it becomes the ink key, so the welcome always has a default. The dialog is the longer route for someone who wants to bring their own tool.
The dialog is the live component: v2-first-run__* names and the same three steps. Marks that were unicode (✓, ↗) become 16px icons. The overlay is a flat --scrim tint; the card uses the page's pop edge, not a drop shadow of its own.
Connected is the only cobalt: the step-1 and step-2 marks and the word Connected. The waiting line pulses its dot, the same cue as the Bring-your-own handoff.
At 390 the card is inset 12px, Skip for now and every act are 44px, and the steps scroll inside the card.
Each state, one line
Scout welcome
Starts stay until this person sends that start. Run an agent here runs in place for the pod's creator and disappears once they hold a hosted agent; others open Bring your own.
+
Composer
While the welcome's starts are open for the pod's creator and they have sent nothing since it, the composer reads Tell Scout: I'm working on…, naming the agent that sent the welcome. After their first message it goes back to Message <pod>.
+
Board chip
The count carries its noun at both widths: 3 to do, the open tasks it counts. A bare 3 read as an unread count on the 11-02 walk.
Dialog · waiting
Step 3 is disabled. If the status check fails, the waiting line is replaced by "Connection status is temporarily unavailable. We'll keep checking." in the error style.
Dialog · connected
Steps 1–2 show the cobalt check; Say hello is the one ink key. While the 1:1 opens, the key reads "Opening…" and is disabled.
Dialog · hello failed
"Could not open your 1:1 yet. Try again." under the key, alert glyph first. The key stays live.
@@ -1330,8 +1332,14 @@
Same look. Less said.
- Dialog · connected · 390
Northwind
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Message Northwind
Pods
Needs you
Team
Settings
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
Connect your agentGenerate its private runtime token and copy the setup command for your tool.
Start your agentConnected
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.
- Dialog · hello failed · 390
Northwind
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Message Northwind
Pods
Needs you
Team
Settings
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
Connect your agentGenerate its private runtime token and copy the setup command for your tool.
Start your agentConnected
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.Could not open your 1:1 yet. Try again.
+ Dialog · connected · 390
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Pods
Needs you
Team
Settings
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
Connect your agentGenerate its private runtime token and copy the setup command for your tool.
Start your agentConnected
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.
+ Dialog · hello failed · 390
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Pods
Needs you
Team
Settings
Your first five minutes
Bring your agent into your pod
Connect Claude Code or Codex, or run one here, then start a private conversation without leaving your workspace.
Connect your agentGenerate its private runtime token and copy the setup command for your tool.
Start your agentConnected
3
Start with one helloYour agent gets its own durable identity and private 1:1 with you.Could not open your 1:1 yet. Try again.
+
+
+ Scout welcome · no hosting · 1440self-hosted, or a hosted agent already running
Search pods⌘K
NWNorthwind1now
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Needs you 0Agents 1Files 0Who can join
+
+
+ Scout welcome · no hosting · 390self-hosted, or a hosted agent already running
Northwind3 to do
Scoutguide · now
I'm Scout, your first agent here. Pick one below, or just tell me what you're working on.
Tell Scout: I’m working on…
Pods
Needs you
Team
Settings
diff --git a/frontend/src/i18n/__tests__/scoutStartLabels.test.ts b/frontend/src/i18n/__tests__/scoutStartLabels.test.ts
index 0d4df717a9..e80e4294ed 100644
--- a/frontend/src/i18n/__tests__/scoutStartLabels.test.ts
+++ b/frontend/src/i18n/__tests__/scoutStartLabels.test.ts
@@ -4,7 +4,7 @@ import i18n, { i18nReady, LANGUAGE_STORAGE_KEY } from '..';
// TASK-550: Scout's welcome starts are sent to Scout by their English labels
// (backend/config/native-agents/scout.ts), so only the displayed text is
// translated, by id. Every id the welcome can offer needs a zh-CN label.
-const START_IDS = ['connect-agent', 'start-pod', 'run-hosted'];
+const START_IDS = ['ask-scout', 'connect-agent', 'start-pod', 'run-hosted'];
describe('Scout welcome start labels', () => {
beforeAll(async () => {
diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json
index 0f0c3fd4b1..1c873b7be6 100644
--- a/frontend/src/i18n/locales/en.json
+++ b/frontend/src/i18n/locales/en.json
@@ -609,6 +609,7 @@
"label": "Ways to start",
"openByo": "Open Bring your own",
"labels": {
+ "ask-scout": "Show me what you can do",
"connect-agent": "Connect an agent I already use",
"start-pod": "Start a pod for a project",
"run-hosted": "Run an agent here"
@@ -716,6 +717,8 @@
"agents_one": "{{count}} agent",
"agents_other": "{{count}} agents",
"boardOpen": "board {{count}} open",
+ "boardTasks_one": "{{count}} to do",
+ "boardTasks_other": "{{count}} to do",
"backToPods": "Back to pods",
"invite": "Invite",
"dm": "DM",
@@ -746,6 +749,7 @@
},
"composer": {
"placeholder": "Message {{podName}}…",
+ "placeholderAgent": "Tell {{agent}}: I'm working on…",
"uploading": "Uploading…",
"attachFile": "Attach file",
"sending": "Sending…",
diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json
index e809799bd9..bb88eeb067 100644
--- a/frontend/src/i18n/locales/zh-CN.json
+++ b/frontend/src/i18n/locales/zh-CN.json
@@ -609,6 +609,7 @@
"label": "开始方式",
"openByo": "去接入自己的智能体",
"labels": {
+ "ask-scout": "看看你能做什么",
"connect-agent": "接入我在用的智能体",
"start-pod": "新建项目 Pod",
"run-hosted": "在这里运行智能体"
@@ -715,6 +716,7 @@
"agents_one": "{{count}}个智能体",
"agents_other": "{{count}}个智能体",
"boardOpen": "看板{{count}}项待办",
+ "boardTasks_other": "{{count}}项待办",
"backToPods": "返回 Pod 列表",
"invite": "邀请",
"dm": "私信",
@@ -745,6 +747,7 @@
},
"composer": {
"placeholder": "发消息到 {{podName}}…",
+ "placeholderAgent": "告诉 {{agent}}:我在做…",
"uploading": "正在上传…",
"attachFile": "添加文件",
"sending": "正在发送…",
diff --git a/frontend/src/v2/__tests__/V2ThreadPodRename.test.tsx b/frontend/src/v2/__tests__/V2ThreadPodRename.test.tsx
index b46ed6acfd..1d364a3b25 100644
--- a/frontend/src/v2/__tests__/V2ThreadPodRename.test.tsx
+++ b/frontend/src/v2/__tests__/V2ThreadPodRename.test.tsx
@@ -115,7 +115,8 @@ describe('V2Thread — owner-only pod rename (TASK-419)', () => {
expect(chips).toHaveLength(2);
chips.forEach((chip) => {
expect(chip).toHaveAttribute('title', 'board 2 open');
- expect(chip).toHaveTextContent(/^2$/);
+ // The count carries its noun: a bare "2" read as an unread count (walk 11-02).
+ expect(chip).toHaveTextContent(/^2 to do$/);
expect(chip.querySelector('svg')).toBeTruthy();
});
fireEvent.click(chips[0]);
diff --git a/frontend/src/v2/__tests__/V2ThreadStarts.test.tsx b/frontend/src/v2/__tests__/V2ThreadStarts.test.tsx
index c2296f61e0..0d63308498 100644
--- a/frontend/src/v2/__tests__/V2ThreadStarts.test.tsx
+++ b/frontend/src/v2/__tests__/V2ThreadStarts.test.tsx
@@ -144,7 +144,7 @@ describe("V2Thread — Scout's starts", () => {
test('a click sends the start as a root message, leaves the draft alone, and that start goes away', async () => {
const sendSpy = renderThread([welcome]);
- const composer = screen.getByPlaceholderText(/message my workspace/i);
+ const composer = screen.getByPlaceholderText(/tell scout: i'm working on/i);
fireEvent.change(composer, { target: { value: 'half typed' } });
fireEvent.click(within(startsGroup()).getByRole('button', { name: POD_START }));
@@ -171,7 +171,7 @@ describe("V2Thread — Scout's starts", () => {
test('typing something else leaves the starts in place, so connecting stays one click away', async () => {
const sendSpy = renderThread([welcome]);
- fireEvent.change(screen.getByPlaceholderText(/message my workspace/i), { target: { value: 'hello' } });
+ fireEvent.change(screen.getByPlaceholderText(/tell scout: i'm working on/i), { target: { value: 'hello' } });
fireEvent.click(screen.getByRole('button', { name: /send message/i }));
expect(await screen.findByText('hello', { selector: '.v2-msg *' })).toBeInTheDocument();
@@ -213,6 +213,57 @@ describe("V2Thread — Scout's starts", () => {
// message, from the moment it is sent.
const OPEN_BYO = 'Open Bring your own';
+// Staging walk 2026-11-02: every start asked for a tool or a project, and the
+// composer named the pod rather than the agent who had just spoken.
+describe('V2Thread — a first message that asks nothing', () => {
+ const ASK = 'Show me what you can do';
+ const withAsk = (extra = []) => ({
+ ...welcome,
+ payload: { kind: 'starts', starts: [...extra, { id: 'ask-scout', label: ASK }, ...welcome.payload.starts] },
+ });
+
+ test('where no hosted start is offered, the ask start is the one ink key', () => {
+ renderThread([withAsk()]);
+ const primary = startsGroup().querySelectorAll('.v2-chat__start--primary');
+ expect(primary).toHaveLength(1);
+ expect(primary[0]).toHaveTextContent(ASK);
+ });
+
+ test('where the hosted start is offered, it keeps the ink key and the ask start is bordered', () => {
+ renderThread([withAsk([{ id: 'run-hosted', label: 'Run an agent here', href: '/v2/agents/byo?pod=pod-1&mode=hosted', action: 'run-hosted' }])]);
+ const primary = startsGroup().querySelectorAll('.v2-chat__start--primary');
+ expect(primary).toHaveLength(1);
+ expect(primary[0]).toHaveTextContent('Run an agent here');
+ });
+
+ test('one tap sends it as the person\'s own message', async () => {
+ const sendSpy = renderThread([withAsk()]);
+ fireEvent.click(screen.getByRole('button', { name: ASK }));
+ await waitFor(() => expect(sendSpy).toHaveBeenCalled());
+ expect(sendSpy.mock.calls[0][0]).toBe(ASK);
+ });
+
+ test('the composer names the agent who welcomed them until they send anything', () => {
+ renderThread([withAsk()]);
+ expect(screen.getByPlaceholderText("Tell scout: I'm working on…")).toBeInTheDocument();
+ });
+
+ test('after their first message the composer names the pod again', () => {
+ renderThread([withAsk(), message('mine', 'u1', 'maya', 'hello', 3)]);
+ expect(screen.getByPlaceholderText('Message My Workspace…')).toBeInTheDocument();
+ });
+
+ test('an older welcome without the ask start still gets the agent composer', () => {
+ renderThread([welcome]);
+ expect(screen.getByPlaceholderText("Tell scout: I'm working on…")).toBeInTheDocument();
+ });
+
+ test("in a pod the viewer didn't create, the composer names the pod", () => {
+ renderThread([withAsk()], jest.fn(), { pod: { ...OWN_POD, createdBy: 'someone-else' } });
+ expect(screen.getByPlaceholderText('Message My Workspace…')).toBeInTheDocument();
+ });
+});
+
describe('V2Thread — the connect start links Bring your own', () => {
test("clicking the connect start shows the link under the person's message at once", async () => {
const send = renderThread([welcome]);
@@ -440,7 +491,7 @@ describe('Scout starts and the composer after a hosted agent goes live', () => {
,
);
- const composer = await screen.findByPlaceholderText(/message my workspace/i);
+ const composer = await screen.findByPlaceholderText(/tell scout: i'm working on/i);
await waitFor(() => expect(composer).toHaveValue('@maya-agent '));
});
@@ -452,7 +503,7 @@ describe('Scout starts and the composer after a hosted agent goes live', () => {
,
);
- const composer = await screen.findByPlaceholderText(/message my workspace/i);
+ const composer = await screen.findByPlaceholderText(/tell scout: i'm working on/i);
await waitFor(() => expect(composer).toHaveValue('@maya-agent '));
});
});
diff --git a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts
index a4d4b208a3..b25fef235e 100644
--- a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts
+++ b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts
@@ -3259,7 +3259,9 @@ describe('v2 layout invariants (CSS rule presence)', () => {
// row under Scout's message, in the slot the delivery cue and the
// no-agent row share, so they land on the message text column too.
expect(threadMessages).toContain('className="v2-chat__starts"');
- expect(threadMessages).toContain('v2-chat__start${start.action === WELCOME_HOSTED_ACTION ? \' v2-chat__start--primary\' : \'\'}');
+ expect(threadMessages).toContain('v2-chat__start${primary ? \' v2-chat__start--primary\' : \'\'}');
+ // One ink key: the hosted start where offered, otherwise the start that asks nothing (walk 11-02).
+ expect(threadMessages).toMatch(/const primary = start\.action === WELCOME_HOSTED_ACTION\s*\|\| \(start\.id === ASK_START_ID && !starts\.some/);
// The 44px phone minimum must come AFTER the 32px base in the sheet: at
// equal specificity the later rule wins, and a base rule placed after
// the media block would silently render 32 on a phone.
diff --git a/frontend/src/v2/components/V2Composer.tsx b/frontend/src/v2/components/V2Composer.tsx
index b01219a53e..985f2035b6 100644
--- a/frontend/src/v2/components/V2Composer.tsx
+++ b/frontend/src/v2/components/V2Composer.tsx
@@ -22,6 +22,8 @@ export interface V2ComposerWarning {
interface V2ComposerProps {
podName: string;
+ /** Replaces "Message " when nothing is being replied to. */
+ placeholder?: string;
authorName: string;
draft: string;
sending: boolean;
@@ -61,6 +63,7 @@ const FILE_ACCEPT = 'image/*,.pdf,.md,.txt,.csv,.json,.doc,.docx,.xls,.xlsx,.ppt
/** The one bounded input surface for a workspace thread (direction C). */
const V2Composer: React.FC = ({
podName,
+ placeholder,
authorName,
draft,
sending,
@@ -171,7 +174,7 @@ const V2Composer: React.FC = ({