Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/published/handbook/engineering/developing-locally.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,43 @@ If `bin/start` sees any `op://` reference in `.env.local`, it re-execs itself un

If the `op` CLI isn't installed, `op://` lines are skipped (rather than sourced as literal `op://...` strings that break downstream services with cryptic errors). Services that need those secrets will fail with their own "missing key" errors — install `1password-cli` or replace the refs with literal values.

### Trying command palette ranking

Cmd+k can rank commands and files with Jev through Django.
Set `AI_GATEWAY_URL` to your region's HTTPS gateway base URL, including `/v1`, and `AI_GATEWAY_API_KEY` to a gateway credential with the `llm_gateway:read` scope in `.env.local`.
Enable the `command-search-jev` flag for the user.
The backend evaluates the flag locally, so the analytics SDK must have its local feature flag definitions available.
Ranking uses the shared `ml_inference` facade and its default decision model on the configured AI gateway.
The facade currently permits local development and US cloud deployments; other deployments keep the existing search.
The shared gateway credential owns billing; the `command_search` product header and team distinct ID attribute usage.
Missing or invalid gateway configuration keeps the existing search active.
The inference facade permits plain HTTP only for loopback development gateways and never falls back to TypeSafe.

The browser sends the search text and available command metadata; it does not fetch or upload a project's files for ranking.
Django retrieves up to 48 newest files, 48 files created by the current user, and 32 path text matches, within the current team and web surface.
It removes duplicate references and combines these with up to 126 commands, favoring text matches when the available command list exceeds that limit.
Django uses fuzzy text matching across names and descriptions to shortlist 15 candidates for one Jevk5 question, reserving the model's sixteenth option for no match.
This keeps inference within the single-pass choice limit and avoids slower multi-question batches.
This is bounded candidate retrieval: older files that neither belong to the user nor match the query text can be missed.
Semantic matches outside the text shortlist can also be missed.
File bodies and arbitrary file metadata are excluded.

Typing waits 200 milliseconds before starting a request.
The palette displays one completed result set and discards superseded responses.
Rankings are cached for 30 seconds; provider failures and exhausted budgets fall back to text matches without a later rerank.
Each user can trigger at most 120 inference requests per minute.
An identical request already in flight returns text matches immediately instead of waiting for the ranked response or making another gateway call.
Gateway requests have an 800-millisecond total network deadline, including connection setup and the complete response body.
Exceeding the deadline cancels the request before releasing its two-second duplicate-request lock.
Requests do not retry or follow redirects.
Gateway requests ignore environment proxy settings.
States larger than 60 KB skip inference, and gateway failures open a shared 30-second cooldown.
A denied or failed ranking request restores the existing search for that team while the palette is mounted.
An empty ranking also uses the existing search, including people, groups, accounts, tickets, and playlists.
These fallback searches finish before their results appear together.
Successful ranked searches stay limited to commands and file candidates to keep their latency bounded.
The existing search remains available when the flag is off.

### Running in detached mode

By default, `hogli start` runs interactively with a terminal UI (phrocs) that displays logs from all processes. If you prefer to run the dev stack in the background without an attached terminal, use detached mode:
Expand Down
4 changes: 4 additions & 0 deletions frontend/snapshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2208,6 +2208,10 @@ snapshots:
hash: v1.k794b7964.8afd7af2739ac45048d67219cbda76b2a37341558b1727626efc2a276d26b968.yVDHAcC3P3RVKJU-gZolegesqOIDBw_HaNaR1UxoBww
components-search--product-recents-and-starred--light:
hash: v1.k794b7964.b8da0d666c219b2f36b7d110b2109ec5586c8c42fecf67b52821a3b18fde4734.ZjncalrNKMXAQVhkoICoGDvgbi1edOR7DaVgF-QRVAQ
components-search--ranked-command-search--dark:
hash: v1.k794b7964.f27ab29c973b519b1ac8c73962546141358c73e772e4cc9b49f68d5ec2aab1c2.k89mbR6K3uV4ceIXBktv81JLnwvNMVng-9qSVkWE4sI
components-search--ranked-command-search--light:
hash: v1.k794b7964.3e4a04dce540688dfad771e8e777d2396e367f603663b7d677b10aee1772ec16.1Iax8zpQyBN8dxRbnJxLIpguOwYMMnnleD8ZYwmqF9Y
components-search--searching--dark:
hash: v1.k794b7964.da5560e3b062f5b1f6cc4d9e5c338258502948ed2353f4add22970bbce7dfd4e.GwVjKIvJSaqKOTsWNTQb5Bz4v5jN-byKBorSc854UrA
components-search--searching--light:
Expand Down
48 changes: 48 additions & 0 deletions frontend/src/generated/core/api.schemas.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions frontend/src/generated/core/api.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions frontend/src/generated/core/api.zod.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { render, screen } from '@testing-library/react'

import { NavProductTooltip } from './NavProductTooltip'

describe('NavProductTooltip', () => {
it('keeps group metadata when the group shares a built-in app name', () => {
render(<NavProductTooltip item={{ path: 'Persons', type: 'group_0', href: '/groups/0' }} />)

expect(screen.getByText(/Understand usage at the group level/)).toBeTruthy()
expect(screen.getByText('Compare activity across customer accounts.')).toBeTruthy()
expect(screen.queryByText(/Explore the people behind your events/)).toBeNull()
})
})
81 changes: 4 additions & 77 deletions frontend/src/layout/panel-layout/navbar/tabs/NavProductTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,87 +1,14 @@
import { commandExamples } from 'lib/components/Search/commandDescriptions'

import { FileSystemImport } from '~/queries/schema/schema-general'

import { sidebarProductMeta } from '../../sidebarProductMeta'
import { productsItemName } from './productsCatalog'

const examples: Record<string, string> = {
Home: 'Return to a dashboard you were investigating yesterday.',
Activity: 'Check which properties arrive with a signup event.',
'SQL editor': 'Join signup events with billing data to compare activation by plan.',
'Product analytics': 'Find the step where new users drop out of onboarding.',
Dashboards: 'Keep activation, retention, and revenue on a weekly team dashboard.',
'Session replay': 'Watch a failed checkout to see what got in the way.',
'Feature flags': 'Try a new navigation with your team before rolling it out to everyone.',
Experiments: 'Test whether a shorter signup flow improves activation.',
'Web analytics': 'Find which referral sources bring visitors who sign up.',
'Error tracking': 'Investigate an exception that appeared after a release.',
Surveys: 'Ask people who abandon a flow what they were trying to do.',
Heatmaps: 'Check whether visitors reach your pricing call to action.',
Notebooks: 'Share a funnel drop-off alongside recordings that explain it.',
'LLM analytics': 'Find the model calls making an assistant slow or expensive.',
Persons: 'Review a user’s recent events while investigating a support question.',
Cohorts: 'Compare people who tried a feature with those who have not.',
'AI gateway': 'Compare model usage across projects through a shared API.',
Apps: 'Build an internal Python dashboard using your project data.',
Broadcasts: 'Send an announcement to a cohort of beta testers.',
'Business knowledge': 'Give your AI assistant context about how your business works.',
Clusters: 'Discover common themes in conversations with your AI assistant.',
'Code review': 'Review automated findings on a pull request before it merges.',
'Customer analytics': 'Explore activity across the accounts that use your product.',
'Data catalog': 'Find the agreed definition of a metric before using it.',
'Data warehouse': 'Manage the shared data your team uses for analysis.',
Datasets: 'Keep representative prompts and expected answers for testing.',
'Early access features': 'Let interested users opt into a public beta.',
Endpoints: 'Serve a saved query to your application and track its usage.',
'Engineering analytics': 'Find workflows that slow down pull requests.',
Evaluations: 'Check whether AI responses meet your quality criteria.',
'Identity matching': 'Review how identities connect across your data.',
Inbox: 'Review a report about friction discovered in user sessions.',
Links: 'Create a trackable link for a new campaign.',
'Live Debugger': 'Inspect the state of running code when a breakpoint fires.',
Logs: 'Search application logs around the time an error occurred.',
'MCP analytics': 'See which tools AI users call and what they are trying to achieve.',
'MCP servers': 'Find a server that gives your agent the tools it needs.',
'Marketing analytics': 'Compare campaign performance alongside your product data.',
Metrics: 'Investigate a change in application performance over time.',
Playground: 'Try a revised prompt before using it in your application.',
'Product tours': 'Guide new users through their first useful action.',
Prompts: 'Keep track of changes to the prompts your application uses.',
Pulse: 'Follow what is happening across your project.',
'Replay vision': 'Explore patterns found in session recordings.',
Skills: 'Share reusable instructions with the agents your team uses.',
Support: 'Investigate and respond to a customer’s support request.',
Taggers: 'Label AI generations so you can compare different kinds of requests.',
Tasks: 'Ask an agent to investigate an issue and prepare a code change.',
Toolbar: 'Inspect elements on your website while setting up tracking.',
Tracing: 'Follow a slow request across services to find the bottleneck.',
'User research': 'Run a voice research campaign about a recent product experience.',
'Visual review': 'Review visual changes before they reach users.',
'Web scripts': 'Add a website tag without changing your application code.',
Wizard: 'Review the code changes an agent prepares to set up PostHog.',
Workflows: 'Send a follow-up when someone completes an onboarding step.',
Actions: 'Combine related clicks into a single event for analysis.',
Annotations: 'Mark a release date to help explain a change in a chart.',
'Core events': 'Define the events that represent meaningful product usage.',
Destinations: 'Send captured events to another tool your team uses.',
'Event definitions': 'Check what an event means before adding it to an insight.',
'Event ingestion filtering': 'Filter unwanted events before they enter your project.',
'Managed migrations': 'Bring historical events into PostHog.',
'Managed viewsets': 'Set up a collection of warehouse views for analysis.',
Models: 'Save a reusable query as a view for other analyses.',
'Property definitions': 'Check the meaning and format of an event property.',
'Property groups': 'Organize related properties so they are easier to find.',
'Revenue definitions': 'Choose the events and properties that represent revenue.',
'SQL variables': 'Reuse the same date boundary across several queries.',
Sources: 'Connect billing or support data to your product analytics.',
Transformations: 'Clean or reshape incoming data before you analyze it.',
'Warehouse destinations': 'Choose where a warehouse source sends its synced rows.',
'Warehouse properties': 'Add account attributes from a warehouse table to your groups.',
}

export function NavProductTooltip({ item }: { item: FileSystemImport }): JSX.Element {
const { description } = sidebarProductMeta(item)
const example = examples[item.path]
const isGroup = item.iconType === 'group' || item.iconType?.startsWith('group_') || item.type?.startsWith('group_')
const description = sidebarProductMeta(item).description
const example = isGroup ? undefined : commandExamples[item.path]
return (
<div className="w-72 max-w-full p-1 text-left whitespace-normal">
<div className="text-sm font-semibold mb-2">{productsItemName(item)}</div>
Expand Down
Loading
Loading