Repository navigation
docs: generate the SDK reference as Markdown with go/doc - #410
Conversation
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 4b84cfd: 1 Must fix.
This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.
See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.
posthog-go Compliance ReportDate: 2026-11-11 17:42:18 UTC ✅ All Tests Passed!111/111 tests passed Capture_V1 Tests✅ 94/94 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
go/doc reads each exported symbol and go/doc/comment renders its doc comment as Markdown, so the generator needs no third-party tool and no regex. It only groups symbols by their posthog-capability tag in sdk-specs order and writes front matter. The release step checks out sdk-specs for the headings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The snapshot includes doc comments, and the tags add a line to some of them. No signatures change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ghcommit-action passes an untracked folder to ghcommit as one path, which fails on the first release that writes references/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The posthog-capability lines showed up in IDE hover help for every SDK user. The generator now reads a label-to-slug map next to it, and fails on stale labels, unknown slugs, and unmapped SDK utils members. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The release's reference step is best-effort, so a failure never blocks a release. generate-references.yml reruns it from main on demand and commits references/ when anything changed. Same shape as posthog-js's generate-references.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reference step is best-effort, so a failure leaves the release green. A ::warning:: annotation now says so and points to generate-references.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| p := pkg.Printer() | ||
| p.HeadingLevel = 5 | ||
| p.DocLinkURL = func(l *comment.DocLink) string { return "#" + anchor(l.Recv+l.Name) } | ||
| return strings.TrimSpace(string(p.Markdown(d))) |
There was a problem hiding this comment.
P1 · Render doc-comment examples as fenced code blocks
p.Markdown renders doc-comment examples as indented code blocks, which MDX does not support. The generated NewSlogCaptureHandler example contains &slog.HandlerOptions{Level: slog.LevelInfo}, so MDX interprets the braces as an expression and fails compilation. This prevents the generated reference from building on posthog.com; render examples with fenced code blocks.
| } | ||
|
|
||
| func write(file, front string, body []string) { | ||
| check(os.WriteFile(filepath.Join("references", file), []byte(strings.Join(append([]string{front}, body...), "\n\n")+"\n"), 0o644)) |
There was a problem hiding this comment.
P2 · Create the output directory before writing references
On a fresh checkout, references/ does not exist and neither workflow creates it. The first write call therefore exits with open references/posthog-go-1.md: no such file or directory, producing no reference pages and failing the manual generation workflow. Create the output directory before calling os.WriteFile so generation works from a clean checkout.
| func typeEntry(t *doc.Type) entry { | ||
| children := append(funcs(t.Funcs, "posthog."), funcs(t.Methods, t.Name+".")...) | ||
| return entry{t.Name, block(t.Decl), markdown(t.Doc), children} |
There was a problem hiding this comment.
P2 · Include constants and variables associated with types
go/doc attaches typed constants to doc.Type.Consts, but typeEntry only renders the declaration, functions, and methods. Consequently, the reference omits declarations for CompressionGzip, CaptureModeAnalyticsV1, and every UnresolvedFlagReason constant, leaving their available values undocumented; render each type's associated constants and variables too.
| p := pkg.Printer() | ||
| p.HeadingLevel = 5 | ||
| p.DocLinkURL = func(l *comment.DocLink) string { return "#" + anchor(l.Recv+l.Name) } | ||
| return strings.TrimSpace(string(p.Markdown(d))) |
There was a problem hiding this comment.
[suggestion] The PostHog Review P1 here holds up: escape() only touches Paragraph and List blocks, and p.Markdown prints comment.Code as a tab-indented block. MDX doesn't support indented code, so those lines get parsed as prose, and braces like &slog.HandlerOptions{Level: slog.LevelInfo} become JSX expressions. references/posthog-go-1.md on #411 has 26 such lines (e.g. the NewSlogCaptureHandler example), so the page would likely fail to compile on posthog.com. Could we print Code blocks as fenced ```go blocks ourselves (they don't need escaping inside a fence), then regenerate #411?
…erences/ - Doc-comment examples printed as indented code, which MDX doesn't support, so braces in them parsed as JSX. Print them as fenced Go blocks. - go/doc groups typed constants and variables under their type, and the type entry left them out, so values like CompressionGzip and every UnresolvedFlagReason weren't documented. Render them under the type. - Create references/ before writing, so generation works from a clean checkout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Print each declaration with only the comments of the fields and methods go/doc kept, so unexported fields' comments don't show, and drop the blank lines a filtered member leaves. - Put package constants and variables under Constants and Variables headings in SDK utils. - Keep the EnqueueClient type entry, which public signatures take. - Align columns with spaces, the way gofmt does. - Tag a code example go only when it looks like Go, and text otherwise. - Point [Name] doc links at the symbol's heading. - Drop empty parts, the brace escapes the site no longer needs, and the printer's escaped backticks. - Read the module path from go.mod, so the next major's page installs and imports .../posthog-go/v2. - Fix the Properties example, which put the dots at the start of lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
PostHog Review · Standard · reviewed bed9314: 1 Must fix.
This is review round 3 on this pull request. When findings keep coming back in the same code, the approach is usually the problem. Before the next fix, check whether a different design would remove the whole class of findings.
| return "#" + anchor("posthog."+l.Name) | ||
| } | ||
|
|
||
| var mdx = strings.NewReplacer("<", "<") |
There was a problem hiding this comment.
P1 · Escape braces in generated prose for MDX
Generating either reference page includes the SlogCaptureHandler prose client.Enqueue(Exception{...}). escape leaves these braces intact, so MDX treats {...} as JavaScript and compilation fails with Could not parse expression with acorn: Unexpected token, blocking the website build even with examples fenced. Escape prose braces or render these snippets as inline code.
There was a problem hiding this comment.
We don't render these pages as MDX. posthog.com blocks them from MDX here: https://github.com/PostHog/posthog.com/blob/b07e215fdada73f80aec4a42ecc8040a3c5d7be2/gatsby-config.js#L143-L145 and renders them as plain Markdown here: https://github.com/PostHog/posthog.com/blob/b07e215fdada73f80aec4a42ecc8040a3c5d7be2/src/templates/sdk/SdkMarkdownReference.tsx#L74. I tested this on a local build, and the live Python reference renders the same raw braces. Thanks!
…s inside parentheses A ... placeholder is read as an argument, so examples such as NewWithConfig(...) still parse as Go, and prose with a parenthesis no longer passes as code. A const block no longer opens with a blank line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main added Client.Emails, and the generator stops on a member with no capability, so the release step would skip the pages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Small cleanups before merge, none blocking: the review-bot threads on fenced code, typed constants and creating |
💡 Motivation and Context
We have a wave of breaking changes with new major versions for most SDKs. References are now read mostly by bots, not humans, and the HogRef format is heavy. Strapi then syncs
references/daily, and posthog.com builds the pages (PostHog/squeak-strapi#260, PostHog/posthog.com#21971).internal/cmd/referenceuses only the standard library:go/docreads each exported symbol andgo/doc/commentrenders its doc comment as Markdown. Our code groups symbols by capability, fromdocs/capabilities.jsonin sdk-specs order and writes front matter, with no regex and no third-party tool.docs/capabilities.jsonmaps each symbol to its sdk-specs capability, so the doc comments stay as they are. Generation fails on a stale entry, an unknown capability, or an unmapped client method.docs/getting-started.mdand a release step that checks out sdk-specs and regeneratesreferences/..github/workflows/generate-references.ymlreruns it by hand frommainand commitsreferences/when anything changed. It follows the prior art in posthog-js'sgenerate-references.yml, and it's the same in every SDK repo apart from the generation step.💚 How did you test it?
go run ./internal/cmd/reference --sdk-specs <checkout>reproduces the pages in the next PR. The release step hasn't run in CI.📝 Checklist
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Claude Code: Sonnet 5.5 built it and Opus 5.5 opened it, directed by Vincent. Not yet reviewed line by line.
Merge order
🤖 Generated with Claude Code