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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions context/agents/integration-v2/ai-observability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
type: ai-observability
flow: integration-v2
label: Instrument LLM calls
model_pi: openai/gpt-5.6-terra
effort_pi: medium
model_sdk: claude-sonnet-4-6
effort_sdk: high
skills: [llm-analytics-setup, posthog-best-practices]
allowedTools: [Read, Write, Edit, Glob, Grep]
disallowedTools: [Bash, enqueue_task]
dependsOn: [install, init]
---

## Goal

Route this app's LLM calls through PostHog so each generation reports its model,
cost, latency, and token counts. The provider or framework in use decides the shape:
a wrapped client, a callback handler, a decorator. Follow the reference for the
provider this project actually imports, and reach the PostHog client the way the init
step already established — never construct a second one.

Instrument at the client, not at the call sites: one wrapped client that every call
site already reaches beats editing each call. If a call site must change, keep the
change to the smallest edit that routes it through the wrapped client.

Where the app has a user identity available at the call, pass it as the distinct id
so generations attribute to a person. Where it does not, leave it out rather than
inventing one — an anonymous generation is still useful, a wrong identity is not.
Never send prompt or completion content the app treats as sensitive.

## How you know you succeeded

Every LLM entry point in the app goes through the instrumented client, the project
still builds the way it did before you started, and no second PostHog client exists.
Your handoff names the files you changed, the provider or framework each one uses,
whether a distinct id was available, and what a reviewer should read to confirm the
call path. If the project imports an LLM SDK you found no reference for, say so and
leave it uninstrumented rather than guessing at an API.
49 changes: 0 additions & 49 deletions context/agents/integration-v2/capture.md

This file was deleted.

23 changes: 0 additions & 23 deletions context/agents/integration-v2/dashboard.md

This file was deleted.

42 changes: 42 additions & 0 deletions context/agents/integration-v2/enable-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
type: enable-features
flow: integration-v2
label: Enable the PostHog products
model_pi: openai/gpt-5.6-luna
effort_pi: low
model_sdk: claude-haiku-4-5-20251001
skills: [integration-v2-enable-features, integration-v2-mcp]
allowedTools: [Read, Glob, Grep]
disallowedTools: [Write, Edit, Bash, enqueue_task]
dependsOn: [product-signals]
---

## Goal

Turn on the PostHog products that self-driving reads from, in the project. The SDK is
installed and initialized by now, so this is the switch that decides whether what it
sends is collected at all. `init` queued you behind the repo groom, so its findings are
already in your context.

Enable the products, then say what the groom's findings change about them. You change
nothing in the repo — a product that needs code to work is a follow-up you name, not an
edit you make.

## Status

Complete with **done** whenever you established each product's state and recorded it —
including when PostHog refused the change. A missing tool, a missing scope, or a
permission wall is an outcome to report, not a failure: the integration in the repo is
untouched and every later step can still run, so failing here would abort a run that
actually succeeded. Reserve **failed** for being unable to determine any product's state
at all.

## How you know you succeeded

Every product has a recorded result — enabled, already enabled, or refused with the
reason. Your handoff names each one, carries forward the `product-signals` block
verbatim so the steps after you see it by the shortest path, and lists every follow-up:
a product needing project admin or a broader token scope, a product inert on this
platform until the SDK is configured for it, a Support inbox with no channel connected
yet. If no product signals were available, say that plainly rather than implying you had
them.
31 changes: 26 additions & 5 deletions context/agents/integration-v2/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,34 @@ model_sdk: claude-sonnet-4-6
effort_sdk: medium
skills: [integration-v2-init, posthog-best-practices]
allowedTools: [Read, Write, Edit, Glob, Grep]
disallowedTools: [enqueue_task]
disallowedTools: []
dependsOn: []
---

## Goal

Initialize PostHog: create the framework's init point so the SDK is configured
once and available across the app, set the PostHog environment variables through
the wizard tools, and document those keys in `.env.example` for other developers.
Before your own work, queue exactly two tasks, once each, then move on and never wait on
either:

1. `product-signals`, with no dependencies, so it grooms the repo in parallel while you
edit. Pass what you already know through its `inputs`: the framework, the kind of app
(client, SSR/fullstack, or server), the init file you are about to create or edit, and
whether the app ships a Content-Security-Policy.
2. `enable-features`, depending on the id `product-signals` just returned — it turns the
products on in PostHog, and the groom's findings are what tell it what it is turning
on. Nothing else depends on it.

Those two types and nothing else. The rest of the run is already queued — the planner
seeded install, identify, error tracking, review, and the report before you started, so
queueing any of them again duplicates work that is already running. Work you think is
missing goes in your handoff, not on the queue.

You read neither result; the steps after you do.

Then initialize PostHog: create the framework's init point so the SDK is configured
once and available across the app, turn on the products that are init options rather
than steps of their own, set the PostHog environment variables through the wizard
tools, and document those keys in `.env.example` for other developers.

Try to follow these principles, in order: codebase convention, don't make any
unnecessary changes, keep the change as lean as possible for an easy review, and
Expand All @@ -25,7 +44,9 @@ part of the shape: reach it the way the docs and the example project reach it.

## How you know you succeeded

The init file exists and the PostHog env keys are present. Keys live in the env
A `product-signals` task and an `enable-features` task that depends on it are both on
the queue. The init file exists and the PostHog env
keys are present. Keys live in the env
file, never hardcoded in source, and `.env.example` lists the key names (with
placeholder values) so the next developer knows what to set. Your handoff names the
files you changed, how the client is constructed in them, and how a call site
Expand Down
40 changes: 27 additions & 13 deletions context/agents/integration-v2/integrate-posthog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,37 @@ dependsOn: []

Plan a PostHog integration and seed the task queue with this graph:

- `install` and `init`, independent of each other.
- `install` and `init`, independent of each other. `init` also configures the products
that are init-time options rather than steps of their own — autocapture, pageviews,
session replay — and owns two tasks you do not queue: the repo groom
(`product-signals`) and the project-side switch-on (`enable-features`) that reads it.
Leave both to `init`; queueing either here would run it before the groom exists.
- `identify` and `error-tracking`, each after `install` and `init` and independent
of one another, so they run in parallel. `error-tracking` makes the errors the app
does not catch reach PostHog, by whatever means the SDK offers for that — it needs
the SDK installed and initialized, not the events.
- `capture`, after `identify` — it decides the events and instruments them, and it
reads how identity is already established before it instruments anything.
- `review`, after `install`, `init`, `identify`, `capture`, and `error-tracking` —
it installs the dependencies, verifies the project builds/typechecks/lints, and
reviews every change the run made, fixing what fails. There is no separate build
step: verifying and reviewing are one pass over the same changeset.
- `dashboard`, after `capture`, parallel to `review` — it builds insights from the
instrumented events, which `capture` has already defined; it needs no code review.
- `report`, after `dashboard` **and** `review` — it writes the setup report last, so
it describes the integration as reviewed rather than as first written.
- `ai-observability`, after `install` and `init`, **only if this project actually
calls an LLM**. Read the manifests before you decide: an LLM SDK or framework in the
dependencies (`openai`, `@anthropic-ai/sdk`, `ai`, `@ai-sdk/*`, `langchain`,
`cohere`, `mistralai`, `google-genai`, or their Python equivalents in
`requirements.txt` / `pyproject.toml`). Found one, queue it; found none, leave it
out — omitting it is the right plan for an app with no LLM calls, not a gap.
- `review`, after `install`, `init`, `identify`, `error-tracking`, and
`ai-observability` if you queued it — it installs the dependencies, verifies the
project builds/typechecks/lints, and reviews every change the run made, fixing what
fails. There is no separate build step: verifying and reviewing are one pass over
the same changeset. It does not wait on the project-side switch-on, which touches no
code.
- `report`, after `review` — it writes the handoff last, so it describes an integration
that has already been reviewed. It reads every step's handoff out of the queue log,
including the tasks `init` queued, so it needs no edge to them.

This run does not instrument events and does not build insights or dashboards. That is
deliberate: it leaves the user's own agent the tools and the suggestions to do that,
and it is why the run is short. Do not queue work for it.

## How you know you succeeded

Every task in the graph is queued with that dependency shape, the report last,
and the first task runnable. Keep labels short — the action in a few words.
Every task in the graph is queued with that dependency shape, the report last, and the
first task runnable. `ai-observability` is present exactly when the manifests justify
it. Keep labels short — the action in a few words.
65 changes: 65 additions & 0 deletions context/agents/integration-v2/product-signals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
type: product-signals
flow: integration-v2
label: Look for product signals
model_pi: openai/gpt-5.6-luna
effort_pi: medium
model_sdk: claude-haiku-4-5-20251001
effort_sdk: medium
skills: []
allowedTools: [Read, Glob, Grep]
disallowedTools: [Write, Edit, Bash, enqueue_task]
dependsOn: []
---

## Goal

Read this repo for evidence about which PostHog products would actually earn their
place here, and hand that evidence forward. You change nothing and enable nothing —
the steps after you decide what to do with what you find.

Evidence, not opinions. Every line you report names the file it came from, and a
claim you could not read out of a file is an assumption, not a finding. Look for:

- what the app is for — routes, pages, entry points, and whether any of them already
call an analytics library
- an LLM client or framework, and the call sites that use it
- a structured logger, and where it writes
- a payments or billing SDK, and the webhook or checkout path it serves
- an existing error reporter already shipping exceptions somewhere
- tenancy: an organizations/teams/workspaces table, or a foreign key on users that
implies one
- a database or third-party service the warehouse could ingest
- public marketing routes, as distinct from the authenticated app

Read broadly and cheaply: the manifests first, then the schema, then the entry
points, then the specific files those point at. Do not read the whole tree, and do
not open a dependency's own source.

## How you know you succeeded

Your handoff's `forNextAgent` is one line per product, in this exact shape, with
every product present — a reader has to be able to tell "looked, found nothing" from
"did not look":

```
<product>: yes|no|partial — <reason> (<files>)
```

Use `partial` when PostHog would overlap something the project already runs; that is
the case the later steps handle differently from a plain `yes`. Cover exactly these
products, in this order: `product-analytics`, `session-replay`, `error-tracking`,
`logs`, `ai-observability`, `revenue`, `groups`, `data-sources`, `web-analytics`.

For example:

```
product-analytics: yes — 14 routes under app/, no analytics calls anywhere (app/, package.json)
error-tracking: partial — @sentry/nextjs 8.x already reporting (package.json, sentry.client.config.ts)
groups: no — single-tenant, no org or team table (prisma/schema.prisma)
```

`did` says where you looked and what you read. `evidence` names the greps and reads
you actually ran. `assumptions` carries anything inferred from a name rather than
read — an `organizations` table taken to mean tenancy. Leave `filesTouched` out; you
touch nothing.
52 changes: 30 additions & 22 deletions context/agents/integration-v2/report.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,43 @@ effort_sdk: high
skills: [integration-v2-report, integration-v2-notebook, integration-v2-mcp]
allowedTools: [Read, Write, Glob, Grep]
disallowedTools: [enqueue_task]
dependsOn: [dashboard, review]
dependsOn: [review]
---

## Goal

Write the setup report summarizing what this integration did, drawing only on what
the run itself recorded: the queue log and event plan in `.posthog-wizard-cache/`
(`queue.json` and `.posthog-events.json`), and the handoff each step left behind.
Then mirror it into a shareable PostHog notebook.
Write the handoff for this project — half a record of what the run did, half a brief
for the agent that picks up after it. Draw only on what the run itself recorded: the
queue log at `.posthog-wizard-cache/queue.json`, which holds every step's handoff
inline, the `product-signals` groom among them. Then mirror it into a shareable
PostHog notebook.

Separate what the run verified from what it did not. A passing build proves the
code compiles, not that events flow — never write that an event was captured
unless the run observed it arrive. Where a step failed or was skipped, say so
plainly instead of rounding it up to success. Anything only the user can confirm
belongs in a checklist to work through before merging, each item naming the file
and line to look at.
This run deliberately instrumented no events and built no insights or dashboards, so
the report is where that work gets handed over: the events worth capturing, the
analyses they would unlock, the data sources worth connecting, and prompts the user
can paste straight into their own agent. Ground every suggestion in the
`product-signals` findings and the files this run actually touched. If that groom is
missing from the queue log, say so in those sections rather than filling them with
guesses.

Separate what the run verified from what it did not. A passing build proves the code
compiles, not that events flow — never write that an event was captured unless the run
observed it arrive, and this run captured none. Where a step failed or was skipped, say
so plainly instead of rounding it up to success. Anything only the user can confirm
belongs in a checklist to work through before merging, each item naming the file and
line to look at.

Where a handoff reports something a step could not resolve — attribution it could not
establish, a question the step before it left open — that is not a caveat to bury in
prose. Raise it as its own issue to follow up, saying what is unresolved and what it
costs if left alone. A `DISTINCT_ID` placeholder left at a call site means no stable id
was available: name every file and line carrying one, so the user knows what to replace
before those events mean anything.
establish, a product it could not enable for lack of permissions, a question the step
before it left open — that is not a caveat to bury in prose. Raise it as its own issue
to follow up, saying what is unresolved and what it costs if left alone.

## How you know you succeeded

`posthog-setup-report.md` exists at the project root: what was installed and
initialized, the events captured, whether identify was wired or skipped, error
tracking added, the dashboard link, any build conflict in full, and the next
steps for the user. Every claim in it traces to a handoff, and what the run could
not confirm reads as unconfirmed. The report is also mirrored into a PostHog
notebook whose URL is emitted with the `[NOTEBOOK_URL]` marker.
`posthog-setup-report.md` exists at the project root, in the section order the report
skill lays out: what is set up, what was left for their agent, suggested events, the
analyses those events unlock, how to drive PostHog from an agent, copy-paste prompts,
suggested data sources, the before-you-merge checklist, and what the run did not do and
why. Every claim traces to a handoff, every suggestion traces to a signal or a file,
and what the run could not confirm reads as unconfirmed. The report is also mirrored
into a PostHog notebook whose URL is emitted with the `[NOTEBOOK_URL]` marker.
Loading
Loading