Skip to content

Add essay: PostHog Code and the production signal#11

Merged
khaliqgant merged 3 commits into
mainfrom
post/posthog-code
May 15, 2026
Merged

Add essay: PostHog Code and the production signal#11
khaliqgant merged 3 commits into
mainfrom
post/posthog-code

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

Summary

  • New essay analyzing PostHog Code through the proactive agent lens
  • Deep dive into the enricher package: tree-sitter static analysis, import resolution, live PostHog API queries that inject production data (feature flag %, stale detection, event volumes, experiment results) as inline annotations the LLM sees
  • Architecture analysis: Claude Agent SDK + Codex, Electron desktop, Temporal cloud sandboxes, session handoff — entirely reactive, no webhooks/cron/event watchers
  • Core thesis: the enricher already detects conditions a proactive agent would act on (stale flags, dead instrumentation), but only runs during human-initiated sessions. Making it always-on would close the gap
  • Links to CodeRabbit post for comparison, three-primitives framework for analysis

Files changed

  • content/posts/posthog-code.mdx — new essay
  • components/mdx/figures.tsx — PHEnricherFigure (code + production context diagram) and PHSignalGapFigure (signals exist but no trigger connects them to agent)
  • components/mdx/mdx-components.tsx — register new figures
  • components/card-illustrations.tsx — PostHogCodeArt card illustration + slug mapping

Test plan

  • TypeScript compiles cleanly (tsc --noEmit)
  • Next.js production build succeeds
  • Post renders with OG image and Twitter card
  • Visual review of figures on desktop and mobile
  • Verify external links resolve (PostHog, GitHub repo, Devin, CodeRabbit post)

🤖 Generated with Claude Code

Analyzes PostHog Code's enricher through the proactive agent lens.
The enricher bridges code and production data (feature flags, event
volumes, experiments) via tree-sitter static analysis and live API
queries. Entirely reactive today but the enricher pattern is the
most interesting primitive for proactive dev agents we've seen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR adds PostHog Code documentation with new visualization components. A card illustration component (PostHogCodeArt) is registered for preview cards. Two MDX figure components (PHEnricherFigure and PHSignalGapFigure) visualize the enricher pipeline and signal-gap limitations. These figures are wired into the MDX component system and used in a new blog post explaining PostHog Code's architecture and reactive versus always-on agent triggering.

Changes

PostHog Code documentation

Layer / File(s) Summary
PostHog Code card illustration
components/card-illustrations.tsx
New PostHogCodeArt SVG component renders analytics bars and code brackets; "posthog-code" slug maps to this component in the card registry.
Enricher and signal gap figures
components/mdx/figures.tsx
PHEnricherFigure shows code lines enriched with PostHog data annotations and status indicators. PHSignalGapFigure visualizes production signals with no trigger path to the coding agent, including dashed non-connections and idle-state context.
MDX figure component registration
components/mdx/mdx-components.tsx
New figure components imported and registered in mdxComponents export for MDX rendering.
PostHog Code blog post
content/posts/posthog-code.mdx
Complete article explaining the enricher's static analysis (tree-sitter), live PostHog API data fetching, system architecture (Claude SDK, Electron, Temporal, Modal/Docker/Kafka), and reactive-vs.-always-on trigger model limitations.

🎯 2 (Simple) | ⏱️ ~12 minutes


🐰 The bunny hops through code so bright,
New figures dancing, card in sight,
PostHog signals leap and play,
Documentation blooms today!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: a new essay about PostHog Code and the production signal.
Description check ✅ Passed The description provides a comprehensive overview directly related to the changeset, including summary, files changed, and test plan.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch post/posthog-code

Comment @coderabbitai help to get the list of available commands and usage tips.

Taller viewBox (360) gives code lines breathing room. Status dots
(green/yellow/red) next to each annotation. Enricher pill with
curved arrows from source boxes. Separator lines between code
entries. Clearer visual flow from inputs → enricher → output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 3 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment thread components/mdx/figures.tsx Outdated
Comment on lines +2355 to +2361
<rect x="20" y="38" width="280" height="100" rx="8" fill={C.paper} stroke={C.ink} strokeWidth="1.5" />
<text x="32" y="56" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>isFeatureEnabled(&apos;checkout&apos;)</text>
<text x="32" y="72" fontFamily="var(--font-mono)" fontSize="8" fill={C.moss}>// → 23% rollout · stale · exp +4%</text>
<text x="32" y="92" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>posthog.capture(&apos;purchase&apos;)</text>
<text x="32" y="108" fontFamily="var(--font-mono)" fontSize="8" fill={C.moss}>// → 1,240 events/30d · verified</text>
<text x="32" y="128" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>isFeatureEnabled(&apos;old-banner&apos;)</text>
<text x="32" y="144" fontFamily="var(--font-mono)" fontSize="8" fill={C.terracotta}>// → 0% rollout · no evals 60d</text>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 PHEnricherFigure: last annotation text overflows the containing rect

The "source file box" rect in PHEnricherFigure spans from y=38 to y=138 (y="38" + height="100"), but the last text element at components/mdx/figures.tsx:2361 has y="144", placing its baseline 6px below the box's bottom edge. Since the rect has fill={C.paper}, this last annotation ("// → 0% rollout · no evals 60d") will render visually outside the white box, breaking the intended "annotated code file" appearance.

Suggested change
<rect x="20" y="38" width="280" height="100" rx="8" fill={C.paper} stroke={C.ink} strokeWidth="1.5" />
<text x="32" y="56" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>isFeatureEnabled(&apos;checkout&apos;)</text>
<text x="32" y="72" fontFamily="var(--font-mono)" fontSize="8" fill={C.moss}>// → 23% rollout · stale · exp +4%</text>
<text x="32" y="92" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>posthog.capture(&apos;purchase&apos;)</text>
<text x="32" y="108" fontFamily="var(--font-mono)" fontSize="8" fill={C.moss}>// → 1,240 events/30d · verified</text>
<text x="32" y="128" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>isFeatureEnabled(&apos;old-banner&apos;)</text>
<text x="32" y="144" fontFamily="var(--font-mono)" fontSize="8" fill={C.terracotta}>// → 0% rollout · no evals 60d</text>
<rect x="20" y="38" width="280" height="114" rx="8" fill={C.paper} stroke={C.ink} strokeWidth="1.5" />
<text x="32" y="56" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>isFeatureEnabled(&apos;checkout&apos;)</text>
<text x="32" y="72" fontFamily="var(--font-mono)" fontSize="8" fill={C.moss}>// → 23% rollout · stale · exp +4%</text>
<text x="32" y="92" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>posthog.capture(&apos;purchase&apos;)</text>
<text x="32" y="108" fontFamily="var(--font-mono)" fontSize="8" fill={C.moss}>// → 1,240 events/30d · verified</text>
<text x="32" y="128" fontFamily="var(--font-mono)" fontSize="9" fill={C.ink}>isFeatureEnabled(&apos;old-banner&apos;)</text>
<text x="32" y="144" fontFamily="var(--font-mono)" fontSize="8" fill={C.terracotta}>// → 0% rollout · no evals 60d</text>
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread content/posts/posthog-code.mdx Outdated

All of this information exists inside the enricher's analysis pipeline. The gap is that the pipeline only runs when a human starts a session and the agent happens to read the relevant file. The enricher is a listener that only operates during active coding sessions.

Making it always-on would close the gap. A background process that periodically scans for stale flags across connected repos and opens cleanup PRs. A watcher that correlates error rate spikes with recent merges and alerts the PR author in Slack. A weekly digest of dead instrumentation that nobody is tracking anymore. The data is already being fetched and analyzed within the enricher's pipeline. It just needs a trigger mechanism that doesn't require a human typing a prompt to start the process.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Two tricolon lists in essay violates CLAUDE.md "more than once per essay" rule

CLAUDE.md states: "Avoid tricolon lists ('Not X. Not Y. Not Z.') more than once per essay. Parallel structures where three items start with the same word are an LLM tell. One instance can be rhetorical; two is a pattern." This essay contains two tricolons: line 43 ("There are no webhooks…No cron jobs…No file watchers") and line 55 ("A background process…A watcher…A weekly digest"). One of these should be restructured.

Prompt for agents
The essay has two tricolon lists (three parallel items starting with the same word), which CLAUDE.md limits to one per essay. The first tricolon at line 43 ('No webhooks...No cron jobs...No file watchers') is more rhetorically effective, so keep that one. The second tricolon at line 55 ('A background process...A watcher...A weekly digest') should be restructured. Consider combining the three items into a flowing sentence, e.g. describing the background process and watcher inline rather than as three parallel 'A [noun]' sentences. The goal is to break the visible parallel structure while preserving the same information.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread content/posts/posthog-code.mdx Outdated
dropcap: true
---

[PostHog](https://posthog.com) launched [Code](https://posthog.com/code) this spring, and the interesting thing about it isn't the coding agent itself. It's what the coding agent can see.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Repeated "isn't X. It's Y." inversion is an LLM tell flagged in CLAUDE.md

CLAUDE.md explicitly flags "'This is not X. It is Y.' inversions" as one of the biggest LLM-sounding sentence structure tells and instructs: "If a sentence sounds like it could appear in any AI-generated essay on any topic, rewrite it." The essay uses this exact pattern twice: line 9 ("the interesting thing about it isn't the coding agent itself. It's what the coding agent can see.") and line 65 ("PostHog Code isn't trying to be a proactive agent. It's a coding tool"). Having two instances creates a recognizable AI writing pattern. At least one should be restructured.

Prompt for agents
The essay uses the 'isn't X. It's Y.' inversion twice — once at line 9 (opening paragraph) and once at line 65 (closing section opener). CLAUDE.md calls this structure out as an LLM tell. Rewrite at least one to break the pattern. For the opening at line 9, consider leading with the positive claim directly (e.g. 'the interesting thing is what the coding agent can see') rather than the negation-then-reveal structure. Alternatively, restructure line 65 to merge the two halves into a single sentence without the contrast pivot.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- Remove "isn't X. It's Y." inversion from opening line and closing section
- Restructure second tricolon list to break parallel "A [noun]" pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@khaliqgant khaliqgant merged commit f3ee43d into main May 15, 2026
1 check was pending
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant