Skip to content

feat(notebooks): PostHog markdown notebooks as an editable surface#3450

Draft
mariusandra wants to merge 5 commits into
mainfrom
notebooks-in-code
Draft

feat(notebooks): PostHog markdown notebooks as an editable surface#3450
mariusandra wants to merge 5 commits into
mainfrom
notebooks-in-code

Conversation

@mariusandra

@mariusandra mariusandra commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

2026-07-14 23 22 42

Brings PostHog notebooks into the desktop app as a fully editable surface, built on the webapp's markdown notebook editor. Across the five commits on this branch:

  • Editor + sync foundation — vendors the webapp's kea-free MarkdownNotebook editor library into packages/ui (with quill-based lemon-ui shims and the ported pure-logic test suites), adds a core NotebooksService over the notebooks REST API with versioned collab markdown_save (409 replay + 3-way merge, 410 reload), a framework-free NotebookSyncEngine, list/editor views, sidebar entry, and /notebooks routes.
  • Robustness fixes — sync engine created in an effect so StrictMode's double-mount can't kill autosave, @posthog/icons replaced with a lucide shim (its builds inline a React 18 jsx-runtime that React 19 rejects), 409/410 recovery mapped from the shared fetcher's thrown errors, and gcTime: 0 so reopening a notebook refetches server truth.
  • Realtime + AI + embeds — authenticated SSE collab stream with Last-Event-ID resume, CRC-guarded diff fast-path, and presence carets; an inline Ask-AI slash command streaming Max AI answers into the document; live REST-backed embeds for flags, experiments, surveys, cohorts, persons, groups, recordings, images, iframes, and richer Query rendering (funnels, retention).
  • Discussions — ports NotebookDiscussionComment so comment threads render replies and accept new ones, synced through the markdown like any other edit.
  • Legacy conversion + runnable cells — legacy TipTap notebooks auto-convert to markdown on open (all 19 upstream converter tests ported); runnable Python and SQL (HogQL/DuckDB) cells with CodeMirror editors, streamed output, and paginated results; a kernel panel with status polling and Modal resource config.

Known limitation

Upstream's kernel/* and hogql/execute actions declare no API scopes, so PostHog rejects desktop token auth on them. HogQL cells run through the generic /query/ endpoint instead; Python/DuckDB kernel paths surface a clear "runs only in the web app for now" message until required_scopes are added in the posthog repo.

Test plan

  • Verified live against us.posthog.com: legacy notebook converts on open with content intact, content round-trips through full reload, remote saves apply via the SSE diff fast-path, presence carets render, Max AI streams into the document, HogQL cell returns real paginated data, flag cards and trends charts render live data.
  • Ported upstream pure-logic test suites (converter, collaboration merge helpers) run under Vitest.

🤖 Generated with Claude Code

mariusandra and others added 5 commits July 14, 2026 16:58
Vendors the webapp's MarkdownNotebook editor library (kea-free,
self-contained contenteditable editor) into packages/ui with quill-based
shims for lemon-ui, a token-bridge stylesheet, and the pure-logic test
suites. Adds a core NotebooksService over the notebooks REST API with
versioned collab markdown_save (409 replay + 3-way merge, 410 reload),
a framework-free NotebookSyncEngine replacing notebookLogic's markdown
autosave slice, list/editor views, a sidebar entry, /notebooks routes,
and live rendering of embedded <Query> blocks via the query endpoint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, shim icons

- Create the sync engine in an effect instead of useMemo: StrictMode's dev
  double-mount disposed the memoized engine permanently, silently killing
  autosave while the UI reported Saved.
- Replace @posthog/icons with a lucide shim: its published builds inline a
  React 18 jsx-runtime whose elements React 19 refuses to render.
- Recover 409/410 from the shared fetcher's thrown errors in
  notebookMarkdownSave — the fetcher throws on any non-2xx, so the
  response-based mapping never ran against the real client.
- gcTime 0 on the notebook query so reopening a notebook refetches server
  truth instead of a stale pre-edit cache.

Verified live against us.posthog.com: markdown_save 200s, content
round-trips through a full reload, embedded Query blocks render real data.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- NotebookStreamController: authenticated SSE over collab/stream with
  Last-Event-ID resume, version-encoded stream ids, CRC-guarded diff
  fast-path into the sync engine (queued during in-flight saves, reload
  on gaps), immediate reconnect on the server's 5-minute rotation, and
  presence — remote carets with TTL pruning plus debounced/heartbeat
  caret publishing.
- NotebookInlineAIController: wires the editor's Ask AI prompt blocks to
  Max AI conversations, streaming full-content assistant messages into
  the response slot via the vendored weaving helpers, with mid-stream
  edit rebasing, follow-up prompt insertion, cancellation, and error
  weaves. AI writes flow through the normal autosave engine.
- Embeds: REST-backed live views for FeatureFlag (id or key lookup),
  Experiment, Survey, EarlyAccessFeature, Cohort, Person, Group,
  Recording, authenticated Image, sandboxed Embed iframes; Query gains
  upstream-matching titles plus funnel and retention rendering.

Verified live against us.posthog.com: remote saves from a second client
apply through the SSE diff fast-path without reloads, presence carets
render, a real Max AI answer streamed into the document, and the flag
card + trends chart render live data.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The <Comment ref replies> discussion flavor fell through to the generic
JSON props panel; port the webapp's NotebookDiscussionComment so threads
render replies (author, relative time, anchored-ref hover highlight) and
accept new replies from the composer. Replies live in the markdown
(id-keyed, merged by the vendored collaboration helpers), so they sync
across clients like any other edit. Registered as both ViewComponent and
EditComponent — the generic edit panel makes no sense for a thread.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n/SQL cells

- Legacy TipTap notebooks convert to markdown automatically on open:
  the webapp's pure convertNotebookContentToMarkdown is vendored (all 19
  upstream converter tests ported as the spec) and the content PATCHes
  with its baseline version (the endpoint 409s without one). The old
  dead-end screen remains only as the error fallback.
- Runnable cells with real editors: Python (CodeMirror, Cmd+Enter,
  SSE-streamed stdout/stderr, persisted results), SQL HogQL/DuckDB
  (CodeMirror SQL, paginated results tables, persisted summaries,
  editable return variables), SQL v2 (run → poll → page, resumable).
  Cells and comment threads set exclusiveEditPanel + hideModeActions so
  the shell renders one editor, not the edit and view panels at once.
- Kernel panel: status polling (2s starting / 10s idle while open),
  start/stop/restart, Modal CPU/RAM/idle-timeout config with hourly
  price estimate.
- Upstream's kernel/* and hogql/execute actions declare no API scopes,
  so PostHog rejects desktop token auth on them (session-only). HogQL
  cells therefore run through the generic /query/ endpoint (verified
  live), and kernel-backed paths surface a clear 'runs only in the web
  app for now' message. Enabling Python/DuckDB/kernel from desktop
  needs required_scopes added to those actions in the posthog repo.

Verified live against us.posthog.com: a legacy notebook converted on
open with all content intact, a HogQL cell returned the project's top
events with pagination, and each cell renders a single editor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Jul 14, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review. (118 files found, 100 file limit)

Bypass the limit by tagging @greptile-apps to review.

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.

1 participant