Skip to content

feat(navigation): experiment with surfacing Cmd+K in the left nav - #73032

Merged
rafaeelaudibert merged 2 commits into
masterfrom
feat/cmd-k-nav-experiment
Jul 23, 2026
Merged

feat(navigation): experiment with surfacing Cmd+K in the left nav#73032
rafaeelaudibert merged 2 commits into
masterfrom
feat/cmd-k-nav-experiment

Conversation

@rafaeelaudibert

@rafaeelaudibert rafaeelaudibert commented Jul 22, 2026

Copy link
Copy Markdown
Member

Problem

The Cmd+K command menu is one of the fastest ways to get around PostHog, but usage is lower than we'd like. Its only persistent entry point in the left nav is an icon-only magnifier button, and the keybind is only discoverable via its tooltip.

We also had no unified event for "the command menu was opened" - keyboard opens were only visible via the generic keybind triggered event, and button opens via nav search clicked, with no way to see totals or compare entry points in one place.

Changes

Adds a multivariate experiment (cmd-k-nav-experiment, five variants) that tries four more prominent placements for the search trigger in the left nav:

control search-bar footer-hint
cmdk-control cmdk-search-bar cmdk-footer-hint
tools-row footer-callout
cmdk-tools-row cmdk-footer-callout
  • control: current behavior, icon-only search button in the nav header
  • search-bar: when the nav is expanded, replaces the icon button with a full-width, input-styled "Search" bar below the nav header with the ⌘K keybind chip always visible (falls back to the icon button when collapsed)
  • footer-hint: keeps the icon button and adds a "Search" row with the ⌘K keybind chip to the nav footer, above Notifications/Settings
  • tools-row: keeps the icon button and adds a "Search" row with the ⌘K keybind chip right after the Tools item in the Project section
  • footer-callout: keeps the icon button and shows a dismissible "Find anything faster" callout card in the existing nav advertisement slot. Only shown once the user's account is at least 3 days old (day-one users have nothing to search for yet), and it takes the ad slot ahead of campaigns so exposure stays consistent for the analysis. Dismissal persists via the existing navPanelAdvertisementLogic, and it reuses the nav panel campaign shown / dismissed events with campaign: "cmd-k-discovery".

Instrumentation:

  • New command menu opened event captured in commandLogic with a source property (keyboard-shortcut, nav-search-button, nav-search-bar, nav-footer-hint, nav-tools-row, nav-panel-callout, quickstart), so every open is counted once regardless of entry point. openCommand/toggleCommand now take a required typed source argument.
  • Individual shortcut presses were already instrumented centrally: shortcutLogic.triggerShortcut and useKeyboardHotkeys both capture keybind triggered for every shortcut, so no changes were needed there.

The draft experiment lives at Cmd+K nav prominence (project 2), five variants at 20% each. Primary metric is mean command menu opened per user; secondaries are nav search clicked and keybind triggered filtered to the Search shortcut. It's left in draft - launch it once this PR is deployed so exposures line up with the instrumented event.

How did you test this code?

  • Drove the local dev stack headlessly (Playwright against localhost:8010 with a setup_test workspace, date_joined backdated 10 days for the callout gate) with the flag overridden to each variant: all five render as in the screenshots above, clicking each new surface opens the command menu, and ⌘K still works.
  • Verified capture calls in-page: search bar click emits nav search clicked + command menu opened {source: "nav-search-bar"}; tools row emits {source: "nav-tools-row"}; callout card emits nav panel campaign shown on render, {source: "nav-panel-callout"} on click, and nav panel campaign dismissed on dismiss (card stays hidden afterward); ⌘K emits keybind triggered (name Search) + {source: "keyboard-shortcut"}; closing with Escape emits nothing.
  • pnpm --filter=@posthog/frontend typescript:check passes with no errors; kea typegen for commandLogic is up to date; pnpm --filter=@posthog/frontend fix (oxlint + oxfmt) passes.
Command menu opened via the search-bar variant

cmdk-menu-open

Automatic notifications

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

Docs update

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Authored with Claude Code (Claude Fable 5) directed by @rafaeelaudibert. The agent explored the nav/command-bar code, implemented the four treatment variants and instrumentation, created and configured the draft experiment (with its auto-created flag) via the PostHog MCP, and verified all variants headlessly against the local dev stack (skills used: /run-posthog).

Decisions along the way:

  • Per-shortcut analytics turned out to already exist (keybind triggered in shortcutLogic / useKeyboardHotkeys), so the only new event is command menu opened; sources are typed (CommandOpenSource) to keep the property enumerable.
  • The footer-callout reuses the existing NavPanelAdvertisement slot, card component, and persisted-dismissal logic rather than introducing a new surface; AdvertisementCard's text prop was widened to ReactNode so the callout can render a platform-aware keybind chip instead of a hardcoded ⌘.
  • The 3-day gate uses user.date_joined; a "modal after signup" treatment was considered and rejected as heavier-handed than the in-nav placements.
  • The existing nav search clicked capture was kept on all click surfaces for continuity with old dashboards.

Adds the cmd-k-nav-experiment multivariate flag (control, search-bar,
footer-hint) to test more prominent placements for the command menu:
a full-width input-styled search bar below the nav header, and a
Search row with the keybind chip in the nav footer.

Also instruments a `command menu opened` event with a `source`
property so opens can be measured across all entry points (keyboard
shortcut, nav button, new variants, quickstart). Individual shortcut
presses were already tracked via `keybind triggered`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rafaeelaudibert rafaeelaudibert self-assigned this Jul 22, 2026
@trunk-io

trunk-io Bot commented Jul 22, 2026

Copy link
Copy Markdown

😎 Merged manually by @rafaeelaudibert - details.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Bundle size — 🔺 +3.2 KiB (+0.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 64.66 MiB · 🔺 +3.2 KiB (+0.0%)

File Size Δ vs base
posthog-app/src/scenes/AuthenticatedShell.js 218.8 KiB 🔺 +3.1 KiB (+1.4%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.24 MiB · 22 files no change ███░░░░░░░ 27.5% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.21 MiB · 3,001 files 🔺 +3.4 KiB (+0.0%) ████████░░ 84.5% of 9.71 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
762 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
281.3 KiB ../node_modules/.pnpm/posthog-js@1.406.2/node_modules/posthog-js/dist/rrweb.js
267.7 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
236.0 KiB src/taxonomy/core-filter-definitions-by-group.json
224.7 KiB ../node_modules/.pnpm/posthog-js@1.406.2/node_modules/posthog-js/dist/module.js
167.1 KiB src/queries/validators.js
154.3 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
105.8 KiB src/lib/api.ts
94.0 KiB ../packages/quill/packages/quill/dist/index.js
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

Toolbar bundle — eager 2.18 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.18 MiB · 17 files 🔺 +44 B (+0.0%) ████░░░░░░ 38.1% of 5.72 MiB
Deferred (lazy) 2.07 MiB · 33 files no change n/a — loads on demand
Loader dist/toolbar.js 1.1 KiB no change █░░░░░░░░░ 5.8% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
713.8 KiB dist/toolbar/toolbar-app-HY7HJI4V.css
543.6 KiB dist/toolbar/chunk-chunk-6LXPUJWA.js
484.2 KiB dist/toolbar/chunk-chunk-QS5AHYGW.js
133.6 KiB dist/toolbar/chunk-chunk-YAXKFW74.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.0 KiB dist/toolbar/toolbar-app-C3PNMI3R.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-T7IBPYAQ.js
20.9 KiB dist/toolbar/chunk-chunk-E5ZPZBER.js
12.2 KiB dist/toolbar/chunk-chunk-PIK3PADE.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

Dist folder size — 🔺 +19.5 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1357.19 MiB · 🔺 +19.5 KiB (+0.0%)

Playwright — all passed

All tests passed.

View test results →

…ariants

Extends cmd-k-nav-experiment with two more placements: a Search row
with the keybind chip right after the Tools item in the Project
section, and a dismissible callout card in the nav advertisement slot
shown only to users who joined at least 3 days ago.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rafaeelaudibert
rafaeelaudibert requested review from a team, MattBro and fercgomes and removed request for a team July 23, 2026 02:03
@rafaeelaudibert
rafaeelaudibert marked this pull request as ready for review July 23, 2026 02:03
@graphite-app graphite-app Bot added the stamphog Request AI approval (no full review) label Jul 23, 2026
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🦔 Hogbox preview · ✅ ready

▶ Open the preview

🔑 Login test@posthog.com / 12345678 (demo data)
🧩 Running this PR's backend and frontend, on the PostHog :master base
🔗 Link stable across rebuilds — a re-push swaps the box underneath, the URL stays
🔒 Access tailnet only (PostHog VPN)
🛠️ Admin inspect & debug state in hogland
💤 Idle sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen

commit aabd979 · box box-c329b9c83ee8 · ready in 868s (push → usable) · build log · rebuilds on every push, torn down on close

@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "feat(navigation): add tools-row and foot..." | Re-trigger Greptile

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Purely additive, feature-flag-gated frontend UI experiment (new nav placements for the search trigger) plus analytics instrumentation; no auth, billing, API contract, migration, dependency, or CI changes — outside risky territory and easily reversible via the flag.

  • Author wrote 8% of the modified lines and has 188 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot], hex-security-app[bot].
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 313L, 11F substantive — within ceiling
tier T1-agent / T1d-complex (313L, 11F, single-area, feat)
stamphog 2.0.0b3 .stamphog/policy.yml @ 0797905 · reviewed head aabd979

@rafaeelaudibert
rafaeelaudibert enabled auto-merge (squash) July 23, 2026 02:15
@rafaeelaudibert
rafaeelaudibert merged commit c4288bd into master Jul 23, 2026
342 of 386 checks passed
@rafaeelaudibert
rafaeelaudibert deleted the feat/cmd-k-nav-experiment branch July 23, 2026 02:38
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 23, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-23 03:10 UTC Run
prod-us ✅ Deployed 2026-07-23 03:28 UTC Run
prod-eu ✅ Deployed 2026-07-23 03:29 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant