From 976563510cea9c7e1958513bc323fedf5064e36a Mon Sep 17 00:00:00 2001 From: sarahxsanders Date: Fri, 1 May 2026 09:51:44 -0400 Subject: [PATCH] feat: add posthog docs skill --- .../skills/posthog-docs/config.yaml | 16 + .../skills/posthog-docs/description.md | 91 ++++ .../posthog-docs/references/api-specs.md | 245 +++++++++++ .../references/mdx-and-components.md | 297 +++++++++++++ .../references/onboarding-docs.md | 293 +++++++++++++ .../posthog-docs/references/product-docs.md | 241 ++++++++++ .../posthog-docs/references/sdk-reference.md | 76 ++++ .../posthog-docs/references/style-guide.md | 412 ++++++++++++++++++ 8 files changed, 1671 insertions(+) create mode 100644 transformation-config/skills/posthog-docs/config.yaml create mode 100644 transformation-config/skills/posthog-docs/description.md create mode 100644 transformation-config/skills/posthog-docs/references/api-specs.md create mode 100644 transformation-config/skills/posthog-docs/references/mdx-and-components.md create mode 100644 transformation-config/skills/posthog-docs/references/onboarding-docs.md create mode 100644 transformation-config/skills/posthog-docs/references/product-docs.md create mode 100644 transformation-config/skills/posthog-docs/references/sdk-reference.md create mode 100644 transformation-config/skills/posthog-docs/references/style-guide.md diff --git a/transformation-config/skills/posthog-docs/config.yaml b/transformation-config/skills/posthog-docs/config.yaml new file mode 100644 index 0000000..032a963 --- /dev/null +++ b/transformation-config/skills/posthog-docs/config.yaml @@ -0,0 +1,16 @@ +type: docs-only +template: description.md +description: Authoring guidance for PostHog documentation – style, formatting, MDX components, and content-type patterns +tags: [posthog-docs] +shared_docs: + - https://posthog.com/handbook/docs-and-wizard/docs-style-guide.md + - https://posthog.com/handbook/docs-and-wizard/mdx-and-components.md + - https://posthog.com/handbook/docs-and-wizard/writing-product-docs.md + - https://posthog.com/handbook/docs-and-wizard/onboarding-docs.md + - https://posthog.com/handbook/docs-and-wizard/sdk-reference-docs.md + - https://posthog.com/handbook/docs-and-wizard/api-specifications.md +variants: + - id: posthog-docs + display_name: PostHog docs authoring + tags: [posthog-docs] + docs_urls: [] diff --git a/transformation-config/skills/posthog-docs/description.md b/transformation-config/skills/posthog-docs/description.md new file mode 100644 index 0000000..44a4da5 --- /dev/null +++ b/transformation-config/skills/posthog-docs/description.md @@ -0,0 +1,91 @@ +# PostHog docs authoring + +This skill helps you write and edit documentation that lives on posthog.com. It packages PostHog's official docs handbook into a single source of truth so what you produce matches what the docs team expects. + +## When to use this skill + +Auto-trigger when: + +- Editing or creating any file under `contents/docs/` in the posthog.com repo +- Editing or creating files under `docs/onboarding/` or `docs/published/` in the posthog/posthog monorepo +- The user mentions writing or editing PostHog docs, a product doc, an SDK reference, an API spec, an onboarding guide, "docs for X product", or "the PostHog docs" + +Do **not** trigger for: + +- Blog posts, tutorials, handbook pages, or marketing pages on posthog.com (those follow PostHog's general content style guide, not the docs style guide) +- Internal CLAUDE.md or AGENTS.md files +- Engineering RFCs, READMEs, or code comments + +## Universal rules (apply to every PostHog doc) + +These are the rules that come up most often. Follow them without needing to load any reference file. + +1. **Address the reader as "you".** Never "the user", "developers", or "we". +2. **Active voice, present tense.** "PostHog captures events" – not "events will be captured by PostHog". +3. **Sentence case for headings.** "How to create a feature flag" – not "How To Create A Feature Flag". +4. **American English** with the **Oxford comma**. +5. **British-style en dash with spaces** ( – ), not em dash. On Mac: Option + hyphen. +6. **Use straight quotes and apostrophes**, never curly ones. +7. **Capitalize PostHog product names** as proper nouns (Product Analytics, Session Replay, Feature Flags). +8. **Never** call the project token an "API key". The **project token** (`phs_...`) is public and goes in SDKs. The **personal API key** (`phx_...`) is private and for server-side API access. +9. **Default to "PostHog"**, not "PostHog Cloud" – only specify "Cloud" when contrasting with self-hosted. +10. **Avoid trivializing words**: don't write "simply", "just", "easily", "obviously", "of course", "clearly". +11. **Use relative URLs for internal links** (`/docs/feature-flags`, not `https://posthog.com/docs/feature-flags`). +12. **Bold UI elements** instead of quoting them: Click **New insight**. +13. **`snake_case` for all PostHog event and property names** in code examples. Never camelCase or PascalCase. +14. **Don't use stock Tailwind colors** in any embedded styles – only PostHog tokens. + +If you violate any of the above, fix it before considering a doc done. + +## Where docs live (orientation) + +PostHog docs are split between two repos. Knowing where content lives prevents wasted edits. + +- **posthog.com repo (`contents/docs/`)** – most product docs, marketing-adjacent docs, hand-rolled API overviews, blog posts, tutorials, the non-engineering handbook. +- **posthog/posthog monorepo (`docs/published/`)** – engineering handbook pages and product docs that are tightly coupled to monorepo code (e.g., surveys SDK feature support). +- **posthog/posthog monorepo (`docs/onboarding/`)** – the **single source** for in-app installation/onboarding instructions. The website pulls these in automatically. Do not duplicate this content in the website repo. Use the onboarding-docs.md reference for onboarding docs. + +## Reference files (load on demand) + +The files below are deep references. Load the ones relevant to the current task – don't load all of them up front. + +| File | When to load | +|------|--------------| +| [references/style-guide.md](references/style-guide.md) | **Always load** for any docs writing or editing task. Covers voice, grammar, formatting, code conventions, links, screenshots, and word choice. | +| [references/mdx-and-components.md](references/mdx-and-components.md) | Load when working in any `.mdx` file under `contents/docs/`. Covers frontmatter, snippets, magic placeholders like ``, and the full component library (``, ``, ``, ``, etc.). | +| [references/product-docs.md](references/product-docs.md) | Load when creating or restructuring a **product's docs section** (Overview, Getting started, Concepts, Guides, PostHog AI, Resources). Use Error Tracking docs as the reference template. | +| [references/onboarding-docs.md](references/onboarding-docs.md) | Load only when creating, migrating, or modifying **shared in-app onboarding/installation content** (the stuff that renders both in-app and on the website). | +| [references/sdk-reference.md](references/sdk-reference.md) | Load only when working on **SDK reference docs** (the auto-generated method/class/type references stored as HogRef JSON in each SDK repo). | +| [references/api-specs.md](references/api-specs.md) | Load only when working on **API specifications** under `/docs/api/` – particularly when figuring out whether a page is hand-rolled or generated, or how to update OpenAPI-driven endpoints. | + +## Quick decision tree + +- *"Edit a typo or sentence in an existing doc"* – universal rules above are usually enough. Load `style-guide.md` if the change involves rewording. +- *"Add a callout, step list, or screenshot to a doc"* – load `style-guide.md` + `mdx-and-components.md`. +- *"Write a new product doc page"* (e.g., a guide, concept, or troubleshooting page) – load `style-guide.md` + `mdx-and-components.md` + `product-docs.md`. +- *"Add or change an installation page for a product"* – load `onboarding-docs.md` first to confirm whether the product uses the shared rendering pattern. If it does, the source lives in the monorepo, not here. +- *"Add or update an SDK reference"* – load `sdk-reference.md`. The source likely lives in the SDK repo, not posthog.com. +- *"Document a new API endpoint"* – load `api-specs.md`. The source likely lives in the posthog/posthog repo (Django serializers + `@validated_request`), not posthog.com. + +## Tooling + +PostHog enforces style through three tools, in roughly this order: + +1. **Vale** – prose linter that runs in PRs and catches style guide violations. +2. **InKeep docs writer** – AI agent that uses these style guides as context when drafting docs PRs. +3. **This skill** – agent skill for use in Claude Code and similar tools. + +Before opening a PR, run: + +```bash +pnpm format:docs +``` + +to auto-fix MDX whitespace issues that commonly break the parser. + +## Boundaries + +- **Never** invent components. If you're not sure a component exists, check `src/components/` in posthog.com or look at how existing docs use it. If still unsure, ask. +- **Never** move or rename a published doc page without adding a redirect in `vercel.json`. +- **Never** edit the website's installation MDX stubs to change content – change the source in the monorepo. +- **Never** copy patterns from a single page and assume they're the standard. Cross-reference at least two examples or check the relevant reference file. diff --git a/transformation-config/skills/posthog-docs/references/api-specs.md b/transformation-config/skills/posthog-docs/references/api-specs.md new file mode 100644 index 0000000..b1b92d6 --- /dev/null +++ b/transformation-config/skills/posthog-docs/references/api-specs.md @@ -0,0 +1,245 @@ +# API specifications + +This file covers PostHog's **API specification docs** under `/docs/api/`. Load it only when you're working on API spec pages – particularly to figure out whether a page is hand-rolled or auto-generated, or how to update an OpenAPI-driven endpoint. + +PostHog's API specifications are (mostly) generated automatically from the OpenAPI spec. There's tooling to generate the API specification markdown files from the OpenAPI spec. + +--- + +## Where API specs are published + +When you run the PostHog app locally, the API spec is available at [`/api/schema/`](https://app.posthog.com/api/schema/), and you can browse it via [Swagger UI](https://app.posthog.com/api/schema/swagger-ui/). + +On the website, API specs live at [`/docs/api/`](https://posthog.com/docs/api). **Some pages are hand-rolled, some are generated.** Knowing which is which determines how you make a change. + +| Page | Type | +|------|------| +| [Overview](https://posthog.com/docs/api) | hand-rolled | +| [Capture](https://posthog.com/docs/api/capture) | hand-rolled | +| [Flags](https://posthog.com/docs/api/flags) | hand-rolled | +| [Queries](https://posthog.com/docs/api/queries) | hand-rolled | +| [Actions](https://posthog.com/docs/api/actions) | generated | +| [Alerts](https://posthog.com/docs/api/alerts) | generated | +| [Activity log](https://posthog.com/docs/api/activity-log) | generated | +| [Annotations](https://posthog.com/docs/api/annotations) | generated | +| [Batch exports](https://posthog.com/docs/api/batch-exports) | generated | +| [Cohorts](https://posthog.com/docs/api/cohorts) | generated | +| [Dashboards](https://posthog.com/docs/api/dashboards) | generated | +| [Dashboard templates](https://posthog.com/docs/api/dashboard-templates) | generated | +| [Early access features](https://posthog.com/docs/api/early-access-feature) | generated | +| [Endpoints](https://posthog.com/docs/api/endpoints) | generated | +| [Environments](https://posthog.com/docs/api/environments) | generated | +| [Event definitions](https://posthog.com/docs/api/event-definitions) | generated | +| [Events](https://posthog.com/docs/api/events) | generated | +| [Experiments](https://posthog.com/docs/api/experiments) | generated | +| [Feature flags](https://posthog.com/docs/api/feature-flags) | generated | +| [Groups](https://posthog.com/docs/api/groups) | generated | +| [Groups types](https://posthog.com/docs/api/groups-types) | generated | +| [Hog functions](https://posthog.com/docs/api/hog-functions) | generated | +| [Insights](https://posthog.com/docs/api/insights) | generated | +| [Invites](https://posthog.com/docs/api/invites) | generated | +| [Members](https://posthog.com/docs/api/members) | generated | +| [Notebooks](https://posthog.com/docs/api/notebooks) | generated | +| [Organizations](https://posthog.com/docs/api/organizations) | generated | +| [Persons](https://posthog.com/docs/api/persons) | generated | +| [Projects](https://posthog.com/docs/api/projects) | generated | +| [Property definitions](https://posthog.com/docs/api/property-definitions) | generated | +| [Query](https://posthog.com/docs/api/query) | generated | +| [Roles](https://posthog.com/docs/api/roles) | generated | +| [Session recordings](https://posthog.com/docs/api/session-recordings) | generated | +| [Session recording playlists](https://posthog.com/docs/api/session-recording-playlists) | generated | +| [Sessions](https://posthog.com/docs/api/sessions) | generated | +| [Subscriptions](https://posthog.com/docs/api/subscriptions) | generated | +| [Surveys](https://posthog.com/docs/api/surveys) | generated | +| [Users](https://posthog.com/docs/api/users) | generated | +| [Web Analytics](https://posthog.com/docs/api/web-analytics) | generated | + +--- + +## How the website ingests the OpenAPI spec + +The website ingests the OpenAPI spec during the Gatsby build process in two stages: + +1. **During `sourceNodes`**: the OpenAPI spec is fetched and parsed using `OpenAPIParser` and `MenuBuilder` from the `redoc` library. This creates a structured menu of API endpoints used for navigation. The menu groups endpoints and handles pagination for groups with more than 20 items. +2. **During `onPostBuild`**: the build fetches the OpenAPI spec from `https://app.posthog.com/api/schema/` (or from `POSTHOG_OPEN_API_SPEC_URL` if set). The spec is then passed to `generateApiSpecMarkdown()`, which: + - Iterates through all paths and HTTP methods in the spec + - For each endpoint with an `operationId`, creates a markdown file named after the operation ID + - Recursively extracts all referenced component schemas for each endpoint + - Generates markdown files containing the endpoint's OpenAPI JSON in a code block + - Writes them to `public/docs/open-api-spec/` + +The generated markdown files are then available at `/docs/open-api-spec/{operationId}.md` and are included in the docs site's API reference section. + +--- + +## How to update the OpenAPI spec + +For automatically generated pages, the source content comes from the OpenAPI spec. To update them, you typically need to update the spec – which means editing the [`PostHog/posthog`](https://github.com/PostHog/posthog) repository. + +### Updating the page title and description + +> These updates happen in the **`PostHog/posthog.com`** repository. + +**Page title**: update the `titleMap` object in [`src/templates/ApiEndpoint.tsx`](https://github.com/PostHog/posthog.com/blob/master/src/templates/ApiEndpoint.tsx#L85-L120). For example, to change the "Actions" page title, modify the `actions` entry in the map. + +**Page description**: create or update an `overview.mdx` file in the corresponding API folder. The file should be at `contents/docs/api/{name}/overview.mdx`, where `{name}` matches the API endpoint name (e.g., `events`, `feature-flags`). + +> Example: [`contents/docs/api/events/overview.mdx`](https://github.com/PostHog/posthog.com/blob/master/contents/docs/api/events/overview.mdx) contains the description that appears at the top of the Events API page. + +### Updating the endpoint title and description + +> These updates happen in the **`PostHog/posthog`** repository. + +**Endpoint title**: the title is auto-generated from the `operationId` in the OpenAPI spec via the `generateName()` function in [`src/templates/ApiEndpoint.tsx`](https://github.com/PostHog/posthog.com/blob/master/src/templates/ApiEndpoint.tsx#L128-L137). To customize it, update the `operationId` or description in the Django viewset in the PostHog repo. You essentially update the path to update the title. + +**Endpoint description**: create an MDX file named after the endpoint's `operationId` in the appropriate API folder, at `contents/docs/api/{name}/{operationId}.mdx`. + +> Example: [`contents/docs/api/feature-flags/feature_flags_list.mdx`](https://github.com/PostHog/posthog.com/blob/master/contents/docs/api/feature-flags/feature_flags_list.mdx) adds custom content that appears under the "List all feature flags" endpoint. Content from this file renders **above** the endpoint's description from the OpenAPI spec. + +### Updating endpoint parameters and responses + +The endpoint request body parameters, query parameters, path parameters, response body, response headers, API key scopes, etc. are all defined in the Django serializers and viewsets in the PostHog repo. + +There are two types of "views" in Django, and they need different annotations to generate accurate OpenAPI specs: + +1. **Model-based CRUD views** – backed by Django models. They map literally to model fields and generally don't need extra annotations for accurate request/response definitions. +2. **Function-based views** – backed by Python functions, generally annotated with `@action` decorators. These need manual annotation for request/response definitions to be accurate. + +If an endpoint needs additional annotation, use the `@validated_request` decorator. It uses the serializers passed in for **both** validation and OpenAPI annotation, ensuring the OpenAPI spec stays accurate (or that we know when it's not). + +#### Basic usage + +```python +from posthog.api.mixins import validated_request +from drf_spectacular.utils import OpenApiResponse +from rest_framework import serializers, status +from rest_framework.response import Response + +# Django uses serializer to validate request body data, validated request can infer the request and response schemas from the serializer definitions. +class EventCaptureRequestSerializer(serializers.Serializer): + event = serializers.CharField(max_length=200, help_text="Event name") + distinct_id = serializers.CharField(max_length=200, help_text="User distinct ID") + properties = serializers.DictField(required=False, default=dict) + +class EventCaptureResponseSerializer(serializers.Serializer): + status = serializers.ChoiceField(choices=["ok", "queued"]) + event_id = serializers.UUIDField() + distinct_id = serializers.CharField() + +@validated_request( + request_serializer=EventCaptureRequestSerializer, + responses={ + 200: OpenApiResponse(response=EventCaptureResponseSerializer), + }, + summary="Capture an event", + description="Sends an event to PostHog for tracking", +) +def capture_event(self, request): + # Access validated request body data + event_name = request.validated_data["event"] + distinct_id = request.validated_data["distinct_id"] + + # Process the event... + + return Response( + { + "status": "ok", + "event_id": str(uuid.uuid4()), + "distinct_id": distinct_id, + }, + status=status.HTTP_200_OK, + ) +``` + +#### Validating query parameters + +Use `query_serializer`: + +```python +class QueryParamSerializer(serializers.Serializer): + page = serializers.IntegerField(required=False, default=1) + limit = serializers.IntegerField(required=False, default=10, max_value=100) + include_deleted = serializers.BooleanField(required=False, default=False) + +@validated_request( + query_serializer=QueryParamSerializer, + responses={ + 200: OpenApiResponse(response=ListResponseSerializer), + }, +) +def list_items(self, request): + page = request.validated_query_data["page"] + limit = request.validated_query_data["limit"] + return Response(...) +``` + +#### Multiple response status codes + +```python +@validated_request( + request_serializer=EventCaptureRequestSerializer, + responses={ + 200: OpenApiResponse(response=EventCaptureResponseSerializer), + 400: OpenApiResponse(response=ErrorResponseSerializer), + 500: OpenApiResponse(response=ErrorResponseSerializer), + }, +) +def capture_event(self, request): + try: + return Response(..., status=status.HTTP_200_OK) + except ValidationError as e: + return Response( + {"type": "validation_error", "code": "invalid", "detail": str(e)}, + status=status.HTTP_400_BAD_REQUEST, + ) +``` + +#### No response body + +Use `None`: + +```python +@validated_request( + responses={ + 204: None, # No response body + }, +) +def delete_item(self, request, pk): + return Response(status=status.HTTP_204_NO_CONTENT) +``` + +#### Validation modes + +By default, `@validated_request` uses strict validation for requests (raises on invalid data) and non-strict for responses (logs warnings in DEBUG mode). You can override: + +```python +@validated_request( + request_serializer=MySerializer, + responses={200: OpenApiResponse(response=MyResponseSerializer)}, + strict_request_validation=False, # Log warnings instead of raising + strict_response_validation=True, # Raise on invalid responses +) +def my_endpoint(self, request): + # ... +``` + +--- + +## Which endpoints have validated request/response definitions + +The `@validated_request` decorator is new and many endpoints have not been annotated yet. The following are annotated: + +- `tasks` +- `task-runs` +- `feature_flags` +- `feature_value` + +The plan is to slowly annotate all endpoints with `@validated_request` through Q1 2026. + +--- + +## The special case for `Capture` + +Ingestion is essentially an entirely different service and is **not** included in the OpenAPI spec. It also has special limitations like batching and rate limiting that need to be documented separately. It doesn't fit the classic patterns for a RESTful API as well as other endpoints. + +The ingestion team and docs team need to work together to update the OpenAPI spec for the `Capture` endpoint. diff --git a/transformation-config/skills/posthog-docs/references/mdx-and-components.md b/transformation-config/skills/posthog-docs/references/mdx-and-components.md new file mode 100644 index 0000000..acf2b15 --- /dev/null +++ b/transformation-config/skills/posthog-docs/references/mdx-and-components.md @@ -0,0 +1,297 @@ +# MDX and components for PostHog docs + +This file covers the MDX features and components available when writing pages under `contents/docs/` on posthog.com. Load this file whenever you're touching an `.mdx` file in the docs. + +The website's core technical architecture is built and maintained by the website team. For deeper detail beyond what's here, see the handbook pages on the website and on MDX components. + +--- + +## Frontmatter + +Every `.mdx` page supports frontmatter that Gatsby uses to configure page metadata. + +```mdx +--- +title: Install PostHog for React +platformLogo: react +showStepsToc: true +--- + +This guide walks you through installing PostHog for React. +``` + +Available fields: + +| Field | Purpose | Example | +|-------|---------|---------| +| `title` | Page title | `React installation` | +| `platformLogo` | Platform icon key for installation pages | `react`, `python`, `nodejs` | +| `showStepsToc` | Show steps in the right-sidebar TOC | `true` | +| `hideRightSidebar` | Hide the right sidebar TOC (used on start-here and changelog pages) | `true` | +| `contentMaxWidthClass` | Customize the width of the main content column | `max-w-5xl` | +| `tableOfContents` | Override the auto-generated TOC with custom entries | `[{ url: 'section-id', value: 'Section Name', depth: 1 }]` | + +--- + +## Snippets for content reuse + +Create snippets in a `_snippets/` directory for content you want to reuse across multiple pages. + +**When to create a snippet:** + +- Content appears in 2+ pages +- Event schemas or property tables +- Platform-specific code blocks +- Reusable UI components + +### MDX snippets + +Use for static reusable content like tables, callouts, or text blocks. + +```mdx file=_snippets/event-properties.mdx +The error event includes the following properties: + +| Property | Type | Description | +|----------|------|-------------| +| `$exception_message` | string | The error message | +| `$exception_type` | string | The error type | +``` + +Use it in a page: + +```mdx +import EventProperties from './_snippets/event-properties.mdx' + + +``` + +### TSX snippets + +Use for dynamic content – lightweight components or React hooks. + +```tsx +// _snippets/installation-platforms.tsx +import usePlatformList from 'hooks/docs/usePlatformList' + +export default function InstallationPlatforms() { + const platforms = usePlatformList('docs/[product]/installation', 'installation') + return +} +``` + +Use it in a page: + +```mdx +import InstallationPlatforms from './_snippets/installation-platforms.tsx' + + +``` + +If a TSX snippet contains substantial logic, create a reusable component or hook in `/src/components/` or `/src/hooks/` instead. + +--- + +## Magic placeholders + +Magic placeholder strings get auto-replaced with values from the user's project when they view the docs while logged in. If they're not logged in, the placeholder displays as-is. + +| Placeholder | Description | Default | +|-------------|-------------|---------| +| `` | Your PostHog project token | n/a | +| `` | Your PostHog project name | n/a | +| `` | Your PostHog instance URL | n/a | +| `` | Your PostHog client API host | `https://us.i.posthog.com` | +| `` | Your PostHog region (us/eu) | n/a | +| `` | Default values for posthog-js | `2026-01-30` | +| `` | Your proxy path | `relay-XXXX` (last 4 digits of project token) | + +Use them in a code block: + +```js +const client = new PostHog('', { host: '' }) +``` + +**Use these whenever you write a code example that includes a token or host.** Hard-coded example values like `phc_abc123` are worse for users. + +--- + +## Components + +### Screenshots + +For UI screenshots with light and dark variants: + +```mdx + +``` + +### Videos + +For `.mp4` or `.mov` files: + +```mdx + +``` + +### Multi-language code blocks + +For code examples in multiple languages: + +````mdx + + +```js +// JavaScript example +``` + +```python +# Python example +``` + + +```` + +### Callout boxes + +Use callouts so skimmers don't miss essential information. + +```jsx + + Here is some information + +``` + +Three styles, by use case: + +- **`fyi`** – helpful but not critical info. +- **`action`** – tasks developers should complete and not miss. +- **`caution`** – flags potential misconfiguration, data loss, or other churn vectors. + +Valid icons come from PostHog's icon library (e.g., `IconInfo`, `IconWarning`). + +**Don't overuse callouts.** If the page has more than 2-3, the signal disappears. + +### Steps + +Use `` for content that walks the reader through a strict sequence (how-to guides, step-by-step tutorials). + +```mdx + + + + +Steps are automatically numbered. + + + + + +Write the _content_ in **markdown**. + + + + + +Add checkpoints to help readers verify their progress. + + + + +``` + +> **Watch the whitespace.** PostHog's MDX parser does not play nice with certain whitespace. When using ``: +> +> - Add a line break after the opening component tags. +> - Avoid using 4-space indents. + +### Decision tree + +For helping users choose between 2–6 options: + +```jsx + { + // return recommendation based on answers + }} +/> +``` + +### PostHog AI components + +PostHog AI (formerly known as Max AI) has two components for embedding AI help in docs. + +**``** opens the PostHog AI chat directly on the website. Use it on docs pages where users may need help understanding concepts or troubleshooting. Unlike `` (which links to the PostHog app), `` keeps users in the docs context. + +```jsx + +``` + +**``** is for troubleshooting sections: + +```mdx +## Have a question? Ask PostHog AI + + +``` + +--- + +## Platform logos + +All platform logos are centralized in `src/constants/logos.ts`. To add a new platform: + +1. Upload the SVG to Cloudinary. +2. Add a key to `src/constants/logos.ts` in `camelCase`. +3. Reference it in MDX frontmatter: `platformLogo: myPlatform`. + +Use consistent naming: `stripe`, `react`, `nodejs`, etc. + +--- + +## Debugging MDX issues + +Common causes of MDX parsing failures: + +- Deep indentation – stay at 2 spaces or less. +- Missing line breaks after opening JSX tags or before closing tags. +- Components that aren't imported correctly. +- "Empty" lines that contain spaces (must be completely empty). +- Snippets that share file names. + +To auto-fix common issues: + +```bash +pnpm format:docs +``` + +Run this before committing. diff --git a/transformation-config/skills/posthog-docs/references/onboarding-docs.md b/transformation-config/skills/posthog-docs/references/onboarding-docs.md new file mode 100644 index 0000000..23085ea --- /dev/null +++ b/transformation-config/skills/posthog-docs/references/onboarding-docs.md @@ -0,0 +1,293 @@ +# Shared onboarding docs + +This file covers PostHog's **shared onboarding/installation docs** – the special architecture where one source renders content in two places: the in-app onboarding flow and the website's getting started pages. + +Load this file only when creating, migrating, or modifying installation/onboarding content for a product. + +These are some of the first pieces of docs a new user sees. They show users how to quickly install a product, so they need to be up to date and accurate. + +--- + +## The pattern at a glance + +There is a **single source of truth** in the [`posthog/posthog`](https://github.com/PostHog/posthog) repo under [`docs/onboarding/`](https://github.com/PostHog/posthog/tree/master/docs/onboarding). You only update onboarding content there – the website pulls it automatically on its next build. + +**Never duplicate onboarding content into the posthog.com repo.** The website only contains thin MDX stubs that import the shared content. + +--- + +## Which products use shared onboarding docs + +This is a relatively new pattern, so old onboarding docs are still being migrated. As of February 2026: + +| Product | Status | +|---------|--------| +| LLM analytics | Migrated | +| Product Analytics | Migrated | +| Web Analytics | Migrated | +| Session Replay | Migrated | +| Feature Flags | Migrated | +| Experiments | Migrated | +| Error Tracking | Migrated | +| Surveys | Migrated | +| Workflows | Migrated | +| Data Pipelines | Not yet migrated | +| Data Warehouse | Not yet migrated | +| Revenue Analytics | Not yet migrated | +| PostHog AI | Not yet migrated | +| Logs | Not yet migrated | +| Endpoints | Not yet migrated | + +--- + +## How it works + +Onboarding content is written once as React components in the monorepo, then rendered in two places: + +1. **PostHog monorepo (in-app onboarding):** the PostHog app imports docs components directly and wraps them with `OnboardingDocsContentWrapper`, which provides UI components like `Steps`, `CodeBlock`, etc. +2. **PostHog.com repo (website):** the website pulls docs components from the monorepo via `gatsby-source-git` (a Gatsby plugin), then renders them through MDX stub files that use a similar `OnboardingContentWrapper` to provide compatible UI components. + +Both wrappers expose the same component names (`Steps`, `CodeBlock`, `CalloutBox`, etc.), so the shared content renders correctly in either place. When you merge changes to `master` in `posthog/posthog`, the website automatically pulls the updated content on its next build. + +```mermaid +flowchart LR + subgraph website["posthog.com repo"] + gatsby["gatsby-source-git
(pulls on build)"] + mdx["MDX stub files"] + wrapper2["OnboardingContentWrapper"] + ui2["Docs pages"] + gatsby --> mdx --> wrapper2 --> ui2 + end + + subgraph monorepo["posthog/posthog repo"] + docs["docs/onboarding/*.tsx
product installation docs"] + wrapper1["OnboardingDocsContentWrapper"] + ui1["In-app onboarding flow"] + docs --> wrapper1 --> ui1 + end + docs -.->|"auto-sync"| gatsby +``` + +### File structure for each repo + +``` +posthog/posthog +├── docs/onboarding/ +│ └── your-product/ +│ ├── index.ts # Barrel file re-exports all Installation components + snippets +│ ├── sdk-name.tsx # getSteps + createInstallation +│ └── _snippets/ +│ └── reusable-snippet.tsx +│ +└── frontend/src/scenes/onboarding/ + └── sdks/your-product/ + └── YourProductSDKInstructions.tsx # withOnboardingDocsWrapper + +posthog/posthog.com +└── contents/docs/your-product/ + └── installation/ + ├── sdk-name.mdx # MDX stub + └── _snippets/ + ├── prefix-installation-wrapper.tsx # Single file with ALL wrappers + └── shared-helpers.tsx # modifySteps helpers +``` + +For a complete working example, see the **Session Replay** implementation: + +| Repo | File | +|------|------| +| posthog/posthog | [`docs/onboarding/session-replay/`](https://github.com/PostHog/posthog/blob/master/docs/onboarding/session-replay/) | +| posthog.com | [`react.mdx`](https://github.com/PostHog/posthog.com/blob/master/contents/docs/session-replay/installation/react.mdx) | +| posthog.com | [`sr-installation-wrapper.tsx`](https://github.com/PostHog/posthog.com/blob/master/contents/docs/session-replay/installation/_snippets/sr-installation-wrapper.tsx) | + +--- + +## How to create or migrate onboarding docs + +### Step 1: Create the shared component in posthog/posthog + +1. Navigate to the product directory in `docs/onboarding/`. Create it if needed: `docs/onboarding/your-product/`. +2. Create a new `.tsx` file: `docs/onboarding/your-product/filename.tsx`. +3. Export a step function and Installation component. Use `createInstallation` to handle rendering automatically: + + ```tsx + // docs/onboarding/feature-flags/python.tsx + import { OnboardingComponentsContext, createInstallation } from 'scenes/onboarding/OnboardingDocsContentWrapper' + import { getPythonSteps as getPythonStepsPA } from '../product-analytics/python' + import { StepDefinition } from '../steps' + + // Step function receives a single context object with all components + export const getPythonSteps = (ctx: OnboardingComponentsContext): StepDefinition[] => { + const { CodeBlock, Markdown, dedent, snippets } = ctx + + // Reuse installation steps from product-analytics + const installationSteps = getPythonStepsPA(ctx) + + // Add feature-flag-specific steps + const flagSteps: StepDefinition[] = [ + { + title: 'Evaluate feature flags', + badge: 'required', + content: ( + <> + Check if a feature flag is enabled: + {snippets?.BooleanFlagSnippet && } + + ), + }, + ] + + return [...installationSteps, ...flagSteps] + } + + // createInstallation wraps your step function into a ready-to-use component + export const PythonInstallation = createInstallation(getPythonSteps) + ``` + + **Key patterns:** + + - You can reuse installation steps from product analytics by calling their step function with the same context. + - Step badges include `required`, `optional`, or `recommended`. + +4. For reusable snippets, create them in `docs/onboarding//_snippets/` and export a named component. +5. Create the in-app wrapper in `frontend/src/scenes/onboarding/sdks/your-product/`. Use the `withOnboardingDocsWrapper` helper: + + ```tsx + // frontend/src/scenes/onboarding/sdks/feature-flags/FeatureFlagsSDKInstructions.tsx + import { PythonInstallation, BooleanFlagSnippet, MultivariateFlagSnippet } from '@posthog/shared-onboarding/feature-flags' + import { PythonEventCapture } from '@posthog/shared-onboarding/product-analytics' + import { withOnboardingDocsWrapper } from '../shared/onboardingWrappers' + + const PYTHON_SNIPPETS = { + PythonEventCapture, + BooleanFlagSnippet, + MultivariateFlagSnippet, + } + + const FeatureFlagsPythonInstructionsWrapper = withOnboardingDocsWrapper({ + Installation: PythonInstallation, + snippets: PYTHON_SNIPPETS, + }) + + export const FeatureFlagsSDKInstructions: SDKInstructionsMap = { + [SDKKey.PYTHON]: FeatureFlagsPythonInstructionsWrapper, + // ... other SDKs + } + ``` + +6. Test in the app by running the monorepo locally and navigating to `localhost:8010/onboarding`. Select your product and test. + +### Step 2: Create the website stub in posthog.com + +1. To test locally, point `gatsby-source-git` at your monorepo branch via the `GATSBY_POSTHOG_BRANCH` environment variable: + + ```bash + GATSBY_POSTHOG_BRANCH=your-branch-name pnpm start + ``` + +2. Create a **single TSX wrapper file** at `contents/docs//installation/_snippets/-installation-wrapper.tsx` that exports all SDK wrappers: + + ```tsx + // contents/docs/session-replay/installation/_snippets/sr-installation-wrapper.tsx + import React from 'react' + import { + JSWebInstallation, + ReactInstallation, + NextJSInstallation, + // ... import all SDK installations + SessionReplayFinalSteps, + } from 'onboarding/session-replay' + import { OnboardingContentWrapper } from 'components/Docs/OnboardingContentWrapper' + import { addNextStepsStep } from './shared-helpers' + + const SNIPPETS = { + SessionReplayFinalSteps, + } + + // Export a wrapper for each SDK + export const SRJSWebInstallationWrapper = () => ( + + + + ) + + export const SRReactInstallationWrapper = () => ( + + + + ) + + export const SRNextJSInstallationWrapper = () => ( + + + + ) + + // ... repeat for all SDKs + ``` + + The `modifySteps` prop lets you add website-specific steps (like "Next steps") that aren't needed in-app. + +3. Create an MDX stub file for each SDK at `contents/docs//installation/.mdx`: + + ```mdx + --- + title: React session replay installation + platformLogo: react + showStepsToc: true + --- + + + + import { SRReactInstallationWrapper } from './_snippets/sr-installation-wrapper.tsx' + + + ``` + +4. Test locally with `pnpm start` and verify the page renders at the expected URL. +5. Commit and merge **both** the `posthog/posthog` and `posthog/posthog.com` PRs. + +--- + +## Exceptions to the standard pattern + +The architecture above works well for products that have their own SDK installation steps – but not every product fits this mold. Some products are exceptions, and that's fine. **Only use shared onboarding when it makes sense.** + +### Workflows + +Installing an SDK is optional for Workflows, so it doesn't define its own shared doc components. There are **no files in `docs/onboarding/workflows/`**. + +Instead, Workflows reuses the Product Analytics `Installation` components directly and transforms them with a `modifySteps` function at the in-app level: + +```tsx +// frontend/src/scenes/onboarding/sdks/workflows/WorkflowsSDKInstructions.tsx +import { ReactInstallation, PythonInstallation } from '@posthog/shared-onboarding/product-analytics' +import { withOnboardingDocsWrapper } from '../shared/onboardingWrappers' + +// Filter out product-analytics-specific steps and add a workflows-specific final step +function workflowsModifySteps(steps: StepDefinition[]): StepDefinition[] { + const installationSteps = steps.filter( + (step) => !['Send events', 'Send an event', 'Send events via the API'].includes(step.title) + ) + return [ + ...installationSteps, + { + title: 'Set up workflows', + badge: 'recommended', + content: , + }, + ] +} + +const WorkflowsReactWrapper = withOnboardingDocsWrapper({ + Installation: ReactInstallation, + modifySteps: workflowsModifySteps, +}) +``` + +This works because Workflows only needs a PostHog SDK installed (the same install steps as Product Analytics), then swaps the final "send events" step for a "set up Workflows" step. Everything lives in a single `WorkflowsSDKInstructions.tsx` file – no shared docs directory, no website stubs. + +> **When to use this pattern**: if your product's onboarding is essentially "install the PostHog SDK + do one product-specific thing," consider reusing existing Installation components with `modifySteps` instead of creating a full set of shared doc files. Avoids unnecessary duplication. diff --git a/transformation-config/skills/posthog-docs/references/product-docs.md b/transformation-config/skills/posthog-docs/references/product-docs.md new file mode 100644 index 0000000..ad5575e --- /dev/null +++ b/transformation-config/skills/posthog-docs/references/product-docs.md @@ -0,0 +1,241 @@ +# How to write PostHog product docs + +This file covers how to **structure** product docs on posthog.com. Load it whenever you're creating a new product doc page or restructuring an existing product's docs section. + +PostHog has a standard, flexible structure for product docs. Each section serves a different purpose in the developer journey. **Use [Error Tracking docs](/docs/error-tracking) as the reference template** – it's the strongest example of well-structured documentation. + +> **Disclaimer**: PostHog's products vary widely (Data Pipelines is integration-heavy; PostHog AI and Workflows are UI-oriented). They require different content emphases, and that's okay. Adapt this structure to your product's needs – but **start with this structure**. It's worked well for other products in both docs-to-product conversion and user feedback. + +--- + +## The six categories + +Every product doc page should fit into one of these: + +1. [**Overview**](#overview) – landing page for your product docs. The "book cover." +2. [**Getting started**](#getting-started) – the minimum to install and stand up your product. +3. [**Concepts**](#concepts) – core abstractions and building blocks. +4. [**Guides**](#guides) – task-oriented tutorials for features and workflows. +5. [**PostHog AI**](#posthog-ai) – AI workflows specific to your product. +6. [**Resources**](#resources) – pricing, troubleshooting, changelog, references, anything that doesn't fit the other categories. + +## Sidebar navigation + +The sidebar mirrors the docs structure. The hierarchy drives how users discover and navigate: + +``` +Docs sidebar +| +├── Your product +| └── Overview # Landing page or home page +├── Getting started +| ├── Start here # "Syllabus" page +| ├── Installation +│ │ ├── Framework 1 # Installation quickstart +│ │ └── Framework 2 +│ └── Basic config # Minimal setup quickstart +├── Concepts +| ├── Concept 1 # In-depth product explainer +| └── Concept 2 +├── Guides +| ├── Guide 1 # Tutorial for feature +| └── Guide 2 +├── PostHog AI +| ├── AI guide 1 # Tutorial for AI feature +| └── AI guide 2 +└── Resources + ├── Pricing # Pricing and usage limits + ├── Troubleshooting # Common issues and solutions + ├── Changelog # Product updates + └── References # Links to SDK and API docs +``` + +--- + +## Overview + +The Overview is the landing page for your product docs. Think of it like a book cover – people *will* judge your product on a quick glance. + +It needs to work like an effective one-pager. Imagine a busy engineering manager evaluating multiple solutions. With a quick scan, they need to confirm: + +- What is this product? +- Is it compatible with my tech stack? +- Does it have the essential features I expect or need? + +> **Example** – [Error Tracking overview](/docs/error-tracking) + +**Your Overview page should include:** + +- Description of the product and its value proposition +- List of key features and capabilities +- List of supported languages, frameworks, and integrations +- List of PostHog platform / cross-product features +- CTAs for next steps in the docs +- Visual components and elements to make it scannable and appealing + +--- + +## Getting started + +The Getting started section gets new users up and running with your product as quickly as possible – with *just* enough context to understand what's going on. Streamline for minimal setup. + +**Avoid** including advanced or complex features here. Those go in [Guides](#guides). + +**Your Getting started section should include:** + +- A **Start here** page +- Installation quickstarts +- Basic config quickstarts (optional, e.g. "upload source maps") + +### Start here + +The Start here page shows the product adoption journey at a high level. It's the syllabus or quest log – a high-level view of milestones the user needs to hit to be successful. + +Users are more willing to invest time when they can see what they're signing up for. One setback (a missing link, an outdated config) can be enough to lose them if they don't know where they are in the process. + +These pages are **high-converting pages for paid ads**, so they matter. Use the `` component to create a visual roadmap. + +> **Example** – [Error Tracking start here page](/docs/error-tracking/start-here) + +**Your Start here page should include:** + +- `` sections for each milestone in the adoption journey +- Screenshots and media +- Links to deeper docs +- A "Use for free" section at the end + +### Installation + +The installation pages are quickstarts for your product. Create one installation page per platform, framework, or language using the `` component. + +Installation pages have a **special architecture**: they render the same content as the in-app onboarding flow from the monorepo. The single source of truth lives in the [posthog/posthog monorepo](https://github.com/PostHog/posthog/tree/master/docs/onboarding); the website pulls the content automatically. + +**See [onboarding-docs.md](onboarding-docs.md) for full details on creating or migrating installation guides to the shared rendering architecture.** + +> **Example** – [Error Tracking installation docs](/docs/error-tracking/installation) + +**Your Installation section should include:** + +- An installation index page listing all supported platforms +- Installation quickstarts for each framework or language using `` + +> The installation index page displays a grid of platform cards (frameworks, languages) generated automatically from the sidebar nav with logos and icons: +> +> 1. The index page imports a snippet that calls `usePlatformList()`. +> 2. The hook reads all MDX files in the installation folder. +> 3. It sorts them based on the order defined in `src/navs/index.js`. +> 4. Each platform's logo comes from the `platformLogo` frontmatter field. + +--- + +## Concepts + +The Concepts section explains your product's core abstractions or building blocks in depth. The goal is to explain *why* the product behaves the way it does – not just how to use it. + +If your product uses any terminology that carries specific meaning or implies functionality, it probably deserves a concept page. Some concepts are industry-wide; others are PostHog-specific. From Error Tracking: + +- **Exceptions** – industry-wide concept +- **Stack traces** – industry-wide concept +- **Issues** – PostHog-specific concept (group of exceptions in the app UI) +- **Fingerprints** – PostHog-specific concept (low-level identifier for exceptions on SDK capture) + +Use Mermaid diagrams for data flows and relationships, tables for definitions, and screenshots for in-app UI elements. + +> **Examples** – [Fingerprints](/docs/error-tracking/fingerprints), [Issues and exceptions](/docs/error-tracking/issues-and-exceptions), [Stack traces](/docs/error-tracking/stack-traces), [Releases](/docs/error-tracking/releases) + +**Your Concepts section should include:** + +- In-depth explainers for each product concept +- Mermaid diagrams for data flows and relationships +- Tables for definitions with context + +--- + +## Guides + +The Guides section contains tutorials framed around accomplishing specific use cases, jobs-to-be-done, or goals. + +**Why "Guides" and not "Features"?** Because it's task-oriented and focuses on outcomes. We don't want a sidebar listing branded feature names – those don't mean anything to the user. What your feature is *called* is secondary to what it *enables*. + +In general, one page per major feature or workflow. Each page should include: + +- A brief intro explaining what the guide helps you do +- Instructions on how to use the feature in practice +- Screenshots of the UI + +> **Examples** – [Capture exceptions](/docs/error-tracking/capture), [Manage and resolve issues](/docs/error-tracking/managing-issues), [Send alerts](/docs/error-tracking/alerts), [Set up integrations](/docs/error-tracking/integrations) + +**Your Guides section should include:** + +- One guide per major feature or workflow +- Screenshots showing the feature in the UI +- Step-by-step or general instructions +- A use case or jobs-to-be-done framing + +--- + +## PostHog AI + +The PostHog AI section showcases your product's AI workflows. This includes integrations with PostHog AI itself, MCP-based workflows, or examples of useful prompts or skills. + +Don't be too prescriptive here. The goal is to show off your product's AI capabilities, big or small. + +> **Example** – [Error Tracking PostHog AI docs](/docs/error-tracking/debugging-with-mcp) + +**Your PostHog AI section should include:** + +- Guides for PostHog AI features your product supports +- Guides for AI workflows like MCP +- Guides for AI resources like recommended prompts or skills + +--- + +## Resources + +The Resources section is where useful "lookup" content lives – important standalone pages like pricing, changelog, troubleshooting, and API/SDK references. + +If something doesn't fit neatly into the other categories, it belongs here. + +> **Example** – [Error Tracking resources](/docs/error-tracking/pricing) + +**Your Resources section should include:** + +- Pricing page +- Troubleshooting page +- Changelog page +- Links to SDK and API references +- Other resources + +### Pricing + +Explains the product's pricing model, free tier limits, and how usage is calculated. Transparency is a PostHog differentiator – be clear and upfront. + +Just as importantly, show users **how to stay in control of costs**. Include advice on how to reduce the bill. + +> **Example** – [Error Tracking pricing](/docs/error-tracking/pricing) + +**Your Pricing page should include:** + +- `` calculator component +- Breakdown of how usage or costs are calculated +- A section on how to reduce and cut costs + +### Troubleshooting + +Common issues and solutions that unblock users. Keep this updated based on support tickets and community questions. + +Start with the `` component to enable AI chat support, then use searchable headings with numbered solutions. Each section should be scannable and actionable. + +> **Example** – [Error Tracking troubleshooting](/docs/error-tracking/troubleshooting) + +### Changelog + +Displays changelog entries for your product using the `` component, which filters entries from the main `/changelog` page. + +> **Example** – [Error Tracking changelog](/docs/error-tracking/changelog) + +### API and SDK references + +Links to SDK reference docs and API documentation filtered by product. + +> **Example** – [Error Tracking references](/docs/error-tracking/references) diff --git a/transformation-config/skills/posthog-docs/references/sdk-reference.md b/transformation-config/skills/posthog-docs/references/sdk-reference.md new file mode 100644 index 0000000..bb31a83 --- /dev/null +++ b/transformation-config/skills/posthog-docs/references/sdk-reference.md @@ -0,0 +1,76 @@ +# SDK reference docs + +This file covers PostHog's **SDK reference docs** – the comprehensive method/class/type references for each SDK. Load this file only when working on SDK reference docs specifically. + +SDK references document class signatures, method signatures, and type interfaces for each SDK. They complement the examples in tutorials and guides by providing the comprehensive reference, with all the details. They matter for two audiences: + +- **Developers** doing deep integration work who need parameter and return type details. +- **LLM-based tools** that use them as context to write better PostHog code. + +Tutorials and guides link out to SDK references for parameter/return type details rather than restating them. + +--- + +## Which SDKs have reference docs + +This is an ongoing effort, starting with the most popular SDKs: + +| SDK | Status | +|-----|--------| +| JavaScript Web SDK | Completed | +| Python SDK | Completed | +| Node.js SDK | Completed | +| React Native SDK | Completed | +| iOS SDK | In progress | +| Flutter SDK | Not started | +| Android SDK | Not started | +| Go SDK | Not started | +| Java SDK | Not started | +| Rust SDK | Not started | +| PHP SDK | Not started | +| .NET SDK | Not started | + +--- + +## How SDK reference docs work + +The flow: + +1. SDKs are parsed for basic information – class names, method names, type interfaces. +2. Descriptions, parameters, return types, and examples are extracted from the SDK code or doc comments. +3. The information is rewritten into a standardized JSON format called **HogRef**. HogRef files are stored in each SDK's repository under a `references/` directory. For example, the JavaScript Web SDK reference is stored at [`packages/browser/references/`](https://github.com/PostHog/posthog-js/tree/main/packages/browser/references). +4. When an SDK releases a new version, the reference docs are generated automatically. See an [example workflow](https://github.com/PostHog/posthog-js/blob/main/.github/workflows/generate-references.yml). +5. The Strapi instance behind the website is configured to [fetch the HogRef JSON files](https://github.com/PostHog/squeak-strapi/blob/main/config/cron-tasks.ts) from each SDK's repo on a cron job. +6. The website renders each HogRef JSON file as a table on the SDK reference page. + +Each language works slightly differently in step 1, but the overall flow is the same. + +--- + +## How to create a new SDK reference doc + +To contribute a reference doc for a new SDK: + +1. **Create a script** to parse the SDK's documentation and extract the info into a HogRef JSON file. The script should: + - Parse for class names, method names, and type interfaces + - Extract descriptions, parameters, return types, and examples from the SDK code or doc comments + - Format the information according to the HogRef JSON schema specification + - Store the HogRef JSON file in a `references/` directory in the SDK's repository + - See existing SDK repositories for examples – the [JavaScript Web SDK reference](https://github.com/PostHog/posthog-js/tree/main/packages/browser/references) is a good starting point. +2. **Create a workflow** to regenerate the HogRef JSON whenever a new version of the SDK is released. See an [example workflow](https://github.com/PostHog/posthog-js/blob/main/.github/workflows/generate-references.yml). +3. **Update [`cron-tasks.ts`](https://github.com/PostHog/squeak-strapi/blob/main/config/cron-tasks.ts)** to fetch the HogRef JSON file from the SDK's repository so it ingests on the next cron run. +4. **Verify it renders.** Once the HogRef is ingested, a new page should be created automatically on the website. The website renders the HogRef JSON file as a table on the SDK reference page. +5. **Update existing links.** Find existing links that point to the SDK's GitHub source code and update them to point to the new HogRef-backed reference page instead. + +--- + +## Where reference content lives + +| Layer | Location | +|-------|----------| +| Source data (per SDK) | The SDK's own repo, under `references/` (e.g., [`posthog-js/packages/browser/references/`](https://github.com/PostHog/posthog-js/tree/main/packages/browser/references)) | +| Generation workflow | The SDK's own repo, under `.github/workflows/` (e.g., `generate-references.yml`) | +| Ingestion config | [`squeak-strapi/config/cron-tasks.ts`](https://github.com/PostHog/squeak-strapi/blob/main/config/cron-tasks.ts) | +| Rendering | The website pulls from Strapi and renders as a table on the SDK reference page | + +**You almost never edit reference content directly in posthog.com.** Edit the source comments/types in the SDK repo, let the workflow regenerate the HogRef JSON, and let the cron job sync it into Strapi. diff --git a/transformation-config/skills/posthog-docs/references/style-guide.md b/transformation-config/skills/posthog-docs/references/style-guide.md new file mode 100644 index 0000000..2fed3a5 --- /dev/null +++ b/transformation-config/skills/posthog-docs/references/style-guide.md @@ -0,0 +1,412 @@ +# PostHog docs style guide + +This file is the source of truth for how to write PostHog docs – voice, grammar, formatting, code, links, screenshots, word choice. It applies to every doc page on posthog.com under `/docs/`. + +These are guidelines, not rigid rules. Good judgement matters more than strict adherence. If something makes the docs clearer, more helpful, or just plain better, do it. + +Two assumptions about every reader: + +1. **They're busy and have limited time.** +2. **They're not experts and don't know what we know.** + +--- + +## Voice and tone + +### Address the reader directly + +Use "you" – never "the user", "developers", or "we". + +- **Do**: "You can create an insight by clicking **New insight**." +- **Don't**: "Users can create insights." + +Use the imperative form (drop the "you") for instructions: + +- **Do**: "Create an insight by clicking **New insight**." + +### Use active voice + +Make it clear who or what performs the action. + +- **Do**: "PostHog captures events automatically." +- **Don't**: "Events are captured automatically by PostHog." + +Exception: passive voice is fine when the actor is unknown or unimportant. e.g., "The data is encrypted at rest." + +### Use present tense + +Avoid future tense unless you're explicitly describing future behavior. + +- **Do**: "The insight displays your data." +- **Don't**: "The insight will display your data." + +### Be concise + +Remove unnecessary words. Every clause should add value or clarity. + +- **Do**: "Click **Save**." +- **Don't**: "Now you can go ahead and click the **Save** button to save your changes." + +### Avoid unexplained jargon + +When you introduce a technical term or acronym, explain it on first use or link to a definition. + +- **Do**: "Create a [cohort](/docs/data/cohorts) to analyze behavior. A cohort is a group of users who share common properties." +- **Do**: "Create a [cohort](/docs/data/cohorts) – a group of users who share common properties – to analyze behavior." +- **Don't**: "Enable LTV analysis by configuring your CDP and syncing cohort data to the warehouse." + +### Use contractions + +Maintain a conversational tone. + +- **Do**: "That's it. The experiment is running." +- **Don't**: "That is it. The experiment is running." + +--- + +## Product terminology + +### Capitalize PostHog product names + +Always capitalize PostHog products as proper nouns. + +- **Do**: "Use Session Replay to understand user behavior." +- **Don't**: "Use session replay to understand user behavior." + +If you're referring to the general industry term – not PostHog's product specifically – use lowercase: "many companies offer product analytics." + +### Keys and tokens + +| Term | Description | +|------|-------------| +| **Project token** | The public identifier (starts with `phs_`) used in SDKs and the snippet to send events. **This is NOT an API key.** Never call it `project API key`. | +| **Personal API key** | A private key (starts with `phx_`) used for server-side API access. This IS an API key. | +| **Feature flags secure API key** | A separate key used for local evaluation of feature flags. | + +- **Do**: "Add your project token to the PostHog initialization code." +- **Don't**: "Add your project API key to the PostHog initialization code." + +### PostHog platform + +| Term | When to use | +|------|-------------| +| **PostHog** | Default. Refers to our cloud platform. Most users are on cloud, so don't specify "Cloud" unless contrasting with self-hosted. | +| **PostHog Cloud** | Only when explicitly contrasting cloud features with self-hosted. | +| **Self-hosted PostHog** or **hobby deployments** | Self-hosted installations. | + +- **Do**: "Go to **Insights** in the PostHog app and click **New insight**." +- **Do**: "This feature is only available on PostHog Cloud." +- **Don't**: "To create an insight on PostHog Cloud, go to the **Insights** tab." (gratuitous "Cloud") + +--- + +## Grammar and mechanics + +### American English + +PostHog has a global team and global users. Use American English spelling, grammar, date, and time formatting. + +- **Do**: color, analyze, behavior, license +- **Don't**: colour, analyse, behaviour, licence + +### Sentence case for headings + +Capitalize only the first word and proper nouns. + +- **Do**: "## How to create a feature flag" +- **Do**: "## Get started with PostHog Feature Flags" +- **Don't**: "## How To Create A Feature Flag" + +### Oxford comma + +Always use it. + +- **Do**: "PostHog offers analytics, session replay, and feature flags." +- **Don't**: "PostHog offers analytics, session replay and feature flags." + +### Numbers + +- Spell out numbers zero through nine. +- Use numerals for 10 and above. +- Use numerals for percentages, measurements, and technical values. + +Examples: "You can create three dashboards." / "You can create 15 dashboards." / "Set the timeout to 30 seconds." + +### Straight apostrophes and quote marks + +Many writing tools (Google Docs, Notion, Word) auto-insert curly quotes. Turn that off. We use straight quotes. + +### British-style en dashes + +Use en dash with a space on either side ( – ), not the longer em dash with no spaces (—). + +On Mac: Option + hyphen. + +Don't use a hyphen in place of an en dash. + +- **Do**: "Don't up vote your own content, and don't ask other people to – post it and pray." +- **Don't**: "Don't up vote your own content, and don't ask other people to—post it and pray." + +--- + +## Word choice + +### Acronyms + +ALL CAPS for acronyms and initialisms. + +- **Do**: SQL, API, HTML, CSS, JSON, REST, HTTP, URL, SDK, CLI, UI, UX +- **Don't**: Sql, Api, Html + +Follow the official capitalization for branded technologies: GraphQL, WebSocket, PostgreSQL. + +### Choose simple words + +| Instead of | Use | +|------------|-----| +| utilize | use | +| facilitate | help | +| commence | start, begin | +| subsequent | next | +| prior to | before | + +### Use precise verbs + +| Vague | Specific | +|-------|----------| +| use the API | call the API | +| work with data | query data, analyze data | +| handle errors | catch errors, log errors | +| manage users | add users, remove users, assign roles | + +### Inclusive language + +| Instead of | Use | +|------------|-----| +| blacklist/whitelist | denylist/allowlist | +| sanity check | validation, verification | +| master/slave | primary/secondary | + +### Avoid trivializing words + +Don't write "simply", "just", "easily", "obviously", "of course", "clearly". They sound dismissive and minimize the reader's effort. + +- **Do**: "Add the SDK to your project." +- **Don't**: "Simply add the SDK to your project." + +--- + +## Formatting and structure + +### Use descriptive headings + +Headings should clearly describe what's in the section. Prefer action-oriented titles over nouns and gerunds. + +- **Do**: "## How to create a feature flag" +- **Don't**: "## Feature flag creation" +- **Do**: "## Customize styles and layouts" +- **Don't**: "## Customization" + +### Use short paragraphs + +Avoid paragraphs longer than 3-4 lines. Break up longer content with line breaks, subheadings, lists, or visual elements. + +### Bulleted lists + +Use bullets for unordered items of equal importance. Default to prose when 1-2 items would read better as a sentence. + +**Do**: + +> PostHog offers several products: +> +> - Product Analytics +> - Session Replay +> - Feature Flags +> - Experiments + +**Don't** (single-item list): + +> Feature flags let you: +> +> - Control feature rollouts + +### Numbered lists + +Use them when ordering, ranking, or hierarchy matters. + +``` +1. Click **New insight** +2. Select your event +3. Click **Save** +``` + +### Definition-style lists + +Separate the item from its description with a dash, not a colon. + +- **Do**: `- **Product Analytics** - Track user behavior and measure conversions` +- **Don't**: `- **Product Analytics:** Track user behavior and measure conversions` + +### Punctuation in lists + +Use periods when each item is a complete, standalone sentence (subject + verb + independent thought). + +Don't use periods when items are phrases or fragments completing an introductory phrase. + +Be consistent within a single list – if one item is a partial sentence, all items should be. + +### Tables + +Use tables for listing multiple items across multiple attributes. If a bulleted list isn't easy to scan, try a table. + +``` +| Plan | Events | Team members | Price | +|------|--------|--------------|-------| +| Free | 1M | Unlimited | $0 | +| Paid | 2M+ | Unlimited | $0.00031/event | +``` + +### Bold text + +Use bold for structured information and visual formatting: + +- **Callout labels** – `**Note:**`, `**Important:**`, `**Warning:**`, `**Tip:**` +- **Definition lists** – `**Term** - Description` patterns +- **Problem/Solution labels** – `**Problem:**` / `**Solution:**` in troubleshooting docs + +Avoid bold for general emphasis in prose. If something is important enough to need emphasis, use a callout box. + +- **Don't**: "This is a **really important** step in the process." +- **Don't**: "Make sure you **always** configure this setting **before** deploying." + +### Bold UI elements + +Bold UI elements (buttons, menu items, labels, text fields). Don't use quotes. + +- **Do**: Click **New insight** in the **Insights** tab. +- **Don't**: Click the "New insight" button. + +For nested UI navigation, use `>` to connect: + +- **Do**: Navigate to **Settings** > **API keys** > **Personal API key**. +- **Don't**: "In PostHog, navigate to **Settings**, look under **API keys**, and then click **Personal API key**." + +### Avoid excessive formatting + +Don't use: + +- Multiple header levels in short sections +- Bold text for general emphasis +- Lists when prose is clearer +- Too many callout boxes + +--- + +## Links + +### Wikipedia-style internal links + +Link the **first mention** of a PostHog term, feature, or SDK on a page to its docs page. + +> **Example**: "To create an [insight](/docs/product-analytics/insights), first [capture events](/docs/product-analytics/capture-events). Then, select the data you want to see." + +### Link to the PostHog app + +Link to the app via `https://app.posthog.com/`. Users are redirected automatically to their correct US or EU subdomain. + +- **Do**: "Go to the [**Insights** tab](https://app.posthog.com/insights) and click **New insight**." +- **Don't**: Use `https://us.posthog.com/...` or `https://eu.posthog.com/...` + +### Link text + +Link text should describe the destination. Avoid "click here" or "this page." + +- **Do**: "See our [installation guide](/docs/getting-started/install) for instructions." +- **Don't**: "Click [this link](/docs/getting-started/install) for installation instructions." + +### Internal links use relative URLs + +Always use relative URLs for posthog.com links: `/docs/feature-flags`, not `https://posthog.com/docs/feature-flags`. + +--- + +## Code + +### Backticks + +- **Inline code** – single backticks for code elements or values in prose: `posthog.capture()`. +- **Code blocks** – triple backticks for multi-line code. + +### Follow language conventions + +- **JavaScript/TypeScript** – `PascalCase` for classes, `camelCase` for functions and variables, ES modules (`import`/`export`) instead of CommonJS (`require`). +- **Python** – `PascalCase` for classes, `snake_case` for functions and variables. +- **HTML** – lowercase for elements and attributes. + +### PostHog event and property naming + +**Always use `snake_case` for PostHog event and property names** – never `camelCase` or `PascalCase`. + +```js +posthog.capture('user_signed_up', { + user_id: '123', + username: 'Jane Doe', +}) +``` + +### Show real-world examples + +Use realistic examples that demonstrate actual use cases. + +**Do**: + +```js +posthog.capture('purchase_completed', { + product_id: 'prod_12345', + revenue: 49.99, + currency: 'USD' +}) +``` + +**Don't**: + +```js +posthog.capture('event', { + property: 'value' +}) +``` + +### Comment sparingly + +Only add comments when the code isn't self-explanatory: + +```js +// Don't show the survey if user dismissed it in the last 30 days +if (lastDismissed > Date.now() - 30 * 24 * 60 * 60 * 1000) { + return +} +``` + +--- + +## Screenshots and media + +> **Important**: Make sure no personal or sensitive information (emails, phone numbers, identifying details) is visible in any screenshot or video. + +### Screenshot requirements + +- **Focus on the relevant UI** – exclude sidebars and unrelated interface elements. +- **Use a standard viewport** – set device width to 1000–1400px in devtools. +- **Use annotations** – add arrows, text, or other visual elements to highlight specific UI elements. + +### When to use videos + +- Multi-step workflows +- Complex interactions +- Demonstrating UI behavior + +Use Screen Studio with these settings: + +- Use the preset +- Remove zoom-in for clicks +- Export: MP4, 1080p, 60 fps, "web" quality