feat(canvas): context onboarding with a slack-style channel intro#3370
Conversation
Reworks the create-context dialog into a plan-mode launcher and gives the context index a real feed of "PostHog agent" system messages. Create dialog (quill Dialog): asks for a name + a description of what the context is about, then launches a cloud plan-mode session that investigates the repo and PostHog and co-builds CONTEXT.md with the user (buildContextGenerationPrompt seeds it with the description). Resolves adapter/model like the composer so cloud runs aren't rejected, and owns the task on the backend channel so it lands in the context feed (not just Recents). On failure the context is kept and the typed description is preserved for the next attempt. Context feed: after launch you land on the context index, where durable, team- visible announcements render alongside the plan task card — "created this context" (server-emitted channel_created) then "is building CONTEXT.md" (context_md_building), in order, then the card you click into for the session. Backed by the new ChannelFeedMessage endpoint (posthog/posthog); ordered via explicit timestamps. Removes the old fire-and-forget generation-task tracking (setGenerationTask / useFolderGenerationTask / GeneratingState + polling); the empty-state "Build with agent" now opens the same describe-and-plan dialog. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The feed-message endpoint (posthog#70320) isn't deployed, so the feed opened with the plan-task card instead of a creation announcement. Synthesize the opener from TaskChannel.created_at/created_by — canonical, always sorts first, deploy-independent — and filter server-emitted channel_created/context_created rows so nothing duplicates once the backend lands. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
😎 Merged manually by @adamleithp - details. |
|
Reviews (1): Last reviewed commit: "fix(canvas): derive 'created this contex..." | Re-trigger Greptile |
| // Restore a description stashed by a prior failed launch (create mode | ||
| // only), otherwise start blank. Consuming clears the stash. | ||
| setDescription(isDescribeMode ? "" : stashedDescription); | ||
| stashedDescription = ""; |
There was a problem hiding this comment.
[correctness, CONFIRMED] The stash's only write path is the create-mode launch failure, which navigates to the context home — where the natural retry is the CONTEXT.md empty state's "Build with agent", which reopens this component in describe mode. This open branch then blanks the field (isDescribeMode ? "") and clears stashedDescription without consuming it, so the advertised restore never survives the natural flow. And because the variable is module-global and keyed to nothing, a stash from failed context A can pre-fill a later, unrelated create dialog for context B.
Consider only consuming/clearing the stash in create mode, and keying it (or better: pre-filling the describe-mode dialog with it, since that's where the user actually retries).
| } | ||
|
|
||
| /** Lifecycle events a channel-feed system message can announce. */ | ||
| export type ChannelFeedMessageEvent = "context_created" | "context_md_building"; |
There was a problem hiding this comment.
[simplification, CONFIRMED] context_created is never posted anywhere in this repo (only context_md_building is), and useChannelFeedMessages explicitly filters it out via CREATION_EVENTS. Advertising it in the union invites a developer to post an event that gets silently dropped from the feed. Narrow the union to "context_md_building" until a second event ships.
- Resolve the cloud model via modelResolver.resolveDefaultModel (like the freeform-canvas flow) instead of trusting the composer picker's async state; hard-stop with a toast when no model resolves, before the task (and orphaned context) is created. - Stop polling the channel feed once the query errors and disable retries — the endpoint 404s on prod until posthog#70320 deploys, and the old numeric interval + default retries streamed ~4 requests per 5s forever. - Make the feed merge comparator consistent for equal timestamps. - Only consume the stashed create-dialog description in create mode, so the describe-mode open the failed-launch flow lands on doesn't wipe it. - Narrow ChannelFeedMessageEvent to the one event actually posted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # packages/ui/src/features/canvas/components/CreateChannelModal.tsx # packages/ui/src/features/canvas/hooks/useGenerateContext.ts
The intro card flips to a tone=success 'Created context.md' state once instructions exist instead of disappearing, and gains a learn-more placeholder card. TaskCard title drops the Radix Text wrapper for a plain span. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/trunk merge |
|
React Doctor found 3 issues in 2 files · 3 warnings. 3 warnings
Reviewed by React Doctor for commit |
… day-diff The intro card gains a building state detected from the channel's plan task (by title prefix — the only task/context.md tie until the backend links them) and stays inert while the instructions query loads. The create dialog gets an off-by-default toggle that reveals the context.md textarea and launches the plan session at creation; plan-launching submits are labeled 'Plan and create'. The triplicated local-day-diff math collapses into getLocalDayDiff in @posthog/shared. Quill is bumped to 0.3.0-beta.23 — the lockfile still pinned beta.22, whose Item lacks the tone prop, which is what failed CI typecheck in apps/web. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/trunk merge |
The Field wrapper stretched the Switch to fill the row, pushing its label off-screen. Use a plain associated label with a shrink-0 Switch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/trunk merge |
…sName Move the create dialog's flex layout onto the scrolling viewport via the new DialogBody viewportClassName prop instead of the outer wrapper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/trunk merge |
- Pass the gateway-resolved model to createTask instead of discarding it for the hardcoded default the resolver was added to replace. - Poll folder instructions while empty (5s, stops once content exists) so an agent's mid-run CONTEXT.md publish flips the intro card to "created" and replaces the CONTEXT.md tab's empty state without a manual reload. - Break feed-sort timestamp ties system-row-first so the "building CONTEXT.md" announcement stays above its task card if the backend truncates the 1ms offset. - Deduplicate the personal-vs-public channel resolution into a shared resolveBackendChannelId exported from useTaskChannels. - Cover getLocalDayDiff with unit tests. Generated-By: PostHog Code Task-Id: 0d69fc27-3c1d-480c-8979-8b9821c90ff9
raquelmsmith
left a comment
There was a problem hiding this comment.
I've throughly reviewed and found nothing that needed addressing
Problem
Contexts had no guided creation flow and their feed was task cards only — no lifecycle announcements, no sense of who created a context or how to give it a CONTEXT.md.
Changes
Slack-style channel intro (
ChannelIntro, new)file-plus-corner) that opens the describe dialog, flipping to an inerttone=success"Created context.md" card (file-check-corner) once instructions exist.Create dialog split into two modes (
CreateChannelModal)Feed opener + system rows (
ChannelFeedView,useChannelFeedMessages)ChannelFeedViewgains anintroslot rendered above the first entry; when set, the feed renders even with zero entries, so new public contexts show intro + Today marker + joined row instead of the suggestions empty state (which remains for the personal "me" context).channel_created/context_createdrows are filtered out so nothing duplicates once the backend lands.Rename — channels are now "contexts" across the UI copy (sidebar, dialogs, menus).
Screenshots from earlier iterations of this PR (create dialog has since dropped the description field; the feed now opens with the intro)
Known follow-ups:
How did you test this?
pnpm --filter @posthog/ui typecheckand Biome clean; lint-staged (biome + typecheck) passed on commit.Automatic notifications