From 0e975d52e9871095729a08205e0cfc1a8a1cb9e9 Mon Sep 17 00:00:00 2001 From: Raquel Smith Date: Fri, 19 Jun 2026 14:58:19 -0700 Subject: [PATCH 1/4] feat(channels): starter prompt suggestions on the new-task screen Add a 2x4 grid of starter-prompt cards below the input on the project-bluebird channels new-task screen. Each card mirrors the SuggestedTaskCard look (icon badge + title + description); clicking one fills the composer with a multi-line template that ends in a "User input:" block of fill-in lines. - New CHANNEL_TASK_SUGGESTIONS data + SuggestedPromptCard component - TaskInput renders the channel suggestions OR SuggestedTasksPanel (never both), so the codebase-discovery/SDK-health cards don't show on channels - Raise the input block when suggestions are present so the longer list isn't squished; extra gap above the suggestions - Fill via setPendingContent so template line breaks survive - Fix: clear the editor draft before onTaskCreated navigates, so a submitted prompt doesn't persist into the next new task Generated-By: PostHog Code Task-Id: 56abea18-4f33-45cb-ae43-55182b861d46 --- .../features/canvas/channelTaskSuggestions.ts | 85 +++++++++++++++++++ .../canvas/components/WebsiteNewTask.tsx | 2 + .../components/SuggestedPromptCard.tsx | 63 ++++++++++++++ .../task-detail/components/TaskInput.tsx | 52 +++++++++++- .../task-detail/hooks/useTaskCreation.ts | 10 ++- packages/ui/src/router/routes/website/new.tsx | 2 + 6 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 packages/ui/src/features/canvas/channelTaskSuggestions.ts create mode 100644 packages/ui/src/features/task-detail/components/SuggestedPromptCard.tsx diff --git a/packages/ui/src/features/canvas/channelTaskSuggestions.ts b/packages/ui/src/features/canvas/channelTaskSuggestions.ts new file mode 100644 index 0000000000..e7684d8729 --- /dev/null +++ b/packages/ui/src/features/canvas/channelTaskSuggestions.ts @@ -0,0 +1,85 @@ +import { + Bug, + ChartBar, + ChartLine, + ChatCircleText, + Cube, + CurrencyDollar, + Flask, + Wrench, +} from "@phosphor-icons/react"; +import type { SuggestedPrompt } from "@posthog/ui/features/task-detail/components/SuggestedPromptCard"; + +// Starter prompts shown as cards on the channels (project-bluebird) new-task +// screen. Clicking a card drops its `prompt` into the composer, ready to +// edit/send. Each prompt ends with a "User input:" block of fill-in lines the +// user completes before sending. Channels-only — the /code new-task screen +// keeps its discovery suggestions. Card styling mirrors SuggestedTaskCard +// (icon badge + title + description); the icon/color follow the same +// `var(---N)` token scheme. +export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ + { + label: "Debug a user issue", + description: "Trace a specific user's events, replays, and errors", + icon: Bug, + color: "red", + prompt: + "Help me debug an issue a specific user is hitting. Pull their recent events, session replays, and errors, then figure out what went wrong.\n\n\nUser input:\n- Describe the user issue:\n- User identifier (distinct ID, email address, etc):", + }, + { + label: "Run a feature analysis", + description: "Adoption, engagement, and retention of a feature", + icon: ChartLine, + color: "blue", + prompt: + "Analyze how a feature is performing — adoption, engagement, and retention of users who use it vs. those who don't.\n\n\nUser input:\n- Feature to analyze:\n- Time period (optional):", + }, + { + label: "Understand revenue patterns", + description: "Trends over time, by plan, and by cohort", + icon: CurrencyDollar, + color: "green", + prompt: + "Analyze our revenue trends — break it down over time, by plan, and by cohort, and call out notable changes and likely drivers.\n\n\nUser input:\n- What revenue question are you trying to answer:\n- Time period (optional):", + }, + { + label: "Summarize product usage", + description: "Top events, active users, and key funnels", + icon: ChartBar, + color: "violet", + prompt: + "Summarize how our product is being used — top events, active users, key funnels, and notable trends.\n\n\nUser input:\n- Product area or feature to focus on (optional):\n- Time period (optional):", + }, + { + label: "Summarize user & agent feedback", + description: "Common themes across recent feedback", + icon: ChatCircleText, + color: "amber", + prompt: + "Summarize recent user and support/agent feedback — surface the common themes, complaints, and requests.\n\n\nUser input:\n- Feedback source or topic to focus on:\n- Time period (optional):", + }, + { + label: "Interpret experiment results", + description: "Significance and what to do next", + icon: Flask, + color: "purple", + prompt: + "Interpret the results of an experiment — explain what the metrics show, whether it's significant, and what to do next.\n\n\nUser input:\n- Experiment name or key:\n- What decision are you trying to make (optional):", + }, + { + label: "Fix a bug", + description: "Track down and fix a problem in the code", + icon: Wrench, + color: "orange", + prompt: + "Help me fix a bug — track down the root cause in the code and implement a fix. Open a PR if appropriate.\n\n\nUser input:\n- Describe the bug / what's going wrong:\n- Steps to reproduce (optional):\n- Where it happens (file, page, area — optional):", + }, + { + label: "Build a new feature", + description: "Design and implement something new", + icon: Cube, + color: "teal", + prompt: + "Help me build a new feature — propose an approach, then implement it. Open a PR if appropriate.\n\n\nUser input:\n- Describe the feature you want:\n- Any constraints or requirements (optional):", + }, +]; diff --git a/packages/ui/src/features/canvas/components/WebsiteNewTask.tsx b/packages/ui/src/features/canvas/components/WebsiteNewTask.tsx index 7b83b47324..c55fb03d42 100644 --- a/packages/ui/src/features/canvas/components/WebsiteNewTask.tsx +++ b/packages/ui/src/features/canvas/components/WebsiteNewTask.tsx @@ -1,4 +1,5 @@ import type { Task } from "@posthog/shared/domain-types"; +import { CHANNEL_TASK_SUGGESTIONS } from "@posthog/ui/features/canvas/channelTaskSuggestions"; import { useChannels } from "@posthog/ui/features/canvas/hooks/useChannels"; import { useChannelTaskMutations } from "@posthog/ui/features/canvas/hooks/useChannelTasks"; import { useFolderInstructions } from "@posthog/ui/features/canvas/hooks/useFolderInstructions"; @@ -47,6 +48,7 @@ export function WebsiteNewTask({ channelId }: { channelId: string }) { channelContext={instructions?.content} channelName={channelName} allowNoRepo + suggestions={CHANNEL_TASK_SUGGESTIONS} /> ); } diff --git a/packages/ui/src/features/task-detail/components/SuggestedPromptCard.tsx b/packages/ui/src/features/task-detail/components/SuggestedPromptCard.tsx new file mode 100644 index 0000000000..6729f0d3b2 --- /dev/null +++ b/packages/ui/src/features/task-detail/components/SuggestedPromptCard.tsx @@ -0,0 +1,63 @@ +import type { Icon } from "@phosphor-icons/react"; +import { Flex, Text } from "@radix-ui/themes"; + +export interface SuggestedPrompt { + label: string; + description: string; + prompt: string; + icon: Icon; + color: string; +} + +export interface SuggestedPromptCardProps { + suggestion: SuggestedPrompt; + onSelect: () => void; +} + +// A starter-prompt card for the channels new-task screen. Mirrors the look of +// SuggestedTaskCard (icon badge + title + description), but clicking it fills +// the composer instead of opening a detail dialog. +export function SuggestedPromptCard({ + suggestion, + onSelect, +}: SuggestedPromptCardProps) { + const PromptIcon = suggestion.icon; + + return ( + + ); +} diff --git a/packages/ui/src/features/task-detail/components/TaskInput.tsx b/packages/ui/src/features/task-detail/components/TaskInput.tsx index 5f997629c4..4f47a041d0 100644 --- a/packages/ui/src/features/task-detail/components/TaskInput.tsx +++ b/packages/ui/src/features/task-detail/components/TaskInput.tsx @@ -55,6 +55,10 @@ import { useInitialDirectoryFromFolderId } from "../hooks/useInitialDirectoryFro import { usePreviewConfig } from "../hooks/usePreviewConfig"; import { useTaskCreation } from "../hooks/useTaskCreation"; import { CloudGithubMissingNotice } from "./CloudGithubMissingNotice"; +import { + type SuggestedPrompt, + SuggestedPromptCard, +} from "./SuggestedPromptCard"; import { SuggestedTasksPanel } from "./SuggestedTasksPanel"; import { type WorkspaceMode, WorkspaceModeSelect } from "./WorkspaceModeSelect"; @@ -77,6 +81,12 @@ interface TaskInputProps { * needs a repo and attaches one lazily. */ allowNoRepo?: boolean; + /** + * Channels new-task starter prompts. When provided, a column of suggestion + * cards renders below the input while it's empty; clicking one fills the + * composer. Channels-only — omitted on the /code new-task screen. + */ + suggestions?: SuggestedPrompt[]; } export function TaskInput({ @@ -91,6 +101,7 @@ export function TaskInput({ channelContext, channelName, allowNoRepo, + suggestions, }: TaskInputProps = {}) { const cloudRegion = useAuthStateValue((s) => s.cloudRegion); const trpc = useHostTRPC(); @@ -674,7 +685,9 @@ export function TaskInput({
0 ? "38%" : "50%", transform: "translate(-50%, -50%)", }} className="absolute left-1/2 z-[1] flex w-[calc(100%-2rem)] max-w-[600px] flex-col gap-2" @@ -922,7 +935,42 @@ export function TaskInput({ )}
- + {suggestions ? ( + suggestions.length > 0 && + editorIsEmpty && ( +
+ + Suggestions + +
+ {suggestions.map((suggestion) => ( + { + // Use pending content (not setContent) so the + // multi-line template — intro + "User input:" fill-in + // lines — keeps its line breaks; focuses at the end. + useDraftStore + .getState() + .actions.setPendingContent(sessionId, { + segments: [ + { type: "text", text: suggestion.prompt }, + ], + }); + }} + /> + ))} +
+
+ ) + ) : ( + + )}
diff --git a/packages/ui/src/features/task-detail/hooks/useTaskCreation.ts b/packages/ui/src/features/task-detail/hooks/useTaskCreation.ts index 8e5f1aa48c..cabdfdcf06 100644 --- a/packages/ui/src/features/task-detail/hooks/useTaskCreation.ts +++ b/packages/ui/src/features/task-detail/hooks/useTaskCreation.ts @@ -290,15 +290,19 @@ export function useTaskCreation({ if (pendingTaskKey) { pendingTaskPromptStoreApi.move(pendingTaskKey, output.task.id); } + // Clear the draft BEFORE navigating away. When onTaskCreated + // navigates (e.g. channels), it can synchronously unmount/destroy + // the editor; clearing afterwards would throw in clearContent() + // before the persisted draft is wiped, leaving stale text behind. + if (!pendingTaskKey && !contentOverride) { + editor.clear(); + } if (onTaskCreated) { onTaskCreated(output.task); } else { void openTask(output.task); } useTourStore.getState().completeTour(createFirstTaskTour.id); - if (!pendingTaskKey && !contentOverride) { - editor.clear(); - } // Pre-flight already ran above for cloud; skip the service's duplicate check. }, { skipCloudUsagePreflight: true }, diff --git a/packages/ui/src/router/routes/website/new.tsx b/packages/ui/src/router/routes/website/new.tsx index 1211854afe..0138523a67 100644 --- a/packages/ui/src/router/routes/website/new.tsx +++ b/packages/ui/src/router/routes/website/new.tsx @@ -1,3 +1,4 @@ +import { CHANNEL_TASK_SUGGESTIONS } from "@posthog/ui/features/canvas/channelTaskSuggestions"; import { TaskInput } from "@posthog/ui/features/task-detail/components/TaskInput"; import { useAppView } from "@posthog/ui/router/useAppView"; import { createFileRoute } from "@tanstack/react-router"; @@ -21,6 +22,7 @@ function WebsiteNewTaskRoute() { initialModel={view.initialModel} initialMode={view.initialMode} reportAssociation={view.reportAssociation} + suggestions={CHANNEL_TASK_SUGGESTIONS} /> ); } From 02fa1aafec2dd80f2b812de567eafb408f0e1ab8 Mon Sep 17 00:00:00 2001 From: Raquel Smith Date: Fri, 19 Jun 2026 15:06:02 -0700 Subject: [PATCH 2/4] fix(task-input): clear draft on success regardless of onTaskReady editor.clear() only ran inside the onTaskReady callback; for repo-less channel tasks the callback can navigate/unmount the editor before the persisted draft is wiped, so a submitted prompt reappeared on the next new task. Clear drafts[sessionId] directly in the guaranteed result.success block, which always runs and survives the unmount. Generated-By: PostHog Code Task-Id: 56abea18-4f33-45cb-ae43-55182b861d46 --- .../features/task-detail/components/TaskInput.tsx | 1 + .../features/task-detail/hooks/useTaskCreation.ts | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/ui/src/features/task-detail/components/TaskInput.tsx b/packages/ui/src/features/task-detail/components/TaskInput.tsx index 4f47a041d0..19ca732037 100644 --- a/packages/ui/src/features/task-detail/components/TaskInput.tsx +++ b/packages/ui/src/features/task-detail/components/TaskInput.tsx @@ -543,6 +543,7 @@ export function TaskInput({ setAdditionalDirectories, } = useTaskCreation({ editorRef, + sessionId, selectedDirectory, selectedRepository: selectedCloudRepository, githubUserIntegrationId: selectedGithubUserIntegrationId, diff --git a/packages/ui/src/features/task-detail/hooks/useTaskCreation.ts b/packages/ui/src/features/task-detail/hooks/useTaskCreation.ts index cabdfdcf06..c990e71361 100644 --- a/packages/ui/src/features/task-detail/hooks/useTaskCreation.ts +++ b/packages/ui/src/features/task-detail/hooks/useTaskCreation.ts @@ -35,6 +35,7 @@ import { type EditorContent, extractFilePaths, } from "../../message-editor/content"; +import { useDraftStore } from "../../message-editor/draftStore"; import { useTaskInputHistoryStore } from "../../message-editor/taskInputHistoryStore"; import type { EditorHandle } from "../../message-editor/types"; import { useSettingsStore } from "../../settings/settingsStore"; @@ -47,6 +48,8 @@ const log = logger.scope("task-creation"); interface UseTaskCreationOptions { editorRef: React.RefObject; + /** Draft-store session id for the editor; cleared on successful creation. */ + sessionId: string; selectedDirectory: string; selectedRepository?: string | null; githubIntegrationId?: number; @@ -132,6 +135,7 @@ async function trackTaskCreated( export function useTaskCreation({ editorRef, + sessionId, selectedDirectory, selectedRepository, githubIntegrationId, @@ -310,6 +314,14 @@ export function useTaskCreation({ if (result.success) { setAdditionalDirectoriesOverride(null); + // Guarantee the editor draft is wiped on success. editor.clear() + // above only runs inside the onTaskReady callback (and after it + // navigates the editor may be torn down); clearing the persisted + // draft directly here always runs and survives the unmount, so a + // submitted prompt never reappears on the next new task. + if (!contentOverride) { + useDraftStore.getState().actions.setDraft(sessionId, null); + } void trackTaskCreated(input, selectedDirectory, hostClient); // Repo-less channel tasks create no workspace row (the agent runs in // a scratch dir surfaced as a synthetic workspace), so the normal @@ -359,6 +371,7 @@ export function useTaskCreation({ canSubmit, canSubmitBase, editorRef, + sessionId, selectedDirectory, selectedRepository, githubIntegrationId, From 9e84d101c1c1169766627de9a314e4621e8c13fb Mon Sep 17 00:00:00 2001 From: Raquel Smith Date: Fri, 19 Jun 2026 15:24:06 -0700 Subject: [PATCH 3/4] feat(channels): set task mode per suggestion "Fix a bug" and "Build a new feature" start in plan mode; the analysis suggestions start in auto mode. Selecting a card applies its mode via setConfigOption (guarded by isValidConfigValue, mirroring initialMode). Generated-By: PostHog Code Task-Id: 56abea18-4f33-45cb-ae43-55182b861d46 --- packages/ui/src/features/canvas/channelTaskSuggestions.ts | 8 ++++++++ .../task-detail/components/SuggestedPromptCard.tsx | 3 +++ .../ui/src/features/task-detail/components/TaskInput.tsx | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/packages/ui/src/features/canvas/channelTaskSuggestions.ts b/packages/ui/src/features/canvas/channelTaskSuggestions.ts index e7684d8729..5529b1447e 100644 --- a/packages/ui/src/features/canvas/channelTaskSuggestions.ts +++ b/packages/ui/src/features/canvas/channelTaskSuggestions.ts @@ -23,6 +23,7 @@ export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ description: "Trace a specific user's events, replays, and errors", icon: Bug, color: "red", + mode: "auto", prompt: "Help me debug an issue a specific user is hitting. Pull their recent events, session replays, and errors, then figure out what went wrong.\n\n\nUser input:\n- Describe the user issue:\n- User identifier (distinct ID, email address, etc):", }, @@ -31,6 +32,7 @@ export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ description: "Adoption, engagement, and retention of a feature", icon: ChartLine, color: "blue", + mode: "auto", prompt: "Analyze how a feature is performing — adoption, engagement, and retention of users who use it vs. those who don't.\n\n\nUser input:\n- Feature to analyze:\n- Time period (optional):", }, @@ -39,6 +41,7 @@ export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ description: "Trends over time, by plan, and by cohort", icon: CurrencyDollar, color: "green", + mode: "auto", prompt: "Analyze our revenue trends — break it down over time, by plan, and by cohort, and call out notable changes and likely drivers.\n\n\nUser input:\n- What revenue question are you trying to answer:\n- Time period (optional):", }, @@ -47,6 +50,7 @@ export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ description: "Top events, active users, and key funnels", icon: ChartBar, color: "violet", + mode: "auto", prompt: "Summarize how our product is being used — top events, active users, key funnels, and notable trends.\n\n\nUser input:\n- Product area or feature to focus on (optional):\n- Time period (optional):", }, @@ -55,6 +59,7 @@ export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ description: "Common themes across recent feedback", icon: ChatCircleText, color: "amber", + mode: "auto", prompt: "Summarize recent user and support/agent feedback — surface the common themes, complaints, and requests.\n\n\nUser input:\n- Feedback source or topic to focus on:\n- Time period (optional):", }, @@ -63,6 +68,7 @@ export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ description: "Significance and what to do next", icon: Flask, color: "purple", + mode: "auto", prompt: "Interpret the results of an experiment — explain what the metrics show, whether it's significant, and what to do next.\n\n\nUser input:\n- Experiment name or key:\n- What decision are you trying to make (optional):", }, @@ -71,6 +77,7 @@ export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ description: "Track down and fix a problem in the code", icon: Wrench, color: "orange", + mode: "plan", prompt: "Help me fix a bug — track down the root cause in the code and implement a fix. Open a PR if appropriate.\n\n\nUser input:\n- Describe the bug / what's going wrong:\n- Steps to reproduce (optional):\n- Where it happens (file, page, area — optional):", }, @@ -79,6 +86,7 @@ export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [ description: "Design and implement something new", icon: Cube, color: "teal", + mode: "plan", prompt: "Help me build a new feature — propose an approach, then implement it. Open a PR if appropriate.\n\n\nUser input:\n- Describe the feature you want:\n- Any constraints or requirements (optional):", }, diff --git a/packages/ui/src/features/task-detail/components/SuggestedPromptCard.tsx b/packages/ui/src/features/task-detail/components/SuggestedPromptCard.tsx index 6729f0d3b2..b1b36e9ab2 100644 --- a/packages/ui/src/features/task-detail/components/SuggestedPromptCard.tsx +++ b/packages/ui/src/features/task-detail/components/SuggestedPromptCard.tsx @@ -1,4 +1,5 @@ import type { Icon } from "@phosphor-icons/react"; +import type { ExecutionMode } from "@posthog/shared/domain-types"; import { Flex, Text } from "@radix-ui/themes"; export interface SuggestedPrompt { @@ -7,6 +8,8 @@ export interface SuggestedPrompt { prompt: string; icon: Icon; color: string; + /** Task mode to apply when this suggestion is selected. */ + mode: ExecutionMode; } export interface SuggestedPromptCardProps { diff --git a/packages/ui/src/features/task-detail/components/TaskInput.tsx b/packages/ui/src/features/task-detail/components/TaskInput.tsx index 19ca732037..72019e975c 100644 --- a/packages/ui/src/features/task-detail/components/TaskInput.tsx +++ b/packages/ui/src/features/task-detail/components/TaskInput.tsx @@ -963,6 +963,11 @@ export function TaskInput({ { type: "text", text: suggestion.prompt }, ], }); + // Bug/feature suggestions start in plan mode; the + // analysis ones start in auto mode. + if (isValidConfigValue(modeOption, suggestion.mode)) { + setConfigOption(modeOption.id, suggestion.mode); + } }} /> ))} From 58595d64de65cd32a344c97f5e2f90cfa5407177 Mon Sep 17 00:00:00 2001 From: Raquel Smith Date: Fri, 19 Jun 2026 16:12:30 -0700 Subject: [PATCH 4/4] fix(task-input): recenter input when suggestion cards hide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The input was raised to 38% whenever suggestions were provided, but the cards only render while the editor is empty — so once the user typed, the cards vanished yet the input stayed raised. Gate the position on the same editorIsEmpty condition so it recenters to 50% as the user types. Generated-By: PostHog Code Task-Id: 56abea18-4f33-45cb-ae43-55182b861d46 --- .../ui/src/features/task-detail/components/TaskInput.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/features/task-detail/components/TaskInput.tsx b/packages/ui/src/features/task-detail/components/TaskInput.tsx index 72019e975c..a508276afb 100644 --- a/packages/ui/src/features/task-detail/components/TaskInput.tsx +++ b/packages/ui/src/features/task-detail/components/TaskInput.tsx @@ -686,9 +686,14 @@ export function TaskInput({
0 ? "38%" : "50%", + // Tied to the same condition as the cards (which hide once the + // editor has content) so the input recenters as the user types. + top: + suggestions && suggestions.length > 0 && editorIsEmpty + ? "38%" + : "50%", transform: "translate(-50%, -50%)", }} className="absolute left-1/2 z-[1] flex w-[calc(100%-2rem)] max-w-[600px] flex-col gap-2"