Skip to content

feat(canvas): context onboarding with a slack-style channel intro#3370

Merged
adamleithp merged 11 commits into
mainfrom
ux/context-home-page
Jul 14, 2026
Merged

feat(canvas): context onboarding with a slack-style channel intro#3370
adamleithp merged 11 commits into
mainfrom
ux/context-home-page

Conversation

@adamleithp

@adamleithp adamleithp commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

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.

2026-07-14 15 15 50 2026-07-14 15 18 35 2026-07-14 15 16 18

Changes

Slack-style channel intro (ChannelIntro, new)

  • Every public context's feed opens with a pinned intro: the context name, "@ann created this context today. This is the very beginning of the mobile context." (creator name rendered as a mention chip, inert for now), derived entirely from the backend channel row — so it renders identically for every teammate and for pre-existing contexts.
  • Below it, a context.md card with two states: a pressable "Create a context.md" call to action (lucide file-plus-corner) that opens the describe dialog, flipping to an inert tone=success "Created context.md" card (file-check-corner) once instructions exist.
  • A "Learn more about contexts" card sits alongside (placeholder — not wired to a destination yet).

Create dialog split into two modes (CreateChannelModal)

  • Create mode is name-only: creates the context and lands you in its feed. No session starts at creation; onboarding continues from the intro card.
  • Describe mode ("Create your context.md", opened from the intro card or the CONTEXT.md empty state's "Build with agent") is a single textarea that seeds the plan-mode session which co-builds CONTEXT.md and publishes via the PostHog MCP.

Feed opener + system rows (ChannelFeedView, useChannelFeedMessages)

  • The derived opener row is now the Slack-style "joined mobile", rendered as the creator (initials avatar + name) instead of the robot "PostHog / Agent" chrome; agent lifecycle rows ("is building CONTEXT.md…") keep the agent chrome.
  • ChannelFeedView gains an intro slot 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).
  • "Ann is building CONTEXT.md for X" is posted as a durable feed message against the backend channel. Requires posthog#70320 server-side; silently no-ops until it deploys.
  • Server-emitted channel_created/context_created rows 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) 2026-07-13 00 18 03 image image image image 2026-07-13 00 30 36

Known follow-ups:

  • "Learn more about contexts" card needs a destination.
  • The context.md card doesn't yet reflect an in-flight plan session (a second click can start a duplicate session).

How did you test this?

  • Manual: created a context in the desktop app; verified the name-only dialog, the intro (name, mention-chip creation line, Today marker, joined row), the create-card → describe dialog → plan session flow, and the task card appearing in the feed.
  • pnpm --filter @posthog/ui typecheck and Biome clean; lint-staged (biome + typecheck) passed on commit.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

adamleithp and others added 3 commits July 12, 2026 13:02
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>
@trunk-io

trunk-io Bot commented Jul 12, 2026

Copy link
Copy Markdown

😎 Merged manually by @adamleithp - details.

@greptile-apps

greptile-apps Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "fix(canvas): derive 'created this contex..." | Re-trigger Greptile

Comment thread packages/ui/src/features/canvas/components/CreateChannelModal.tsx
Comment thread packages/ui/src/features/canvas/hooks/useGenerateContext.ts
Comment thread packages/ui/src/features/canvas/components/ChannelFeedView.tsx Outdated
Comment thread packages/ui/src/features/canvas/hooks/useGenerateContext.ts Outdated
Comment thread packages/ui/src/features/canvas/hooks/useChannelFeedMessages.ts Outdated
Comment thread packages/ui/src/features/canvas/components/WebsiteContext.tsx
// Restore a description stashed by a prior failed launch (create mode
// only), otherwise start blank. Consuming clears the stash.
setDescription(isDescribeMode ? "" : stashedDescription);
stashedDescription = "";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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).

Comment thread packages/ui/src/features/canvas/components/ChannelFeedView.tsx Outdated
Comment thread packages/ui/src/features/canvas/hooks/useGenerateContext.ts Outdated
Comment thread packages/ui/src/features/canvas/hooks/useGenerateContext.ts
Comment thread packages/ui/src/features/canvas/components/WebsiteChannelHome.tsx
Comment thread packages/shared/src/domain-types.ts Outdated
}

/** Lifecycle events a channel-feed system message can announce. */
export type ChannelFeedMessageEvent = "context_created" | "context_md_building";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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>
adamleithp and others added 3 commits July 14, 2026 11:59
# 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>
@adamleithp adamleithp changed the title feat(canvas): plan-mode context creation with a channel feed feat(canvas): context onboarding with a slack-style channel intro Jul 14, 2026
@adamleithp

Copy link
Copy Markdown
Contributor Author

/trunk merge

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

React Doctor found 3 issues in 2 files · 3 warnings.

3 warnings

src/features/canvas/components/ChannelIntro.tsx

src/features/canvas/components/WebsiteChannelHome.tsx

Reviewed by React Doctor for commit 7d0387d.

… 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>
@adamleithp

Copy link
Copy Markdown
Contributor Author

/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>
@adamleithp

Copy link
Copy Markdown
Contributor Author

/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>
@adamleithp

Copy link
Copy Markdown
Contributor Author

/trunk merge

@adamleithp adamleithp requested a review from k11kirky July 14, 2026 14:18
- 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 raquelmsmith left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've throughly reviewed and found nothing that needed addressing

@adamleithp adamleithp merged commit dccfb47 into main Jul 14, 2026
26 checks passed
@adamleithp adamleithp deleted the ux/context-home-page branch July 14, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants