From 4b8e90c9275f5d55de8ee3bf63c525811cf935a6 Mon Sep 17 00:00:00 2001 From: Edwin Lim Date: Wed, 28 Oct 2026 17:30:28 -0700 Subject: [PATCH 1/2] feat(orchestrator): pick task skills by project traits, in shadow Orchestrator runs resolve each task's skills two ways. The exact-match pick (the id itself, else its group's variant for the run's framework) decides. The criteria resolver in `@shared/skill-resolution` picks beside it from menu tags and the run's project traits, and each disagreement is logged as `orchestrator skill resolver disagreement`. With the `wizard-agent-dag` flag on, the criteria pick decides and the exact match is its fallback. `@services/project-traits` holds the run's project traits from static detection: the framework, and `callsLlmApi` when an LLM SDK is a dependency. `traitsToSkillTags` maps the framework to its `framework:` tag, and the program runner hands the tags to the orchestrator through `RunConfig.traitTags`. Skill-menu entries carry `title`, `description` and `tags`, and bundle variants inherit the bundle's title and description. Every event after the menu loads carries `context_mill_version`, and the terminal `setup wizard finished` event carries the run's wizard flags. `fixtures/context-mill/` holds a context-mill build's skill menu, agent menu and 41 agent prompts; `pnpm record:context-mill-fixtures` re-records them from a release. The equivalence test checks that both resolvers pick the same skill for every prompt skill and framework. Co-Authored-By: Claude Opus 5.5 --- fixtures/context-mill/agent-menu.json | 211 + .../error-tracking/capture-exceptions.md | 116 + .../agents/error-tracking/configure.md | 173 + .../agents/error-tracking/credentials.md | 81 + .../agents/error-tracking/init.md | 121 + .../agents/error-tracking/install.md | 54 + .../agents/error-tracking/link-releases.md | 87 + .../agents/error-tracking/report.md | 103 + .../error-tracking/setup-error-tracking.md | 170 + .../agents/error-tracking/test-setup.md | 55 + .../agents/error-tracking/verify.md | 82 + .../agents/error-tracking/wire-ci.md | 109 + .../agents/feature-flags/create-flag.md | 48 + .../agents/feature-flags/evaluate.md | 44 + .../context-mill/agents/feature-flags/init.md | 35 + .../agents/feature-flags/install.md | 31 + .../agents/feature-flags/report.md | 50 + .../feature-flags/setup-feature-flags.md | 66 + .../agents/integration-v2/ai-observability.md | 60 + .../agents/integration-v2/capture.md | 51 + .../agents/integration-v2/dashboard.md | 23 + .../agents/integration-v2/error-tracking.md | 36 + .../agents/integration-v2/identify.md | 62 + .../agents/integration-v2/init.md | 38 + .../agents/integration-v2/install.md | 67 + .../integration-v2/integrate-posthog.md | 51 + .../agents/integration-v2/logs.md | 60 + .../agents/integration-v2/report.md | 53 + .../agents/integration-v2/review.md | 104 + .../agents/integration-v2/warehouse.md | 41 + .../agents/metrics/instrument-metrics.md | 32 + .../context-mill/agents/metrics/report.md | 44 + .../agents/metrics/setup-metrics.md | 60 + .../context-mill/agents/metrics/verify-sdk.md | 46 + .../agents/replay-vision/enable-replay.md | 46 + .../context-mill/agents/replay-vision/init.md | 33 + .../agents/replay-vision/install.md | 30 + .../agents/replay-vision/report.md | 38 + .../scanner-broken-experiences.md | 40 + .../scanner-session-summaries.md | 37 + .../replay-vision/scanner-user-frustration.md | 35 + .../replay-vision/setup-replay-vision.md | 53 + fixtures/context-mill/skill-menu.json | 9831 +++++++++++++++++ package.json | 3 +- .../record-context-mill-fixtures.no-jest.ts | 64 + src/agent/runner/sequence/README.md | 7 + .../__tests__/delivered-report.test.ts | 1 + .../__tests__/skill-equivalence.test.ts | 71 + .../orchestrator/orchestrator-runner.ts | 49 +- .../sequence/orchestrator/skill-picks.ts | 100 + src/agent/runner/shared/types.ts | 3 + .../runner/switchboard/flags/agent-dag.ts | 7 + src/agent/runner/switchboard/flags/index.ts | 1 + src/agent/runner/switchboard/index.ts | 1 + src/programs/program-runner/run-program.ts | 2 + src/services/README.md | 1 + .../project-traits/__tests__/traits.test.ts | 64 + src/services/project-traits/index.ts | 9 + src/services/project-traits/traits.ts | 52 + src/shared/__tests__/skill-menu.test.ts | 53 + src/shared/constants.ts | 3 + src/shared/skill-menu.ts | 29 +- src/shared/skill-resolution.ts | 109 + src/shared/utils/__tests__/analytics.test.ts | 13 + src/shared/utils/analytics.ts | 2 + 65 files changed, 13213 insertions(+), 38 deletions(-) create mode 100644 fixtures/context-mill/agent-menu.json create mode 100644 fixtures/context-mill/agents/error-tracking/capture-exceptions.md create mode 100644 fixtures/context-mill/agents/error-tracking/configure.md create mode 100644 fixtures/context-mill/agents/error-tracking/credentials.md create mode 100644 fixtures/context-mill/agents/error-tracking/init.md create mode 100644 fixtures/context-mill/agents/error-tracking/install.md create mode 100644 fixtures/context-mill/agents/error-tracking/link-releases.md create mode 100644 fixtures/context-mill/agents/error-tracking/report.md create mode 100644 fixtures/context-mill/agents/error-tracking/setup-error-tracking.md create mode 100644 fixtures/context-mill/agents/error-tracking/test-setup.md create mode 100644 fixtures/context-mill/agents/error-tracking/verify.md create mode 100644 fixtures/context-mill/agents/error-tracking/wire-ci.md create mode 100644 fixtures/context-mill/agents/feature-flags/create-flag.md create mode 100644 fixtures/context-mill/agents/feature-flags/evaluate.md create mode 100644 fixtures/context-mill/agents/feature-flags/init.md create mode 100644 fixtures/context-mill/agents/feature-flags/install.md create mode 100644 fixtures/context-mill/agents/feature-flags/report.md create mode 100644 fixtures/context-mill/agents/feature-flags/setup-feature-flags.md create mode 100644 fixtures/context-mill/agents/integration-v2/ai-observability.md create mode 100644 fixtures/context-mill/agents/integration-v2/capture.md create mode 100644 fixtures/context-mill/agents/integration-v2/dashboard.md create mode 100644 fixtures/context-mill/agents/integration-v2/error-tracking.md create mode 100644 fixtures/context-mill/agents/integration-v2/identify.md create mode 100644 fixtures/context-mill/agents/integration-v2/init.md create mode 100644 fixtures/context-mill/agents/integration-v2/install.md create mode 100644 fixtures/context-mill/agents/integration-v2/integrate-posthog.md create mode 100644 fixtures/context-mill/agents/integration-v2/logs.md create mode 100644 fixtures/context-mill/agents/integration-v2/report.md create mode 100644 fixtures/context-mill/agents/integration-v2/review.md create mode 100644 fixtures/context-mill/agents/integration-v2/warehouse.md create mode 100644 fixtures/context-mill/agents/metrics/instrument-metrics.md create mode 100644 fixtures/context-mill/agents/metrics/report.md create mode 100644 fixtures/context-mill/agents/metrics/setup-metrics.md create mode 100644 fixtures/context-mill/agents/metrics/verify-sdk.md create mode 100644 fixtures/context-mill/agents/replay-vision/enable-replay.md create mode 100644 fixtures/context-mill/agents/replay-vision/init.md create mode 100644 fixtures/context-mill/agents/replay-vision/install.md create mode 100644 fixtures/context-mill/agents/replay-vision/report.md create mode 100644 fixtures/context-mill/agents/replay-vision/scanner-broken-experiences.md create mode 100644 fixtures/context-mill/agents/replay-vision/scanner-session-summaries.md create mode 100644 fixtures/context-mill/agents/replay-vision/scanner-user-frustration.md create mode 100644 fixtures/context-mill/agents/replay-vision/setup-replay-vision.md create mode 100644 fixtures/context-mill/skill-menu.json create mode 100644 scripts/record-context-mill-fixtures.no-jest.ts create mode 100644 src/agent/runner/sequence/orchestrator/__tests__/skill-equivalence.test.ts create mode 100644 src/agent/runner/sequence/orchestrator/skill-picks.ts create mode 100644 src/agent/runner/switchboard/flags/agent-dag.ts create mode 100644 src/services/project-traits/__tests__/traits.test.ts create mode 100644 src/services/project-traits/index.ts create mode 100644 src/services/project-traits/traits.ts create mode 100644 src/shared/skill-resolution.ts diff --git a/fixtures/context-mill/agent-menu.json b/fixtures/context-mill/agent-menu.json new file mode 100644 index 000000000..12e4e8cc5 --- /dev/null +++ b/fixtures/context-mill/agent-menu.json @@ -0,0 +1,211 @@ +{ + "version": "1.0", + "buildVersion": "dev", + "agents": [ + { + "id": "capture-exceptions", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-capture-exceptions.md" + }, + { + "id": "configure", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-configure.md" + }, + { + "id": "credentials", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-credentials.md" + }, + { + "id": "init", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-init.md" + }, + { + "id": "install", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-install.md" + }, + { + "id": "link-releases", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-link-releases.md" + }, + { + "id": "report", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-report.md" + }, + { + "id": "setup-error-tracking", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-setup-error-tracking.md" + }, + { + "id": "test-setup", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-test-setup.md" + }, + { + "id": "verify", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-verify.md" + }, + { + "id": "wire-ci", + "flow": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-error-tracking-wire-ci.md" + }, + { + "id": "create-flag", + "flow": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-feature-flags-create-flag.md" + }, + { + "id": "evaluate", + "flow": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-feature-flags-evaluate.md" + }, + { + "id": "init", + "flow": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-feature-flags-init.md" + }, + { + "id": "install", + "flow": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-feature-flags-install.md" + }, + { + "id": "report", + "flow": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-feature-flags-report.md" + }, + { + "id": "setup-feature-flags", + "flow": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-feature-flags-setup-feature-flags.md" + }, + { + "id": "ai-observability", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-ai-observability.md" + }, + { + "id": "capture", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-capture.md" + }, + { + "id": "dashboard", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-dashboard.md" + }, + { + "id": "error-tracking", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-error-tracking.md" + }, + { + "id": "identify", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-identify.md" + }, + { + "id": "init", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-init.md" + }, + { + "id": "install", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-install.md" + }, + { + "id": "integrate-posthog", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-integrate-posthog.md" + }, + { + "id": "logs", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-logs.md" + }, + { + "id": "report", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-report.md" + }, + { + "id": "review", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-review.md" + }, + { + "id": "warehouse", + "flow": "integration-v2", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-integration-v2-warehouse.md" + }, + { + "id": "instrument-metrics", + "flow": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-metrics-instrument-metrics.md" + }, + { + "id": "report", + "flow": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-metrics-report.md" + }, + { + "id": "setup-metrics", + "flow": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-metrics-setup-metrics.md" + }, + { + "id": "verify-sdk", + "flow": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-metrics-verify-sdk.md" + }, + { + "id": "enable-replay", + "flow": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-replay-vision-enable-replay.md" + }, + { + "id": "init", + "flow": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-replay-vision-init.md" + }, + { + "id": "install", + "flow": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-replay-vision-install.md" + }, + { + "id": "report", + "flow": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-replay-vision-report.md" + }, + { + "id": "scanner-broken-experiences", + "flow": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-replay-vision-scanner-broken-experiences.md" + }, + { + "id": "scanner-session-summaries", + "flow": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-replay-vision-scanner-session-summaries.md" + }, + { + "id": "scanner-user-frustration", + "flow": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-replay-vision-scanner-user-frustration.md" + }, + { + "id": "setup-replay-vision", + "flow": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/agents-replay-vision-setup-replay-vision.md" + } + ] +} diff --git a/fixtures/context-mill/agents/error-tracking/capture-exceptions.md b/fixtures/context-mill/agents/error-tracking/capture-exceptions.md new file mode 100644 index 000000000..2bfd887d9 --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/capture-exceptions.md @@ -0,0 +1,116 @@ +--- +type: capture-exceptions +flow: error-tracking +label: Wire up exception capture +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [integration-v2-error-tracking-step, posthog-best-practices] +allowedTools: [Read, Write, Edit, Glob, Grep, Bash] +disallowedTools: [enqueue_task] +dependsOn: [install, init] +--- + +## Goal + +Make the errors the app does not catch reach PostHog, by whatever means the +SDK offers for that. Which means depends on the SDK: some autocapture +exceptions once you enable it at init, some wire into the framework's own +error handler, some give you a boundary to mount at the app entry. Follow the +docs and the reference example for this one, and set it up once per runtime — +never manual capture calls sprinkled across files. + +An app that runs code on a server as well as in the browser has two runtimes, +and each needs its own capture. Cover every runtime the docs cover for this +framework and the app actually uses: the server side takes the SDK's server +library, where the framework hands you its errors (for Next.js, +`onRequestError` in `instrumentation.ts`). A browser-only setup leaves every +server error uncaptured. An Electron app has the same split: its main process +runs Node, and its uncaught errors never reach the renderer's capture, so the +main process takes the server library. A packaged app ships without the +developer's `.env`, so a runtime `process.env` lookup in the main process is +always empty there: read the token the way the bundler inlines it at build time +(electron-vite: `import.meta.env.MAIN_VITE_*`). A fully static app has no +server runtime to cover. + +A page often shows two setups side by side: a global initializer, and an +explicit client you hold. Follow one of them the whole way through. Taking the +wiring from one and the calls from the other reads fine and compiles nowhere — +an initializer that hands back nothing leaves you nothing to call methods on. + +The SDK is installed and initialized — either it already was, or the install +and init tasks before you did it (see their handoffs); build on that, do not +re-check it. + +Install nothing except the server library your server-side capture imports, +when the manifest lacks it: add it with the project's package manager +(`detect_package_manager`). When it answers `No lockfile found. Default to +npm`, look up the tree first: in a workspace package, use the manager whose +lockfile sits at the workspace root above this directory, and npm only when no +parent holds a lockfile. Do not run tests or start the app, and do not touch +the build config: when the flow includes a configure task, it owns those files. +Stay inside this project's directory and set up capture in those places; that +is the whole job. + +Each import needs its declaration in the manifest of the package that holds the +importing file. An app inside a workspace often nests its own package (a +`v2/package.json` below this directory): when the SDK sits in a different +manifest than the code that imports it, add it to the importing package too, +with the workspace's manager. Otherwise the import resolves only through +hoisting and breaks in a focused install or a container build. + +Once your edits are in, run the project's build, or its typecheck when that +covers your files and is quicker, and fix what your edits broke. A failure +that was there before your edits is not yours: note it in your handoff and +leave it. Only a build the project defines in this checkout counts: a package +script or a compiler. Most Python, Ruby, and PHP apps have none, and then +there is nothing to run: do not create environments, install packages, or +reach for Docker to check your edit. Let the build check API names and types: write from the docs and +build, and open an SDK's type declarations only to fix an error the build +reports. + +Build, never run: no command that installs or launches the app (`expo run:*`, +`react-native run-*`, `flutter run`), because it opens a simulator or an +emulator on the user's machine. Leave no build output the project does not +ignore: in Go, check with `go vet ./...`, because `go build ./...` writes a +main package's binary into the project root. Your shell gets a reduced +environment, so a build that cannot find an SDK (`SDK location not found`) +failed because of this shell, not your edit: do not retry it, and say so in +your handoff. + +## Do not copy the SDK's own listeners + +Exception autocapture already registers the global handlers: `window.onerror` +and `unhandledrejection` in the browser, `uncaughtException` and +`unhandledRejection` in Node, `sys.excepthook` in Python, the panic hook in +Rust, and the uncaught-exception and signal handlers on iOS and Android. Turn +that on with the SDK's own option — `capture_exceptions`, +`enableExceptionAutocapture`, `enable_exception_autocapture`, `capture_panics`, +`errorTrackingConfig.autoCapture` — and register none of those handlers +yourself. A second listener on the same event sends every error twice, and it +stops matching the SDK's handling the moment the SDK changes. + +What the SDK cannot see is yours to add: errors a framework catches before any +global handler fires. Express error middleware, Fastify `setErrorHandler`, Hono +`onError`, Vue `app.config.errorHandler`, Angular `ErrorHandler`, SvelteKit +`handleError`, a React error boundary, Next.js `global-error` — hook those, +because the framework swallows the error and the global listener never hears +of it. NestJS is one more layer up: its exception filters answer every request +error before Express error middleware runs, so capture goes in a global filter +(the app's existing `@Catch()` filter when it has one), not in +`setupExpressErrorHandler`. A platform with no autocapture at all, such as Go, +is the other case: there the capture boundary at the entry point is the +mechanism, not a copy of one. + +## How you know you succeeded + +An error the app does not catch reaches PostHog from every runtime the app +runs in, through the mechanism each SDK gives you rather than one you invented, +and every PostHog library in the manifest is imported. No global error listener +of your own sits beside the SDK's autocapture. The project builds as well as it +did before your edits. You installed nothing but the server library your +capture imports, and did not run tests, search outside the project, or read +through the whole app or hand-wrap individual components or routes. Your handoff names the files you changed, the capture mechanism, and +the build command you ran with its result, so the report can explain it to the +user. diff --git a/fixtures/context-mill/agents/error-tracking/configure.md b/fixtures/context-mill/agents/error-tracking/configure.md new file mode 100644 index 000000000..3b9a49f11 --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/configure.md @@ -0,0 +1,173 @@ +--- +type: configure +flow: error-tracking +label: Apply build-config changes +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, Bash, load_skill_menu, install_skill, check_env_keys] +disallowedTools: [enqueue_task] +dependsOn: [capture-exceptions] +--- + +## Goal + +Make this project's production build emit and upload source maps or debug +symbols. Flutter Android/iOS release builds upload Dart AOT symbols separately +from platform-native symbols. Install the skill your task input names +(`install_skill` with the `skillId`) and read it — it is the source of truth +for the per-framework build-config and the uploader wiring. + +Two of the skill's steps are yours: + +- **"Apply build-config changes"** — make the bundler / build-config edits the + skill instructs for this platform, so the build produces matching maps or + debug symbols and runs the uploader. Only web source maps need chunk IDs. +- **"Make credentials available at build time"** — do the skill's step so the + build can read the upload credentials from the environment. If it calls for a + loader (e.g. `dotenv`), install it SILENTLY with the project's package + manager. Skip this step entirely when the platform already auto-loads `.env`. + +Install every dependency with the project's own package manager: call +`detect_package_manager` before the first install and use its answer, +translating any `npm install` the skill or docs show (`pnpm add -D …`, +`yarn add -D …`). In a pnpm or yarn workspace, npm fails outright on +`workspace:*` dependencies (`EUNSUPPORTEDPROTOCOL`) — that error means the +wrong manager, never a flag to retry with. When `detect_package_manager` +answers `No lockfile found. Default to npm`, look up the tree first: in a +workspace package, use the manager whose lockfile sits at the workspace root +above this directory, and npm only when no parent holds a lockfile. + +Change only what the upload needs. Do not remove or weaken a source-map setting +the project already has (`productionBrowserSourceMaps`, Vite's +`build.sourcemap`, webpack's `devtool`): a build without the upload credentials +must still emit what it emitted before. Do not upgrade a package the project +already depends on to quiet a peer-dependency warning, because a warning is not +a failure. Upgrade one only when the install or build fails on it, or when the +skill requires a newer version for the feature you are wiring. Keep the +project's version style: an exact pin stays exact. + +Wire the upload into a build the project already has, in this directory or in +a package nested below it. Code that no build compiles or bundles runs as +written, and its stack traces are already readable: do not add a bundler, a +compiler, or a new `build` or `start` script to create one. When this project +has no production build to attach an upload to, report this task as +`not needed` and say why in your handoff. + +When the upload step you wire runs a machine-global `posthog-cli` rather than +one from the project's own dependencies, do not try to install it or check for +it: a global install, `posthog-cli` itself, and `command -v` are blocked for +you, and the wizard already tried the install before your task. Name it in +your handoff as a follow-up for every other machine that runs the release +build — `npm install -g @posthog/cli@latest` — because without it the upload +step cannot run. + +When your changes make the build emit a bundle to a new directory (`dist/`, +`build/`), check that some script actually runs that output. A project whose +`build` writes `dist/index.js` while `start` still runs the original source +never executes the bundle the maps were uploaded for, so every uploaded map +goes unused. Add or fix the script that serves the built output. + +That run script has its own environment to satisfy, and it is not the build's. +The uploader's credentials are handled — your build step passes them itself. The +separate question is the variables **the application reads when it starts**: the +project token and host its init looks up. Those live in the same gitignored env +file, and a compiled binary or a bare interpreter loads nothing on its own. + +So open the init point and note the variables it reads. When the project +already loads the env file for them, you're done: never remove an env-file +flag or loader the project's `start` already has, because that local loading +is the project's choice. When it doesn't, do not wire +a loader into the run script: production supplies these as real environment +variables, and a script that loads the gitignored file breaks wherever it is +missing. Never put a hard `--env-file=.env` on `start`. Leave the script as it +is and name the gap in your handoff as a manual follow-up, with the variable +names. Leave it out of the handoff and the build is green, the symbols are +uploaded, and the single command you hand the user to verify with is the one +command that cannot capture. + +Put a multi-step build somewhere the tool actually runs it — a script file, a +make target, the manifest's own scripts — never an alias mechanism you are +assuming exists, borrowed from a neighbouring tool. + +Match the bundle's module format to the package's type. A build passes either +way, and the mismatch only shows when the bundle starts: `esbuild +--platform=node` emits CommonJS unless you pass `--format=esm`, so in a package +whose `package.json` sets `"type": "module"` the bundle dies at boot with +`ReferenceError: module is not defined in ES module scope`. Read the `type` +field before writing the command. + +## The names are a contract + +An env variable only works if the name the code reads is the name in the file. +You write the code that reads them; the `credentials` task writes the file, and +you two run in parallel. So never invent a name that already exists somewhere +else — look for the other half of the contract first, and adopt it: + +- **Call `check_env_keys` before you write the config.** It returns names, never + values. If the PostHog upload variables are already there, make your config + read exactly those names, whatever they are, even when they are not the ones + your skill's example shows. +- **Only when they are absent yet** are you the one deciding. Use the names your + skill documents for the mechanism you are wiring, and name them in your + handoff in full so `credentials` and `wire-ci` can match them. + +Names that merely look plausible are the failure here. A build reading +`POSTHOG_API_KEY` beside an env file holding `POSTHOG_CLI_API_KEY` throws no +error anywhere — the upload is skipped silently, the build looks clean, and +every stack trace stays minified. + +Do not write any credential values and do not create env files — the +`credentials` task owns that, in parallel with you. + +## Build it + +Once your edits are in, run the production build and read its exit status, not +only its log: the upload often runs before the type check, so the maps can +land in a build that still fails. Fix what your changes broke and build again. +A failure that was there before your changes is not yours: note it in your +handoff and leave it. Let the build check option names and types: write from +your skill, build, and open a plugin's type declarations only to fix an error +the build reports. + +Build, never run. A command that installs or launches the app (`expo run:*`, +`react-native run-*`, `flutter run`, `./gradlew install*`) opens a simulator +or an emulator on the user's machine, even where your skill names it as the +build. On an Expo app whose `android/` and `ios/` folders are generated, build +the JavaScript bundle instead: `npx expo export --source-maps --platform +`. Your shell blocks `make`, shell scripts, and a Gradle wrapper +outside the project root: when you put the build in a `make` target or a +script, run the build command inside it directly. Never add a package script +to get past a blocked command. Skip it, and say in your handoff what you could +not run. + +Your shell gets a reduced environment: `ANDROID_HOME` and other variables from +the user's shell do not reach it. A build that cannot find an SDK (`SDK +location not found`) failed because of this shell, not the project. Do not +retry it, and do not give the user a setup step for it: say the build could +not run here. + +The `credentials` task may not have written the upload credentials yet, so this +build may run without them. It has to pass either way. A teammate's checkout +and a pull-request build have no key either, and a config that demands one +stops their builds. When the build fails only because the upload credentials +are missing, make the upload skip itself when they are absent, with the option +your skill's plugin or CLI offers, and build again. Once the credentials are +written you cannot build without them: the build reads the env file, and a +prefix such as `VAR= npm run build` is blocked. Check the skip path by reading +the config instead. + +When the credentials are in place, the build creates a release and uploads to +the user's project. That is expected; it is what every production build will +do. + +## How you know you succeeded + +The build config carries the skill's source-map / debug-symbol changes and can +read its credentials from the environment at build time. The production build +passes with your changes, with or without the upload credentials. Your handoff +names every file you changed, the exact build-config keys you added, and the +build command you ran with its result and whether the credentials were +present, so the CI task can wire the same variables through the pipeline. diff --git a/fixtures/context-mill/agents/error-tracking/credentials.md b/fixtures/context-mill/agents/error-tracking/credentials.md new file mode 100644 index 000000000..d748955b9 --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/credentials.md @@ -0,0 +1,81 @@ +--- +type: credentials +flow: error-tracking +label: Get and write the upload credentials +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, Bash, load_skill_menu, install_skill, wizard_ask] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Put the PostHog source-map upload credentials into this project's environment. +Install the skill your task input names (`install_skill` with the `skillId`) +and follow its **"Write credentials to the env file"** step for the variable +names and the env file to pick. + +The upload needs a PostHog **personal API key** at build time. Only the user can +mint one — never call the PostHog API or any tool to create it. Get it and +write it in this one task (the key never survives across tasks): + +1. Ask with `wizard_ask`, exactly: + `{ id: "api-key", prompt: "Uploading source maps needs a PostHog personal API key. Source maps let PostHog show your original code in error stack traces, not minified code.\n\nCreate a key with the right permissions here:\n/source-maps-key\n\nThen paste it below.", kind: "text", sensitive: true }` + You receive `{ secretRef: "secret:..." }` — a vaulted reference, never the raw + value. If `wizard_ask` is unavailable (non-interactive run), report this task + with status `not needed` and say in your handoff that the user must create + the key and set the variables themselves; do not block. +2. Pick the env file per the skill (reuse the one PostHog's SDK already writes + its `POSTHOG_*` vars to, when there is one). Call `check_env_keys` on it + first (it returns present/absent, never values — never read the file + directly). +3. Settle the variable names before you write them — see "The names are a + contract" below. Then call `set_env_values`, passing the secretRef as a + value object, not a literal string — e.g. + `values: { "POSTHOG_CLI_API_KEY": { secretRef: "" }, "POSTHOG_CLI_PROJECT_ID": "", "POSTHOG_CLI_HOST": "" }` + with whichever names you settled on. The wizard resolves the ref locally, so + you never see the key value. +4. Document the same variable names for other developers: append them to + `.env.example` (create it if the project has none) with empty or + placeholder values — never a real value, and never the key itself. The + example file is committed and is the only `.env*` you may write directly; + it is how the next developer, and the next wizard run's `check_env_keys`, + learns the project expects these variables. The `init` task may write the + same file beside you, so read it right before you change it and add your + lines with `edit`; never `write` over it once it exists. + +Replace `` and `` from your project context. Do not touch the build config — the `configure` task owns that. + +## The names are a contract + +An env variable only works if the name in the file is the name the code reads. +You write the file; the `configure` task writes the code that reads it, and you +two run in parallel. So never invent a name that already exists somewhere else +— look for the other half of the contract first, and adopt it: + +- **Read the build config before you choose.** If it already references PostHog + env variables, use exactly those names, whatever they are, even when they are + not the ones your skill would suggest. Reading config is safe — it holds + names, not secrets. +- **Only when nothing references them yet** are you the one deciding. Use the + names your skill documents for the mechanism that was actually wired. +- **Either way, say which set you chose in your handoff, in full.** That is how + `configure` and `wire-ci` learn what to match. A handoff that says "the usual + variables" hands the next task the same guess you just made. + +Names that merely look plausible are the failure here. A build reading +`POSTHOG_API_KEY` beside an env file holding `POSTHOG_CLI_API_KEY` throws no +error anywhere — the upload simply never runs, and every stack trace stays +minified. + +## How you know you succeeded + +The env file holds the upload variables (the key as a resolved secret, the +non-secret project id and host as literals), written through the wizard tools, +never hardcoded in source, and `.env.example` documents the same names with +placeholders. Your handoff names the env file and every variable name — never +a value — so the CI task carries the same names into the pipeline. diff --git a/fixtures/context-mill/agents/error-tracking/init.md b/fixtures/context-mill/agents/error-tracking/init.md new file mode 100644 index 000000000..b1928af4a --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/init.md @@ -0,0 +1,121 @@ +--- +type: init +flow: error-tracking +label: Set up PostHog initialization +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-init, posthog-best-practices] +allowedTools: [Read, Write, Edit, Glob, Grep, Bash, check_env_keys, set_env_values] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Make sure PostHog is initialized. If the project already has a working +`posthog.init(...)` (or the framework's equivalent) with its env keys wired, +leave it alone and say so in your handoff. If it doesn't, create it following +your skill — it owns the how: the framework's init point, the env-var wiring +through the wizard tools, and `.env.example`. The `credentials` task may write +`.env.example` beside you, so read it right before you change it and add your +lines with `edit`; never `write` over it once it exists, or the upload +variables it documented are lost. + +You exist in this flow because the user asked for error tracking on a repo +whose PostHog init is missing or unproven. Initialize the SDK so exceptions can +flow and stop — no instrumentation, no extras. Don't set up exception capture +either way; the capture-exceptions task after you owns that. + +## Initialize the server the project ships + +A directory can hold more than one server: a workspace often keeps a small +script beside a nested package with its own manifest (`index.js` next to +`v2/package.json`). Initialize each server the project builds or deploys, the +one with a `build` or `start` script, a Dockerfile, or a job in the pipeline. A +script the project only runs in development, with nothing but a `dev` script, +gets no client. Name the server and its entry file in your handoff, so the +tasks after you cover the same one. + +## An existing init still needs its variable defined + +"Already initialised" is a property of the pair, not of the call. An init point +that reads `process.env.SOMETHING` only works when `SOMETHING` is defined in the +env file the project loads. A repo can carry an init that has never once run: +the call is there, the variable it names is nowhere, and the client is built +from an empty string. + +So before you leave an existing init alone, call `check_env_keys` on that env +file and look for the exact name the init reads. It returns names, never values. + +- **Present** — the pair is complete. Leave it alone and say so. +- **Absent** — the init is not wired yet, whoever wrote it. Write that variable + with `set_env_values` under the name the code already reads, and document it + in `.env.example`. Do not rename the code to match a name you would rather + have written; the code is the half that already exists. + +An empty key is the quiet failure here. A client constructed from `''` throws +nothing and logs nothing. The build is clean, the app starts, every capture call +returns — and no event ever arrives. + +## Make the environment actually reachable + +Writing the keys to `.env` is only half the job — something has to load that +file at runtime, or the app throws on boot and captures nothing. + +Most frameworks do it for you: Next, Nuxt, Astro and SvelteKit auto-load `.env`, +and Vite auto-loads it for client code. Nothing to do there. + +A plain Node backend does not — Express, Fastify, Hono, Koa, a raw `node:http` +server — and neither does a bare Rollup or webpack config. When the project +already loads `.env` there (a `dotenv` import, an env-file flag in its scripts), +leave it alone. + +When nothing loads it, do not wire a loader. Don't install a package for it and +don't edit `start` or `dev`. Every way in is a guess about where the app runs: a +hard `--env-file=.env` stops the app wherever the gitignored file is missing, +`--env-file-if-exists` needs Node 22.9, and putting the variables in front of +the command commits the key. Name it in your handoff as a manual follow-up +instead, with the variable names and the user's two options: load `.env` with +`dotenv`, or set the variables in the app's environment. Say that until then, +the guard stops the app at boot in development with +`POSTHOG_… variable required by PostHog is missing or un-configured`. That loud +failure is the guard doing its job. + +Some platforms have no environment to read at all, and there the answer is not +a loader. Angular on the stock `@angular/build` builder is the common one: +nothing populates `process.env`, `import.meta.env`, or the project's own +`src/environments/.env.ts` with your keys. + +The trap is that each of those *looks* like a mechanism. `import.meta.env` and +the `NG_APP_` prefix only exist with `@ngx-env/builder` installed, and a +generated `.env.ts` usually carries one unrelated key such as +`npm_package_version` and nothing else. Read from either and your key is +`undefined`: in development the guard throws while the module evaluates and the +app renders a blank page, and in a production build the guard returns quietly, +so the app looks fine while PostHog never initialises at all. + +So do not wire a lookup unless you have opened the thing it reads from and seen +your key defined there. When nothing populates it, write the real public project +token as a literal in the committed `src/environments/*` files. This is the +skill's "no valid environment to read from" case, and the public token is +publishable — it ships inside the browser bundle either way. + +## Leave the build to later tasks + +The `install` task may still be adding the SDK beside you, so do not build +here: the build would fail on a package that is about to arrive. The tasks +after you build the project once every edit is in, and fix what does not +compile. + +## How you know you succeeded + +An init point exists with the PostHog env keys present — whether it already +did or you just created it — keys in the env file and confirmed there with +`check_env_keys`, never hardcoded. On a platform that does not auto-load +`.env` and has no loader, your handoff names it as a manual follow-up; on a platform with no environment at all, the +token is a literal rather than a lookup into something that never defines it. +Your handoff names the files involved, how the client is constructed, and how +`.env` reaches it, so the capture-exceptions task can find the init options +without re-discovering them. diff --git a/fixtures/context-mill/agents/error-tracking/install.md b/fixtures/context-mill/agents/error-tracking/install.md new file mode 100644 index 000000000..0bb1cb16b --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/install.md @@ -0,0 +1,54 @@ +--- +type: install +flow: error-tracking +label: Add the PostHog SDK to the manifest +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-haiku-4-5 +skills: [integration-v2-install] +allowedTools: [Read, Edit, Glob, Grep, Bash] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Make sure the PostHog SDK is in the manifest. If it's already installed, +leave it alone and say so in your handoff. If it isn't, install it following +your skill — it owns the version rules, what counts as an environment failure, +and the fallback. The package manager comes from the section below, which wins +over your skill's own rule: the skill looks at this directory only. + +You only exist in this flow because the user asked for error tracking on a +repo without PostHog. Install the SDK the init will construct — the browser +SDK for an app with a browser side, the server SDK for a server-only app — and +stop: no instrumentation, no extras. A second, server-side library for an app +that has both is not yours to add. The `capture-exceptions` task adds it when +it wires server-side capture, so the manifest never carries a library no code +imports. + +## Pick the package manager first + +Call `detect_package_manager`. When it names a manager, use it. When it answers +`No lockfile found. Default to npm`, do not run npm yet: this directory may be +a package inside a workspace, whose lockfile sits at the repository root. Read +`../package.json` and `../../package.json` up to the root, and look there for a +lockfile (`pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, `package-lock.json`) or a +`packageManager` field. Reading them is part of this task even though they sit +above this directory; edit nothing there. Use the manager they name, from this +directory. npm is right only when no parent holds either: npm in a pnpm or Yarn +workspace fails on `workspace:*` dependencies (`EUNSUPPORTEDPROTOCOL`) or +leaves a second lockfile behind. + +## Python + +In a Python project, install into the virtualenv the project already keeps in +its directory. When it has none, add the package to the manifest and stop. Do +not create one: it would stay behind in the user's project. + +## How you know you succeeded + +The SDK is declared in the manifest at a real version — whether it already +was or you just installed it — or your handoff plainly says why the +environment stopped you. Your handoff names the manifest and the package, so +later steps import it under the name they will actually get. diff --git a/fixtures/context-mill/agents/error-tracking/link-releases.md b/fixtures/context-mill/agents/error-tracking/link-releases.md new file mode 100644 index 000000000..2e9645010 --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/link-releases.md @@ -0,0 +1,87 @@ +--- +type: link-releases +flow: error-tracking +label: Link deploys to releases +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, Bash, load_skill_menu, install_skill, detect_package_manager] +disallowedTools: [enqueue_task] +dependsOn: [capture-exceptions] +--- + +## Goal + +Link every exception this app sends to the production release it came from. +This platform ships its source as is, so there is nothing to upload. Instead the +production deploy resolves a PostHog release, and the app starts with that +release's ID in `POSTHOG_RELEASE_ID`. Install the skill your task input names +(`install_skill` with the `skillId`) and follow it. It owns the minimum SDK +version, the CI step per provider, and how the ID crosses each deploy boundary. + +Your task has three parts, in this order: + +1. **SDK version.** Make sure the project resolves at least the SDK version + that reads `POSTHOG_RELEASE_ID`, per the skill's "Update the SDK" step. An + older SDK ignores the variable without an error. Refresh the lock for that + one package with the project's own tool: call `detect_package_manager` + first. Do not upgrade across a major version when code from before this run + already calls the SDK; when the `install` handoff says this run added the + SDK, raise it straight to the minimum. The production runtime + decides what can install, not the interpreter on this machine: never lower + the version below the minimum because a local install fails. +2. **Resolve the release in the production deploy.** Trace the deploy path by + reading the project's own files: CI workflows, Dockerfiles, compose files, + deploy scripts, service and pool configs. Add the resolve step to the job + that deploys to production, and to no other job. +3. **Get the ID into the running app.** Pass the ID on at every boundary + between that step and the process that creates the PostHog client, until + that process starts with `POSTHOG_RELEASE_ID` in its environment. + +## Local development stays as it is + +This is a deploy-time change only. Local runs, tests, pull-request builds, and +previews send no release ID, and that is correct. So do not touch run scripts, +dev servers, test config, `.env`, or `.env.example`. Do not ask for a personal +API key, because nothing local uses one. Never run `posthog-cli` yourself: a +resolve creates a real release in the user's project. + +Only edit CI and deploy files that already exist. When this project has no +deploy path you can open and follow, make no CI changes. Report the task done +with the SDK update alone, and put the requirement into your handoff as a +manual follow-up. + +## The last hop decides it + +A release ID that stops one boundary short of the app looks correct in the +diff and does nothing. The resolve step succeeds, the deploy is green, and +every exception still arrives without a release. Each of these boundaries drops +the value unless you pass it on: a `docker build`, a container start, an SSH +session, a service manager's environment, PHP-FPM's `clear_env`, and Laravel's +cached config. So walk the path to its end, and pass the value on the same way +the deploy already passes the app's other runtime variables. + +In a workspace package, the deploy path usually starts at the repository root, +above this directory (`../.github/workflows`, a root `Dockerfile`): look there +before you conclude there is none. When you cannot open those files, name them +in your handoff. + +While you are at the start step, check the other names on it too. The app's +PostHog init reads a token and a host, and the start step may predate PostHog. +If it passes the app's variables by hand and leaves those out, add them by the +names the app's source reads, and name any secret the user must create. + +## How you know you succeeded + +The project resolves an SDK version that reads `POSTHOG_RELEASE_ID`, or your +handoff names the upgrade as a follow-up. The production deploy job resolves +the release before it ships, without failing the deploy when PostHog cannot be +reached or a PostHog secret does not exist yet. The user merges this change +before creating the secrets, so never stop a deploy step on an empty PostHog +variable (`${VAR:?…}`, an `exit 1`). The ID reaches the app process as +`POSTHOG_RELEASE_ID`, and no local, test, or pull-request path changed. Your +handoff lists the files you changed, the SDK version before and after, the +deploy path hop by hop, and every secret and variable the user must create, +with its exact name and where it goes. diff --git a/fixtures/context-mill/agents/error-tracking/report.md b/fixtures/context-mill/agents/error-tracking/report.md new file mode 100644 index 000000000..41e0facff --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/report.md @@ -0,0 +1,103 @@ +--- +type: report +flow: error-tracking +label: Summarise and hand off +model_pi: openai/gpt-5.6-luna +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [] +allowedTools: [Read, Glob, Grep, Write] +disallowedTools: [enqueue_task, publish_handoff] +dependsOn: [capture-exceptions, wire-ci, link-releases, verify] +--- + +## Goal + +Tell the user what error tracking now does for them and what they still have +to do, from the handoffs of every task in the run. `read_handoffs` gives you +each task's report — the capture mechanism, the files changed, the env +variable names, the CI secrets and variables to create, and any deploy path +that could not be traced. Do not re-derive any of it from the project. + +This flow keeps its report on disk. Write it once, with `write`, to +`posthog-error-tracking-report.md` at the top level of this project's +directory: the wizard's closing message sends the user to that file and reads +its warning block, and `test-setup` appends to it. `publish_handoff` is +blocked for this task; the file is the report. When any handoff carries a +manual follow-up, START +the report, right under its H1, with this warning block, one short bullet per +item. The wizard shows these bullets again when it exits. + +```markdown +> ⚠️ **Needs your attention** +> - Load `.env` in the app, or set `POSTHOG_API_KEY` in its environment. +``` + +Then, when the run wired source-map upload or release linking, or any +follow-up has steps, add a **"What you still need to do"** section — numbered, +copy-pasteable: + +1. Create a personal API key at `/source-maps-key` (skip when the + credentials handoff says the key is already written and no release linking + was wired). The link opens the key form with the 'Source map upload' preset + selected; the preset carries the error tracking write scope that both + uploads and release linking need. +2. Add it as the CI secret the wire-ci or link-releases step referenced, named + exactly as in the pipeline config. When link-releases also reads a project + ID variable (such as `POSTHOG_PROJECT_ID`), add it with the value + ``, and say where each goes in the CI provider's settings. +3. Any other manual follow-up the handoffs carry (an env file nothing loads, + an untraceable deploy path, provider-side settings, installing a missing + `posthog-cli`, an SDK upgrade across a major version). + +Then cover, briefly and concretely: + +- How uncaught errors reach PostHog now — the capture mechanism and the files + that carry it. +- If the run also installed and initialized the SDK, say so — the user + started this command without PostHog and now has it. +- When source-map upload was wired and neither the credentials nor the wire-ci + handoff reports a skip: the files changed (paths only), the exact production + build command, and that every production build now uploads. +- When the build was wired but the credentials or wire-ci handoff reports a + skip: the same files and command, and that the build is set up to upload. + Say that uploads start only once the upload variables are present where the + build runs. +- What the `verify` handoff found: the build command it ran and whether it + passed. When it uploaded, name the release and how many files went up, so + the user knows the first symbol set is already in PostHog. Anything still + failing is a follow-up in the warning block. When the build could not run in + the wizard's shell (an SDK it could not find, a blocked command), the + follow-up is to run that build command once themselves, not to set anything + up: their own shell has what the wizard's lacked. +- When it was skipped: one line saying why — readable stack traces on this + platform, or that Astro is not supported by the uploader. An outcome, not an + apology. Say plainly that the build command was left untouched. +- When release linking was wired: the files changed (paths only), the SDK + version it now requires, and the deploy path the release ID takes to the + app. Say that each production deploy resolves a release and starts the app + with `POSTHOG_RELEASE_ID`, so every exception names the release, version, and + commit it came from. Say plainly that local runs, tests, and pull-request + builds are unchanged and send no release ID. When the link-releases handoff + reports no deploy path it could follow, say what the user's deploy must do + instead. +- How to verify: trigger any error and look at + `/project//error_tracking`; uploaded symbol sets appear + at `/project//error_tracking/configuration`. With + release linking, check after the next production deploy that the stack trace + shows the release, and that the exception's `$release_id` matches the ID the + deploy resolved. + +Never write a secret value into the report — only variable names. Replace +`` and `` from your project context. Give the same +summary in chat, warning block first. + +## How you know you succeeded + +`posthog-error-tracking-report.md` exists on disk, written in one `write` +call, and a user who reads only the file knows +how errors reach PostHog, whether the build passed with the changes, the +follow-ups they still owe (the API key and the +CI secrets and variables named exactly, when upload or release linking was +wired), and where in PostHog to see the first captured exception. diff --git a/fixtures/context-mill/agents/error-tracking/setup-error-tracking.md b/fixtures/context-mill/agents/error-tracking/setup-error-tracking.md new file mode 100644 index 000000000..67ec23a78 --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/setup-error-tracking.md @@ -0,0 +1,170 @@ +--- +type: setup-error-tracking +flow: error-tracking +seed: true +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [Write, Edit, Bash, complete_task] +dependsOn: [] +--- + +## Goal + +Plan a PostHog Error Tracking setup and seed the task queue. The end state: +errors the app does not catch reach PostHog; where the platform ships minified +bundles or stripped binaries, production builds upload the source maps or debug +symbols that make the stack traces readable; and where the platform runs its +source as is (Python, Ruby, PHP), each production deploy links its errors to a +release. + +First establish three facts from the repo: + +**1. Is PostHog already integrated?** Look for `posthog-js` or a server SDK in +the dependency manifests, or a `posthog.init(...)` / snippet in the source. +Check the project state for existing events if the repo is ambiguous. + +Integrated means the init runs, not that the package is listed. An init point +is a pair: the call, and the key it is constructed from. A repo can carry the +call while the key it names is defined nowhere — then the client is built from +an empty string and captures nothing, however complete the manifest looks. So +when you find an init that reads a variable, look for that same name in the +repo's committed env template or its build config. Found, or the project state +shows real events arriving: integrated. Named nowhere, or you cannot tell: +**queue `init`**. It re-checks the pair itself and leaves a complete init +alone, so queuing it when you are unsure costs one cheap task, while skipping +it on a keyless init costs the whole run. + +**2. Which uploader variant is this project — or none?** Read the manifests +and pick at most one, by this precedence (first match wins): + +- `react-native` or `expo` in `package.json` dependencies → `react-native`. + A React Native repo also carries `ios/Podfile`, an `.xcodeproj` and Gradle + files for its native shells, so this rule wins over every native marker + below. Picking `ios` or `android` for it uploads no JavaScript source maps, + and every JavaScript stack trace stays minified. +- `pubspec.yaml` → `flutter` +- an `.xcodeproj`, `Podfile`, or `Package.swift` → `ios` +- a Gradle build file that applies `com.android.application` or + `com.android.library`, or an `AndroidManifest.xml` → `android`. A Gradle + project without these markers is a JVM server: keep reading. +- `go.mod` → `go` +- `Cargo.toml` → `rust` +- `astro` in `package.json` dependencies → **none**. Astro is not supported by + the uploader: it inlines scripts below its asset limit into the HTML, so a + build routinely emits a `.map` with no `.js` beside it, and the upload step + then fails the whole build. This rule wins over every `package.json` match + below — an Astro project that also depends on `vite` is still **none**. +- otherwise read `package.json` dependencies, first match wins: + `nuxt` → `nuxt`; `next` → `nextjs`; + `@angular/core` → `angular`; `vite` → `vite`; `webpack` → `webpack`; + `rollup` → `rollup`; `react` → `react`; server-only Node → `node`; + any other browser JS → `web`. Server-only Node is `node` only when a + build compiles or bundles it (a `build` script running `tsc`, esbuild, or + another bundler), in this directory or in a package nested below it. + Server JavaScript that no build touches runs as written: **none**. +- **none** for platforms whose stack traces are already readable: plain + Python (Django, Flask, FastAPI), Ruby, PHP, Elixir, JVM servers, .NET. + Skip the whole upload subgraph for them — a skipped upload on such a + platform is an outcome, not a gap. Fact 3 decides what Python, Ruby, and + PHP get instead. + +When a variant matched, the uploader skill id is +`error-tracking-upload-source-maps-`. Pass it to the four upload +tasks as `inputs: { skillId: "", displayName: "" }` +so no task re-detects. + +**3. Which release-linking variant is this project — or none?** It applies +when the app itself is a server that runs Python, Ruby, or PHP source as is: + +- a Python app (`requirements*.txt`, `pyproject.toml`, `Pipfile`, or + `setup.py`; Django, Flask, FastAPI, and plain Python alike) → `python` +- a Ruby app (`Gemfile` or a `*.gemspec`; Rails, Sinatra, and plain Ruby + alike) → `ruby` +- a PHP app (`composer.json`; Laravel and plain PHP alike) → `php` +- **none** for every other platform. A manifest that only carries tooling for + another platform does not count: a `Gemfile` for CocoaPods or fastlane beside + a mobile app, or a `requirements.txt` for scripts beside a Node service. The + mobile uploader variants (`react-native`, `flutter`, `ios`, `android`) always + mean none here. Bundled and compiled platforms get their release from the + uploader, and Elixir, JVM servers, and .NET have no release-linking skill + yet. + +When a variant matched, the skill id is +`error-tracking-link-releases-`. Pass it to `link-releases` as +`inputs: { skillId: "", displayName: "" }`. Fact 3 +does not depend on fact 2: a Django app that also bundles a Vite frontend in +the same project gets both the upload subgraph and `link-releases`, and both +default to the same release. + +The three facts are independent — settle ALL of them before you enqueue +anything. "PostHog is already integrated" answers fact 1 only; it never decides +fact 2 or fact 3, and an already-integrated project still gets the upload +subgraph or `link-releases` when a variant matches. A compiled or bundled JS +project normally has an uploader variant: a Node service built with `tsc` ships +minified/compiled output, so it is the `node` variant, not "none". Only three +kinds of project skip the upload subgraph — the readable-stack platforms listed +above, Astro, and server JavaScript that no build compiles or bundles. + +Then seed the graph: + +- `install`, only when the SDK is missing from the manifest. +- `init`, independent of `install` — whenever fact 1 did not show a complete + pair. Do not stop on an uninstrumented repo, integrate. +- `capture-exceptions`, after whichever of `install` and `init` you queued + (with no dependencies when you queued neither). +- When an uploader variant matched, add the upload subgraph: + - `credentials`, no dependencies — it stops to ask the user for a personal + API key, so keep it a root task: the prompt reaches the user early while + the code tasks run. + - `configure`, after `capture-exceptions` — build-config changes; it runs + after the code edits so the two never fight over the same files. + - `wire-ci`, after `configure` and `credentials`. +- When a release-linking variant matched, `link-releases`, after + `capture-exceptions` — and after `wire-ci` too when you queued the upload + subgraph, because both edit the deploy pipeline. It changes production + deploys only, needs nothing from the user during the run, and leaves local + development as it is. +- When you queued the upload subgraph, `verify`, after every other task that + edits code: `capture-exceptions`, `configure`, `credentials`, and + `link-releases` when you queued it. It builds the project once every edit is + in, with the upload credentials in place, and fixes what broke. It does not + wait for `wire-ci`: that task edits only CI files, which a local build never + reads, so the two run side by side. A project without the upload subgraph + has no build of its own to check (Python, Ruby, and PHP apps build only in + their deploy), so it gets no `verify`. +- `report`, after every other queued task except `test-setup`. It writes the + handoff once the work is done, so it describes what actually shipped. +- When you queued the upload subgraph, `test-setup` last, after `report` — it + offers the user an optional local end-to-end test. The report comes first on + purpose: a user who walks away still gets it. + +A task can name another as a dependency only once that one is queued and has +an id. So queue the tail one call per turn, never batched: `verify` when you +queue it, then `report` naming the `verify` id, then `test-setup` naming the +`report` id. A `report` queued in the same turn as `verify` cannot wait for it, +and then reports a build that has not finished. + +Never plan an identify, capture, dashboard, or session-replay task — this run +sets up error tracking, not the full integration. The minimal SDK footprint +that `install` and `init` leave behind is enough for exceptions to flow. + +## How you know you succeeded + +Every task in the chosen graph is queued with that dependency shape, the four +upload tasks (when queued) share the same `{ skillId, displayName }` inputs, +`verify` (when queued) depends on every task that edits code except `wire-ci`, +`report` depends on every other task except `test-setup` (directly or +transitively), `test-setup` (when queued) depends on `report`, and the first +task is runnable. `link-releases` (when queued) carries its own +`{ skillId, displayName }` inputs. Your plan states all three facts explicitly: +whether PostHog was integrated — and, when you called it integrated, the name +of the key you found defined —, which uploader variant matched — or, when you +queue no upload tasks, why no variant applies: which readable-stack platform +this is, or that Astro is not supported by the uploader —, and which +release-linking variant matched, or that none applies. A plan that never +mentions fact 2 or fact 3 is an incomplete plan, not a decision. Keep labels +short — the action in a few words. diff --git a/fixtures/context-mill/agents/error-tracking/test-setup.md b/fixtures/context-mill/agents/error-tracking/test-setup.md new file mode 100644 index 000000000..facccf9be --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/test-setup.md @@ -0,0 +1,55 @@ +--- +type: test-setup +flow: error-tracking +label: Offer an optional local test +sink: true +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, Bash, load_skill_menu, install_skill, wizard_ask] +disallowedTools: [enqueue_task] +dependsOn: [report] +--- + +## Goal + +The setup is done and the report is written. Offer the user an optional, +one-time, end-to-end check that errors reach PostHog with readable stack traces. + +You run after the report on purpose. A user who stepped away still gets a +finished setup and a report, so nothing waits on this test. + +Ask before you do anything else, with `wizard_ask`: +`{ id: "test-affordance", prompt: "Error tracking is set up, and the report is in posthog-error-tracking-report.md. Optional: want me to help you test it locally? I'll add a temporary test button (or route) and build the app, so you can run it and confirm errors show up in Error Tracking with readable stack traces. Then I'll remove it.", kind: "single", options: [{ label: "Yes, help me test it", value: "yes" }, { label: "No, I'm done", value: "no" }] }` + +- **"no"**, no answer (`__cancelled__`), or `wizard_ask` unavailable: report + this task done right away, noting the test was offered and not taken. Install + no skill and read nothing first. +- **"yes"**: install the skill your task input names (`install_skill` with the + `skillId`) and follow its **"Test the local setup"** step for the + platform-appropriate affordance, the `captureException` shape, the + placement, and the read-before-edit / always-revert rules. Add the + affordance, then run the production build yourself: it uploads the maps for + the bundle that carries the affordance. + When the build fails, revert, tell the user what failed, and stop. When it + passes, pause with a second `wizard_ask` (id `"test-done"`, a single + `Continue (revert test code)` option) whose prompt gives the rest as literal + numbered steps: run the built app, trigger the affordance, then confirm the + error resolves to real source in Error Tracking. When the platform's build + and run are one step (an Xcode Run, `expo run`), give that step to the user + instead of building. After the user continues, or when that ask comes back + unanswered, REVERT every test edit per the skill's rules. Never leave the + affordance in place, even if the user says it didn't work. + +When the user says the test failed, add a short **"Local test"** section at the +end of `posthog-error-tracking-report.md` with what they saw, and say the same +in chat. The report task has already run, so this is the only place the +failure is written down. + +## How you know you succeeded + +Either the offer was declined or unanswered and no code changed, or the +affordance was added, tested, and fully reverted. Your handoff says which, and +a failure the user reported is in the report file. diff --git a/fixtures/context-mill/agents/error-tracking/verify.md b/fixtures/context-mill/agents/error-tracking/verify.md new file mode 100644 index 000000000..7cfa900a5 --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/verify.md @@ -0,0 +1,82 @@ +--- +type: verify +flow: error-tracking +label: Build and check the setup +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, Bash, check_env_keys, detect_package_manager] +disallowedTools: [enqueue_task] +dependsOn: [capture-exceptions, configure, credentials, link-releases] +--- + +## Goal + +Every edit of this run is in. Prove the setup works by building the project +the way it builds for production. `read_handoffs` names the files each task +changed, the packages it added, and the env variable names it used. + +Read the handoffs first. When the `configure` handoff reports a passing +production build that ran with the upload credentials present, and this run +has no `link-releases` task, that build already ran on the finished code: every +other code task finished before `configure` started. Do not build again. Hand +off its command, result, and uploader summary lines as your own, and say you +reused them. Otherwise: + +1. Install with the project's package manager, so the build sees the manifest + and lockfile this run left behind. In a workspace package, that is the + manager whose lockfile sits at the workspace root above this directory. +2. Run the production build the project defines in this checkout: its package + manager's build script, or the platform's compiler (Cargo, Go, Gradle, + Xcode). You cannot run a Dockerfile or a CI job; when that is the only + build, say so and finish. When the project defines no build, run its + typecheck or lint script instead; when it defines none of them, say so and + finish. +3. Read the exit status first, then the log. When source-map or debug-symbol + upload is wired and the credentials are written, the log shows the uploader + creating a release and uploading files. A green build with no upload lines + means the upload never ran: compare the variable names the build config + reads with the names in the env file (`check_env_keys`). When the + `credentials` handoff reports no key, the build still has to pass, with the + upload skipped. +4. Fix what this run's changes broke, in the files the handoffs name, and build + again. A failure that was there before this run is not yours: say so in your + handoff and leave it. After a few attempts, stop and hand off what still + fails. + +Build, never run. A command that installs or launches the app (`expo run:*`, +`react-native run-*`, `flutter run`, `./gradlew install*`) opens a simulator +or an emulator on the user's machine. On an Expo app whose `android/` and +`ios/` folders are generated, build the JavaScript bundle instead: `npx expo +export --source-maps --platform `. + +When the upload is a separate `posthog-cli` command rather than part of the +build, or the build sits in a `make` target or a shell script, you cannot run +those: run the build command itself, and say so. Never add a package script to +get past a blocked command. Your shell gets a reduced +environment: `ANDROID_HOME` and other variables from the user's shell do not +reach it. A build that cannot find an SDK (`SDK location not found`) failed +because of this shell, not the project: do not retry it, and do not give the +user a setup step for it. A missing toolchain, or a local interpreter too old +for a version this run pinned, is the environment, not the setup: say so and +finish, and never lower a version to make a local install pass. + +Finish this task `done` even when the build still fails. Your handoff gives +the command, the error, and whether this run caused it, and the report turns +it into a follow-up. A `failed` verify stops the report, and the user gets no +report at all. + +A build with the credentials in place creates a release and uploads to the +user's project. That is expected: it is what every production build will do, +and it puts the first symbol set in PostHog right away. + +## How you know you succeeded + +The production build passes with this run's changes, and when the upload is +wired with credentials, its log shows the release and the upload. Your handoff +gives the command you ran, or that you reused `configure`'s build, its result, +the uploader's summary lines (release name and how many files it uploaded), +every fix you made with its file, and anything that still fails, so the report +can tell the user what was verified. The task ends `done` either way. diff --git a/fixtures/context-mill/agents/error-tracking/wire-ci.md b/fixtures/context-mill/agents/error-tracking/wire-ci.md new file mode 100644 index 000000000..ea5f4f3e8 --- /dev/null +++ b/fixtures/context-mill/agents/error-tracking/wire-ci.md @@ -0,0 +1,109 @@ +--- +type: wire-ci +flow: error-tracking +label: Set up CI for automatic uploads +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, load_skill_menu, install_skill] +disallowedTools: [enqueue_task] +dependsOn: [configure, credentials] +--- + +## Goal + +Make the credentials reach the production build wherever it actually runs, so +source maps upload on every deploy — not just on a local build. Install the +skill your task input names (`install_skill` with the `skillId`) and follow its +**"Set up CI for automatic uploads"** step — it owns tracing where the +production build runs and wiring the credentials through every layer, whatever +the CI provider. + +The `configure` and `credentials` handoffs already name the build-config keys +and the exact environment-variable names in use — carry those same names into +the pipeline; do not invent new ones. Trace the deploy path by reading the +project's own files (CI workflows, Dockerfiles, deploy scripts) — never invent +config that is not there. You cannot create the CI secret that holds the API +key; reference it by name and carry that follow-up, plus any deploy path you +could not trace, into your handoff for the report. + +A package inside a workspace rarely holds its own pipeline. The CI config and +deploy files usually sit at the repository root, above this directory +(`../.github/workflows`, `../../.gitlab-ci.yml`): look there before you +conclude there is none, and wire the job that builds this package. When you +cannot open them, name the file and the job in your handoff. + +The user merges this change before they create the secrets. A step that fails +when a PostHog variable is empty (`${VAR:?…}`, an `exit 1`, a required input) +breaks every deploy until they do. Pass the variables through and let the +upload skip itself when they are empty: the build config's gate does that, and a +`posthog-cli` step in the pipeline needs a condition on the key. Name the +secrets in your handoff instead of enforcing them. + +## Two things cross the boundary, not one + +Credentials are half of it. The uploader also needs a **release identity** — a +name and a version — and it derives that from the CI's own git variables or +from a `.git` directory. A container build sees neither: `.git` is almost +always in `.dockerignore`, and the CI's variables stop at the `docker build` +command. Nor does a hardcoded release name rescue you; the uploader wants both +halves, and stops the build when it has only one. + +So forward the provider's git variables into the build the same way you forward +credentials, and declare each one as `ARG` **and** `ENV` — `ARG` alone is not +visible to the uploader's environment lookup. Your skill's "Associate the +release with a git commit" step lists the variables per provider. Read that +step even though it is not the CI step: this boundary is where it applies. + +Forward them only where a provider actually sets them. A project with no +pipeline — an image built and run by hand — has nothing to inherit from, and +variables declared but never filled resolve to no release at all: it reads as +wired and still fails the build. There the identity has to be supplied outright, +both halves, from something the build itself holds — a build argument the +operator passes, or the manifest's own version — so name and version are always +present. Decide which case you are in by reading the repo, not by assuming a +provider exists. + +That `ARG`-plus-`ENV` shape is for the git variables and the non-secret settings +only. The API key is a secret and keeps whatever secret-carrying mechanism the +build system offers — a build secret mounted for the one step that needs it, a +masked variable, a secret file. A secret in `ARG` or `ENV` is recorded in the +build history, and the builder itself will warn you: *do not use ARG or ENV +instructions for sensitive data*. Widening the git-variable pattern to cover the +key is a downgrade, not consistency. + +A build cache between the pipeline and the build, such as Turborepo's, is one +more boundary. List the upload credentials among the task's hashed inputs +(Turborepo's `env`), so a build that has them never replays an entry made +without them, and pass the git variables through without hashing them +(`passThroughEnv`). Leave the cache on: a hit restores output whose chunks are +already uploaded. + +## The runtime boundary has names too + +Upload credentials are a build-time concern. The app also reads its own +variables at **run** time, and the step that starts it is another place a name +has to match — a `docker run -e`, a compose file, a systemd unit, a platform's +environment settings. That step was written before PostHog existed here, so the +name it passes is whatever the project used back then. If `init` settled on a +different one, the deployed process starts with an undefined key. + +Nothing fails loudly. In production the init guard returns quietly instead of +throwing, so the process boots, serves traffic, and reports nothing — the same +silent shape as a mismatched upload variable, one boundary later. + +So read the names the app's own source reads, and make the start step pass +exactly those. Rename the deploy step's variable, not the code: the code is the +half that already exists. Name any secret the user must create under its new +name in your handoff. + +## How you know you succeeded + +The pipeline that runs the production build carries the upload credentials by +the same names the credentials task used and reaches the uploader with a +resolvable release identity, and the step that starts the app passes the +variable names the app's own source reads. Every secret the user still has to create is named +in your handoff. Your handoff lists the CI files you changed +and every manual follow-up, so the report can hand them to the user. diff --git a/fixtures/context-mill/agents/feature-flags/create-flag.md b/fixtures/context-mill/agents/feature-flags/create-flag.md new file mode 100644 index 000000000..04bbefd39 --- /dev/null +++ b/fixtures/context-mill/agents/feature-flags/create-flag.md @@ -0,0 +1,48 @@ +--- +type: create-flag +flow: feature-flags +label: Create the example flags in PostHog +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-mcp] +allowedTools: [Read, posthog_exec] +disallowedTools: [Write, Edit, Bash, enqueue_task] +dependsOn: [] +--- + +## Goal + +Make sure this PostHog project has one example flag for each side in your +`sides` input, and none for a side that is not listed: + +| Side | Key | Name | +|---|---|---| +| `backend` | `wizard-example-backend-flag` | Wizard example backend flag | +| `frontend` | `wizard-example-frontend-flag` | Wizard example frontend flag | + +For each flag you need: + +1. Look it up by key with `feature-flag-get-definition-by-key`. One keyed + lookup per flag; never list every flag in the project. +2. Found: reuse it as it is. Do not change its rollout or its active state. +3. Not found: create it with `create-feature-flag`, using the key and name + above, a boolean flag with one release condition at 0% rollout, and + `active: false`. New flags are active by default, so pass + `active: false` explicitly. The user turns it on when they are ready. +4. Create rejected because the key already exists: another run created it + after your lookup. Look it up by key once more and reuse it as in step 2. + +Run `info` on each tool before calling it; never guess the input shape. + +If a call is rejected for permissions, or the tool is hidden for a missing +scope, stop and say so in your handoff: the credentials need +`feature_flag:read` and `feature_flag:write`. Do not retry with other +tools. + +## How you know you succeeded + +Your handoff gives, for each flag: its side, key, id, whether you created or +reused it, whether it is active, and its URL in PostHog (the tool result's +URL, verbatim). diff --git a/fixtures/context-mill/agents/feature-flags/evaluate.md b/fixtures/context-mill/agents/feature-flags/evaluate.md new file mode 100644 index 000000000..83aab53f1 --- /dev/null +++ b/fixtures/context-mill/agents/feature-flags/evaluate.md @@ -0,0 +1,44 @@ +--- +type: evaluate +flow: feature-flags +label: Evaluate the flags in the app +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [integration-v2-feature-flags-step] +allowedTools: [Read, Write, Edit, Glob, Grep] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +For each flag the create-flag handoff names, add one evaluation on that +flag's side of this app: the backend flag in server code through the server +SDK, the frontend flag in browser or device code through the client SDK. +Never evaluate a flag on the other side. Your skill carries the SDK flag docs +and the best-practices page; follow them for the exact calls. + +The SDKs are installed and initialized, either already or by the tasks before +you. Build on that; do not re-check it. + +For each flag, choose a call site where a real request or screen passes +through. On the backend, evaluate once for that request and pass the value +down; never re-evaluate deeper in the call stack. Put the keys in a constants +module the call site imports, one module per language; a template script that +cannot import it gets the key from the server's constant, never a literal. +Evaluate with the identified user's distinct id, the same id on both sides, +and report each evaluation back to PostHog the way the docs show for that SDK. +Gate something harmless on each value, such as a log line or a small label, +so the app behaves the same while the flags are off. + +This is an edit-only task. Do not install dependencies, run the build, or +start the app. + +## How you know you succeeded + +Each flag is evaluated once, at one call site on its own side, with its key +imported from a constants module, and its evaluation is reported. Your +handoff names, for each flag, the files changed and the call site, plus how +the distinct id is chosen on each side. diff --git a/fixtures/context-mill/agents/feature-flags/init.md b/fixtures/context-mill/agents/feature-flags/init.md new file mode 100644 index 000000000..516bdbd6c --- /dev/null +++ b/fixtures/context-mill/agents/feature-flags/init.md @@ -0,0 +1,35 @@ +--- +type: init +flow: feature-flags +label: Set up PostHog initialization +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-init, posthog-best-practices] +allowedTools: [Read, Write, Edit, Glob, Grep, check_env_keys, set_env_values] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Make sure PostHog is initialized on each side in your `sides` input. An +existing init counts only when the env variable it reads is defined: check it +with `check_env_keys`. When a side's init is complete, leave it alone and +say so. Otherwise create or finish it following your skill, including the +env wiring and `.env.example`. A template-script frontend gets the PostHog +snippet in its base template. + +Initialize each SDK so a flag can be evaluated, and stop. Do not evaluate any +flag; the evaluate task owns that. + +You do not install packages, run builds, linters, or tests, or start the app. +The install task owns packages, and your edits just need to be right by +reading. + +## How you know you succeeded + +PostHog initializes from a defined key on every side in `sides`. Your +handoff names, for each side, the init file, the client the evaluate task +should use, and the env variable names (never values). diff --git a/fixtures/context-mill/agents/feature-flags/install.md b/fixtures/context-mill/agents/feature-flags/install.md new file mode 100644 index 000000000..950dd81f7 --- /dev/null +++ b/fixtures/context-mill/agents/feature-flags/install.md @@ -0,0 +1,31 @@ +--- +type: install +flow: feature-flags +label: Add the PostHog SDKs to the manifest +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-install] +allowedTools: [Read, Edit, Glob, Grep, Bash] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Make sure each side in your `sides` input has its PostHog SDK in the +manifest: the server library for `backend`, the browser or mobile library +for `frontend`. Leave an SDK that is already there alone and say so. +Install a missing one following your skill, which owns the package manager +and version rules. + +A frontend that is only scripts in server-rendered templates has no package +to install: the init task adds the PostHog snippet there. Install nothing for +that side, and install nothing beyond these SDKs. + +## How you know you succeeded + +Each side's SDK is declared in the manifest at a real version, or your +handoff says plainly why the environment stopped you. Your handoff names the +manifest and package for each side. diff --git a/fixtures/context-mill/agents/feature-flags/report.md b/fixtures/context-mill/agents/feature-flags/report.md new file mode 100644 index 000000000..340ed97d2 --- /dev/null +++ b/fixtures/context-mill/agents/feature-flags/report.md @@ -0,0 +1,50 @@ +--- +type: report +flow: feature-flags +label: Write the setup report +sink: true +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-notebook, integration-v2-mcp] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Compose the setup report from `read_handoffs` only, then publish it with a +single `publish_handoff` call. The same call mirrors the markdown into a +shareable PostHog notebook. The notebook skill says what the result means and +covers older wizards. Do not write a report file. The handoff call and the +notebook are how the report reaches the user. + +Write one section per flag: + +- The flag: its side, key, URL, whether it was created or reused, and whether + it is active, as the handoff gives it. Say a flag stays off until the user + enables it only when the handoff marks it inactive. +- Where the app evaluates it: files and call site, the constants module, and + how the distinct id is chosen. + +Then: + +- If the run installed or initialized an SDK, say which and on which side. +- How to confirm it works: open the page or endpoint that evaluates each flag, + then find the evaluation on the flag's page in PostHog. It can take a few + minutes to show up. + +The run does not check that an evaluation reached PostHog, so never write that +one did. Where a step failed or was skipped, say so plainly instead of rounding +it up to success. + +## How you know you succeeded + +One `publish_handoff` call went through with the full report, and a user who +reads only it knows which flags were created, which side evaluates each and +where, which are still off and need turning on, and how to confirm an +evaluation reaches PostHog. Every claim in it traces to a handoff. The notebook +mirror is best effort: when it was created, the user has its link, and when it +wasn't, your final message says why. A missing notebook never fails this task. diff --git a/fixtures/context-mill/agents/feature-flags/setup-feature-flags.md b/fixtures/context-mill/agents/feature-flags/setup-feature-flags.md new file mode 100644 index 000000000..b46e90946 --- /dev/null +++ b/fixtures/context-mill/agents/feature-flags/setup-feature-flags.md @@ -0,0 +1,66 @@ +--- +type: setup-feature-flags +flow: feature-flags +seed: true +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Glob, Grep] +disallowedTools: [Write, Edit, Bash, complete_task] +dependsOn: [] +--- + +## Goal + +Plan example PostHog feature flags for this project and seed the task queue. +The end state: one example flag per side of the app that exists, each +evaluated once in one place on its own side and reported back to PostHog, and +a report in a PostHog notebook telling the user how to turn the flags on. + +First establish two facts from the repo. + +**1. Which sides does the app have?** + +- `backend`: server code that handles requests, such as route handlers, API + views, controllers, server components, or server loaders. +- `frontend`: JavaScript or device code the app owns that runs in a browser + or on a device, such as client components, a single-page app, inline + scripts in its page templates, script files its pages load (directly or + through asset helpers such as import maps or Vite), or mobile screens. + +A side counts only when the app already has code there to put an evaluation +in. Never add a side to host a flag. Server-rendered templates that load no +JavaScript of the app's own are not a frontend: such an app has only a +backend. An API has only a backend; a mobile app or a static single-page app +has only a frontend. + +**2. Is PostHog already integrated on each of those sides?** Look for the +PostHog SDK for that side in the dependency manifests (or, for template +scripts, the PostHog snippet) and an init call in the source. An init counts +only when the key it reads is defined in the repo's committed env template or +build config. When you cannot tell, treat it as missing: the init task +re-checks and leaves a complete init alone. + +Then seed the graph. Give every task the same input: `sides`, the list of +sides you found (`["backend", "frontend"]`, `["backend"]`, or +`["frontend"]`). Pass no other inputs; each task learns the rest from the +handoffs before it. + +- `install`, only when an SDK a side needs is missing from the manifest. +- `init`, whenever an init is missing or unproven on either side. +- `create-flag`, with no dependencies. It only talks to PostHog. +- `evaluate`, after `create-flag` and after whichever of `install` and + `init` you queued. +- `report`, after every other task. + +Never plan capture, dashboard, or session-replay work. This run sets up the +example flags, nothing else. + +## How you know you succeeded + +Every task above is queued with that dependency shape and the `sides` input, +`report` depends on every other task, and your plan states which sides the +app has, whether PostHog is integrated on each, and the files that told you. +Keep labels short. diff --git a/fixtures/context-mill/agents/integration-v2/ai-observability.md b/fixtures/context-mill/agents/integration-v2/ai-observability.md new file mode 100644 index 000000000..942e05f90 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/ai-observability.md @@ -0,0 +1,60 @@ +--- +type: ai-observability +flow: integration-v2 +label: Add AI Observability +model_pi: openai/gpt-5.6-terra +effort_pi: high +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, load_skill_menu, install_skill] +disallowedTools: [enqueue_task] +dependsOn: [capture] +optional: true +--- + +## Goal + +Add AI Observability to the LLM calls this project already makes. Read the +upstream handoffs and inspect the call sites, not just the dependency names. +If there are no LLM calls, complete as `not needed` with the reason and make no +changes. Do not install a vendor SDK, add a demo call, or use manual capture to +invent an AI feature in an app that has none. + +For existing LLM calls, load the `ai-observability` skill menu and install the +variant matching the calling code's language and provider or agent framework. +Follow that skill's selection rules and instrumentation references. Manual +capture is appropriate only for existing calls without a supported wrapper. +Instrument against the provider SDK version the app already uses; never +require, assume, or request an upgrade of the app's own dependencies — if the +wrapper cannot support the app's version, fall back to manual capture or +report why. Reuse the PostHog client and identity established earlier in this +run. Follow the skill's privacy-mode instructions: default new SDK clients to +`privacy_mode=False` (Python) or `privacyMode: false` (Node), so prompt and +completion content is captured. Preserve existing privacy settings, redaction, +and explicit user or project requirements. Use the variant's documented controls +where capture is configured elsewhere; do not strip manual-capture content by +default. If a variant cannot be chosen from the code, report the ambiguity as +`not needed`; this default run does not ask the user to choose a provider. + +This is the instrumentation part of a larger integration. Name the packages +this task needs in your handoff for review to install; do not edit dependency +manifests, and never write a version number you invented — the package manager +resolves real versions when review installs by name. Defer the skill's +package-manager and import-check commands to that task. For Go, review adds the +modules with `go get` and `go mod tidy`; do not hand-edit `go.mod` or `go.sum`. +Do not run the app or make paid LLM calls. Use `check_env_keys` and +`set_env_values` for environment files, using the project credentials supplied +by the wizard. + +## How you know you succeeded + +Existing LLM calls are wired using the selected skill, or the handoff clearly +explains why this task was not needed. List the variant, changed files, declared +dependencies, and a concrete call path the user can trigger to verify the +session/trace/generation tree. Include the skill's **Privacy mode** handoff: +the effective setting, the file and line to edit, when to enable it, and the +[privacy-mode docs](https://posthog.com/docs/ai-observability/privacy-mode). Pass any +deferred dependency work to review. +Describe delivery as unverified unless this run actually observed it; do not +publish a separate setup report. diff --git a/fixtures/context-mill/agents/integration-v2/capture.md b/fixtures/context-mill/agents/integration-v2/capture.md new file mode 100644 index 000000000..e77450f40 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/capture.md @@ -0,0 +1,51 @@ +--- +type: capture +flow: integration-v2 +label: Capture events +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [integration-v2-capture, posthog-best-practices] +allowedTools: [Read, Write, Edit, Glob, Grep] +disallowedTools: [enqueue_task] +dependsOn: [install, init, identify] +--- + +## Goal + +Decide which events are worth capturing in this app, then instrument them in the +same pass — read each file once, choose the events, and add the capture calls +while the file is already open. Instrumenting the events is the job; everything +below is a rule you apply while you do it, not work of its own. + +The identify step's handoff already says how this app attributes events. Read it +once, up front, and follow it: + +1. Where identity is established for you — a client library that remembers it, or a + framework middleware that binds it per request — a plain capture is already + attributed. Write the plain call and move on. Do not add a context of your own, + and do not go looking through the call tree to prove it. +2. Where the handoff says it is not — no middleware, or a call path that runs + outside the request — tag that call with the distinct id and the session id. + +Where the project has no identity to begin with — the identify step found nothing to +wire, because the app has no accounts or login — personless events are the right +answer. Capture plainly, with no id and no placeholder, and say so in your handoff. + +The placeholder is for the third case only: identity exists in this project, but no +stable id reaches the call site. Do not guess at the id and do not invent a fallback — +pass `DISTINCT_ID` there so the gap is visible in the code, and say in your handoff +that identity exists but could not be reached, so the report calls it out as an issue +to follow up rather than claiming events that belong to nobody. + +Never put PII in an event. When new information about the user surfaces, tag the +user the way the identify docs describe, not the event. + +## How you know you succeeded + +The meaningful user actions across the app have capture calls that fire on the +real action, not on page load, each one attributable to the user who took it, and +`.posthog-wizard-cache/.posthog-events.json` lists the events you instrumented. + +You do not run builds, linters, or tests — the review task verifies the whole integration after you; your edits just need to be right by reading. diff --git a/fixtures/context-mill/agents/integration-v2/dashboard.md b/fixtures/context-mill/agents/integration-v2/dashboard.md new file mode 100644 index 000000000..349e49c47 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/dashboard.md @@ -0,0 +1,23 @@ +--- +type: dashboard +flow: integration-v2 +label: Create a starter dashboard +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [integration-v2-dashboard, integration-v2-insight, integration-v2-mcp] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [Write, Edit, Bash, enqueue_task] +dependsOn: [capture] +--- + +## Goal + +Create a starter PostHog dashboard with a few insights built on the events this +integration instruments, using the PostHog MCP. + +## How you know you succeeded + +A dashboard exists with a handful of insights on the captured events, and you hand +off its URL for the report to link. diff --git a/fixtures/context-mill/agents/integration-v2/error-tracking.md b/fixtures/context-mill/agents/integration-v2/error-tracking.md new file mode 100644 index 000000000..ee76c1382 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/error-tracking.md @@ -0,0 +1,36 @@ +--- +type: error-tracking +flow: integration-v2 +label: Add error tracking +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [integration-v2-error-tracking-step, posthog-best-practices] +allowedTools: [Read, Write, Edit, Glob, Grep] +disallowedTools: [enqueue_task] +dependsOn: [install, init] +--- + +## Goal + +Make the errors the app does not catch reach PostHog, by whatever means the SDK +offers for that. Which means depends on the SDK: some autocapture exceptions once +you enable it at init, some wire into the framework's own error handler, some give +you a boundary to mount at the app entry. Follow the docs and the reference example +for this one, and set it up in one place — never manual capture calls sprinkled +across files. + +The SDK is already installed and initialized (see the context from previous steps); +build on that, do not re-check it. + +This is an instrument-only task. Do not install dependencies, run the build, run +tests, or start the app — a later `build` step does all verification. Stay inside +this project's directory and set up that one place; that is the whole job. + +## How you know you succeeded + +An error the app does not catch reaches PostHog, through the mechanism this SDK +gives you rather than one you invented. You did not install anything, run a build, +lint, or tests (the review task verifies after you), search outside the project, or read through the whole app or hand-wrap +individual components or routes. diff --git a/fixtures/context-mill/agents/integration-v2/identify.md b/fixtures/context-mill/agents/integration-v2/identify.md new file mode 100644 index 000000000..9c2e0cbf1 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/identify.md @@ -0,0 +1,62 @@ +--- +type: identify +flow: integration-v2 +label: Wire user identification +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [integration-v2-identify, posthog-best-practices] +allowedTools: [Read, Edit, Glob, Grep] +disallowedTools: [enqueue_task] +dependsOn: [install, init] +--- + +## Goal + +Wire user identification so everything the app reports — its errors as much as its +events — carries who the user is. + +The distinct id is the app's own stable identifier for the user — a primary key, a +uuid, a resource name. Not an email and not a username: those are PII and they change; +send them as person properties instead. Fall back to email only when the app truly has +no other stable key, and say so in your handoff — do not invent one by altering the +app's schema. + +Work out first what you are in: a client-only app, a fullstack or SSR app, or a +backend or API. Identification takes a different shape in each, and the shape +follows from that answer: + +1. Client and frontend — identify once, and only once, when the user logs in or + registers, and reset when they log out. That single call merges what was already + captured against the anonymous id into the stable distinct id you give it. The + library persists identity from there, so everything after it is attributed to the + same user until reset — nothing needs re-identifying per page or per event. +2. Fullstack or SSR — your identification hinges on the client side, where the + identity is persisted. The distinct id and the session id travel on every request + the frontend sends, in the header format the docs describe. Some libraries already + do this for you; read the docs and the example app before wiring it by hand. The + backend should take note of the session and distinct id as soon as possible and + either carry it to every capture or use the identified context to identify the + request. +3. Backend and API — a server serves many users at once, so identity belongs to the + request, never to the process. Take it from the incoming request or the ambient + context, as far as the app allows. Then either tag each event with the distinct + id and session id, or, where the SDK has contexts, open one around the whole + request and identify that context so everything the request reports inherits it. + Where the SDK ships a middleware for this framework, that is what does this — use + it rather than writing your own. Read the docs and the example app. + +## How you know you succeeded + +Identification matches the kind of app you are in. While a user is known, what the +app reports is attributable to them with a stable distinct id — the errors it +reports, not only the events — established at the boundary the SDK gives you rather +than repeated at call sites that already inherit it. Where the app changes who the +user is mid-request, that boundary cannot know it yet, and establishing identity +again there is the point, not a duplicate. Your handoff names the files you +changed, how identity is established in them, and what a later step must do for its +own calls to inherit it — whether that is nothing at all, or tagging each call +itself. If the app has no auth or user concept, say so and stop. + +You do not run builds, linters, or tests — the review task verifies the whole integration after you; your edits just need to be right by reading. diff --git a/fixtures/context-mill/agents/integration-v2/init.md b/fixtures/context-mill/agents/integration-v2/init.md new file mode 100644 index 000000000..474081812 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/init.md @@ -0,0 +1,38 @@ +--- +type: init +flow: integration-v2 +label: Set up PostHog initialization +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-init, posthog-best-practices] +allowedTools: [Read, Write, Edit, Glob, Grep] +disallowedTools: [enqueue_task] +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. + +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 +follow the shape of the examples provided. How call sites reach the client is +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 +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 +reaches that client — every step after you has to reach the same one the same way. +If the app ships a Content-Security-Policy, the handoff also names exactly +which directives you touched (`script-src`, `connect-src`, `worker-src`) and +which you left alone — the review verifies directive-by-directive, and an +unnamed directive reads as unhandled, not as fine. + +You do not run builds, linters, or tests — the review task verifies the whole integration after you; your edits just need to be right by reading. diff --git a/fixtures/context-mill/agents/integration-v2/install.md b/fixtures/context-mill/agents/integration-v2/install.md new file mode 100644 index 000000000..6c6d7274d --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/install.md @@ -0,0 +1,67 @@ +--- +type: install +flow: integration-v2 +label: Add the PostHog SDK to the manifest +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-haiku-4-5 +skills: [integration-v2-install] +allowedTools: [Read, Edit, Glob, Grep, Bash] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Install the PostHog SDK with the project's own package manager, so the real +published version lands in the manifest and the lockfile — not one you made up. +Run the manager's add command with the bare package name and let it resolve the +version: `npm install ` (or the project's pnpm/yarn/bun), `pip install `, +`composer require `, `bundle add `, `gem install `. Never invent a +version — one that was never published fails the whole run with `ETARGET`, and +guessing another just fails again. The only version you write by hand is one copied +from the framework reference example, and only in the environment fallback below. + +Add the client library, plus the server library if the app has server-side code +that sends events. If the SDK is already installed, leave it and say so. + +Some ecosystems pin an explicit version in a manifest no install command resolves +(Swift SPM, Gradle). There, declare the dependency the way the framework reference +shows and take the version from the SDK's latest release — do not invent one. + +Attempt the install once. If it fails on something you own — a wrong package name or +the wrong manager — fix that and run it one more time. + +But if the environment prevents the install through no fault of your change, do NOT +spiral retrying it. These are environment failures, not yours: + +- a peer-dependency conflict the project already had (npm `ERESOLVE`), +- a dependency already in the manifest that itself does not resolve (a bad or yanked + version, a package that no longer exists) — the failure names a package that is not + PostHog, +- the package manager crashing on the project's existing dependency graph or a + corrupt/incompatible lockfile (e.g. npm `Cannot read properties of null`), +- the package manager itself failing to run or provision — corepack unable to + switch to a pinned version (`Failed to switch pnpm to …`, `Cannot find matching + keyid`), a missing manager binary, a toolchain the machine does not have, +- no network or registry reachable. + +The test: if the failure names your PostHog package or your command, it is yours to +fix; if it names another dependency, a version pin the project set, or the toolchain +itself, it is the environment — fall back and move on. + +When you hit one of those, fall back: add the PostHog package to the manifest by hand +at a known-good version, so the dependency is still declared for the later steps and +for the user's own install. Use the framework reference example's spec if it names +one; otherwise use a caret on the SDK's current known-good release — `posthog-js` +`^1.407.2`, `posthog-node` `^5.46.1`, `posthog-php` `^4.12.1`, `posthog` (Python) +`^7.29.0`, `posthog-ruby` `^3.21.0`. The caret keeps it current without pinning a +patch; never invent a version that was never published. Then move on, and say in your +handoff exactly what failed and the command +you ran, so the review step and the report surface it. + +## How you know you succeeded + +The SDK resolved and installed at its real version, or you have reported plainly in +your handoff why the environment stopped it. Your handoff names the manifest and the +package, so later steps import it under the name they will actually get. diff --git a/fixtures/context-mill/agents/integration-v2/integrate-posthog.md b/fixtures/context-mill/agents/integration-v2/integrate-posthog.md new file mode 100644 index 000000000..712e39238 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/integrate-posthog.md @@ -0,0 +1,51 @@ +--- +type: integrate-posthog +flow: integration-v2 +seed: true +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Glob, Grep] +disallowedTools: [Write, Edit, Bash, complete_task] +dependsOn: [] +--- + +## Goal + +Plan a PostHog integration and seed the task queue with this graph: + +- `install` and `init`, independent of each other. +- `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. +- `ai-observability`, after `capture`, parallel to `error-tracking` — it instruments + existing LLM calls, or reports that none apply. Queue it on every default run; the + task checks applicability rather than the planner guessing from a package name. +- `logs`, after `ai-observability` — it configures log capture on supported + platforms, or reports why it does not apply. Queue it even when AIO will be + skipped. These tasks run sequentially because both instrument the same entry + and initialization files, and Logs preserves any tracing provider AIO + configures — an ordering-dependent instruction. (Their dependency installs + are deferred to review, so manifests are not the conflict.) +- `review`, after `install`, `init`, `identify`, `capture`, `error-tracking`, + `ai-observability`, and `logs` — + 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`, independent of AIO, Logs, and `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. + +If `enqueue_task` does not offer a task's type, this run excludes that product +— skip it rather than retrying, and hang nothing off 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. diff --git a/fixtures/context-mill/agents/integration-v2/logs.md b/fixtures/context-mill/agents/integration-v2/logs.md new file mode 100644 index 000000000..f5750d6cf --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/logs.md @@ -0,0 +1,60 @@ +--- +type: logs +flow: integration-v2 +label: Add log capture +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, load_skill_menu, install_skill] +disallowedTools: [enqueue_task] +dependsOn: [ai-observability] +optional: true +--- + +## Goal + +Configure PostHog log capture for this project's supported runtimes. Load the +`logs` skill menu, install its matching skill, and read the platform reference +before editing. Inspect the runtime and existing logging setup; use the +documented OTLP exporter or SDK-native log capture for that platform. If the +app already uses OpenTelemetry, write against its existing OTel version and +name exporter packages compatible with it — never require, or write code that +assumes, an upgrade of a package this integration did not introduce. A +browser-only app must not receive a server exporter. If no documented setup +applies, complete as `not needed` and explain why. + +Export only log lines this integration adds. Create a dedicated logger for the +PostHog exporter and emit a few purpose-written lines at meaningful points the +app already passes through. Even where the platform reference attaches the +exporter to the application's root or existing loggers, do not — the app's +existing logs are data this run has no mandate to export, and every line that +leaves must be visible in this run's diff. Reuse any existing PostHog log +export and leave all existing handlers and outputs intact; if capture is +already configured, report that without adding a second exporter. Preserve any +tracing provider AIO configured in the previous step. Do not export secrets, +request bodies, or user data, and do not scatter logs through unrelated code. + +This is the instrumentation part of a larger integration. Instead of the +standalone skill's install command, name the required packages in your handoff +and leave installation, manifest and lockfile updates, builds, and lint to +review. Do not edit dependency manifests or write a version number you +invented — the package manager resolves real versions when review installs by +name. Use `detect_package_manager` if needed. Use +the wizard's supplied project and region and the env names from upstream +handoffs; inspect and write environment files only through `check_env_keys` +and `set_env_values`. Do not request credentials or select a different project. +If required configuration is unavailable, report what is missing instead of +guessing a region. + +## How you know you succeeded + +Log capture is configured once for the supported runtime, was already present, +or has a clear skip reason. The handoff names the changed files, packages, env +variable names (never values), and any dependency work for review. Give a +specific code path the user can trigger to produce one of the added log lines +and find it in PostHog Logs; delivery remains unverified until observed. Note +for the report that only lines added by this run are exported, and the one-line +change that routes the app's existing loggers into the same exporter if the +user wants more. Do not publish a separate report. diff --git a/fixtures/context-mill/agents/integration-v2/report.md b/fixtures/context-mill/agents/integration-v2/report.md new file mode 100644 index 000000000..25bda1924 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/report.md @@ -0,0 +1,53 @@ +--- +type: report +flow: integration-v2 +label: Write the setup report +sink: true +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [integration-v2-report, integration-v2-notebook, integration-v2-mcp] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [enqueue_task] +dependsOn: [dashboard, review] +--- + +## Goal + +Compose 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 publish it with a single `publish_handoff` +call. The same call mirrors the markdown into a shareable PostHog notebook. The notebook skill says what the result +means and covers older wizards. Do not write a report file. The handoff call +and the notebook are how the report reaches the user. + +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. + +Where a handoff carries a report section, that step already wrote the part of +the report it owns. Include it as its own section instead of rewriting or +summarizing it, and do not restate its contents elsewhere. + +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. + +## How you know you succeeded + +One `publish_handoff` call went through with the full report: what was +installed and initialized, the events captured, whether identify was wired or +skipped, error tracking added, AI Observability and Logs configured, skipped, or +failed with reasons, 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 notebook mirror is +best effort: when it was created, the user has its link, and when it wasn't, +your final message says why, and when an update failed, that the notebook holds the earlier version. A missing notebook never fails this task. diff --git a/fixtures/context-mill/agents/integration-v2/review.md b/fixtures/context-mill/agents/integration-v2/review.md new file mode 100644 index 000000000..b36ec7c19 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/review.md @@ -0,0 +1,104 @@ +--- +type: review +flow: integration-v2 +label: Verify and review the integration +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [posthog-best-practices, integration-v2-build] +allowedTools: [Read, Edit, Glob, Grep, Bash] +disallowedTools: [enqueue_task] +dependsOn: [install, init, identify, error-tracking, capture, ai-observability, logs] +--- + +## Goal + +You are the last hands on the code. First make the integration run, then review it, +then leave it building to the best of your ability. Do both in one pass, verifying and reviewing are the same +reading of the same changeset. + +**Install and verify.** The earlier steps edited code but did not install — +install now, then verify the project builds, typechecks, and lints, whichever +of those it defines. Install what the manifest declares plus every package the +upstream handoffs name, adding the named ones by bare name with the project's +package manager so it resolves real versions. The app's existing dependencies +are not yours to touch: never upgrade, downgrade, or re-add a package this +integration did not introduce. If an instrumentation package's peer range +conflicts with a dependency the app already has, install an older +instrumentation version that fits the app's existing versions — find it with +the package manager, stepping down major versions (`pkg@^7`, then `@^6`, +…) for a few attempts rather than looking for documentation of one. If none +fits, revert that piece of instrumentation, leave the app's dependency alone, +and record the incompatibility so the report can say what was skipped and why. An optional upstream task +(AI Observability, Logs) may have failed and left partial edits no handoff +describes — install and build either way, and let the build surface stray +imports; fix or revert them like any other defect. Do not run the test suite; the +runtime does not allow it, and a green build is the bar. A bad version only surfaces +here: if the install fails because a declared version does not exist (npm `ETARGET`, +"no matching version", a yanked release), do not guess pins — reinstall the +package by bare name and let the package manager pick, matching the framework +reference example's spec only if that also fails. If the failure is the environment, not the +integration's own change (a pre-existing broken dependency, a package manager that +cannot provision), note it and move on; do not spiral. + +**Review, as a strict reviewer who did none of the writing.** The changeset is +already handed to you: `read_handoffs` returns every upstream task's handoff, and +each one names the files it touched and what it changed in them. That union of +touched files IS the changeset. Read each changeset file once and judge it — after +your own edit you already know its contents, so do not re-read it. Read beyond the +changeset only where a dimension sends you: one neighboring example per pattern you +are checking, and the callers of code that changed. Nothing else — not the SDK's +installed internals, not other tasks' instructions, not a diff of the whole tree; +the handoffs are the signal. +The handoffs also carry what no file shows — env values written through +`set_env_values`, manifest edits. Judge each change against these dimensions, in +order: + +1. Minimal — every line earns its place. Delete helpers nothing calls, defensive + wrapping around code that cannot fail, config for features that were not set up, + and comments that narrate what a line does or that it was added. +2. Unrelated — the run must not have changed behavior outside the integration. + Revert reformatting, renames, or edits in code the integration never needed. +3. Codebase patterns — for each kind of edit (client construction, how call sites + reach it, config and env access, imports, naming, comment density), find one + neighboring example in this project and compare. If a change invented a seam the + project does not have — a registry, locator, wrapper, or app the codebase never + uses — replace it with the closest pattern the project actually uses. +4. Example shapes — where the framework reference example shows a shape for init or + instrumentation, the code should be recognizably that shape adapted to this + codebase. Codebase idiom beats the example when they conflict; the PostHog + correctness rules you were given beat both. + +You never change what is captured — event names, properties, and where events fire +are a contract the dashboard and report are built on. Refactor how, and kill bad +changes; never alter the what. + +Events reaching PostHog in production is the point of this code, so a capture wired +to a place it will never fire, an uninitialized SDK, or a call the runtime silently +drops is squarely yours to catch and fix — it is a code defect. What you cannot do is +confirm delivery: you cannot exercise the app, and you never treat "I could not +verify events arrive" as a finding. + +Stay inside verify-and-review. These are not your job: + +- The report or the dashboard — other tasks own those; do not write or judge them. +- Product or analytics design — which events are worth tracking, identity strategy, + framework-version tradeoffs. The changeset is the decision; review whether the code + implements it correctly, not whether it was the right decision. +- Anything the integration did not touch. Do not widen scope to pre-existing issues. + +If you notice something real but out of scope, leave it — a one-line mention in your +handoff, no more. Only flag what you can pin to a specific line and dimension — no +taste-based rewrites, and never expand the integration. For each fix, ask what would +behave differently if it were wrong, and check by reading the callers. After any +change, re-run the build or lint and confirm it still passes. + +## How you know you succeeded + +The project installed and builds, typechecks, and lints as well as it did before the +run; you can name each review dimension and say it passes; and your fixes are in the +files. If the build or lint fails only on pre-existing errors you did not introduce, +that still counts — put a one-line summary in the `conflict` field and the detail in +what you did. Reserve a failed status for when your own changes break the build. Put +the number of fixes and the dimension each addressed in your handoff. diff --git a/fixtures/context-mill/agents/integration-v2/warehouse.md b/fixtures/context-mill/agents/integration-v2/warehouse.md new file mode 100644 index 000000000..9079ae5a4 --- /dev/null +++ b/fixtures/context-mill/agents/integration-v2/warehouse.md @@ -0,0 +1,41 @@ +--- +type: warehouse +flow: integration-v2 +label: Connect your data sources +runnerSeeded: true +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-warehouse, integration-v2-mcp] +allowedTools: [Read, Glob, Grep, wizard_ask, posthog_exec] +disallowedTools: [Write, Edit, Bash, enqueue_task] +dependsOn: [] +--- + +## Goal + +Connect the data sources listed in your task input to PostHog's data warehouse, +so the project's own data can be queried next to the events this run +instruments. The wizard found them in the project; your job is to turn each one +into a real connection, or into a link the user can finish in the browser. + +You are the only step that stops to ask the user for anything, so make the ask +count: send the user to that source's secure connect page in one `wizard_ask` +call, tagged with that source's kind as its `subject`. The user enters the +credentials on that page, so no secret passes through you. A decline answers +that one source. Move on to the next source rather than re-asking or ending the +round. + +Touch no project code. This step connects data; it does not edit the app. + +## How you know you succeeded + +Every source in your input reached a decided end: connected in PostHog, handed +back as a link to finish, or skipped with a reason. Your handoff carries a +finished report section naming each source and which of those three it was, so +the reporting step can include it as it stands. + +A link is a handoff, not a connection. Your report section opens with the count +you connected, and your `complete_task` status matches it: `done` only when you +connected at least one source. diff --git a/fixtures/context-mill/agents/metrics/instrument-metrics.md b/fixtures/context-mill/agents/metrics/instrument-metrics.md new file mode 100644 index 000000000..4030ceea3 --- /dev/null +++ b/fixtures/context-mill/agents/metrics/instrument-metrics.md @@ -0,0 +1,32 @@ +--- +type: instrument-metrics +flow: metrics +label: Instrument the service with metrics +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Write, Edit, Glob, Grep, load_skill_menu, install_skill] +disallowedTools: [enqueue_task] +dependsOn: [verify-sdk] +--- + +## Goal + +Instrument your service with application metrics. When your task input names +a `package`, stay inside it — sibling packages belong to other chains. +Install the platform's skill the way the verify handoff names it (`load_skill_menu` category +"metrics", then `install_skill`), and follow it end-to-end — it owns where +metrics belong (request middleware, background +jobs, external calls, business commit sites), which of counter, gauge, and +histogram fits each site, and the low-cardinality attribute rules. + +Import the client the way the verify handoff names it. Only additive changes: +add metric calls, never restructure the code they land in. + +## How you know you succeeded + +The hot paths and business commit sites record metrics through the one shared +client, the project still builds, and your handoff lists every metric name +with its type and where it fires. diff --git a/fixtures/context-mill/agents/metrics/report.md b/fixtures/context-mill/agents/metrics/report.md new file mode 100644 index 000000000..d1b5362cf --- /dev/null +++ b/fixtures/context-mill/agents/metrics/report.md @@ -0,0 +1,44 @@ +--- +type: report +flow: metrics +label: Report and hand off +sink: true +model_pi: openai/gpt-5.6-luna +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-notebook] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [enqueue_task] +dependsOn: [instrument-metrics] +--- + +## Goal + +Tell the user what their service now measures, from the handoffs of every task +in the run. Briefly and concretely: + +- Each metric now recording: its name, type (counter, gauge, histogram), and + where in the code it fires. +- The service name the client reports under, and the SDK version the run + verified or installed. +- Anything skipped or deferred, with the reason — an environment that blocked + an upgrade is an outcome, not an apology. +- Where results appear: the Metrics page in PostHog, with the first series + arriving as traffic flows. + +If the run also installed or initialized the SDK, say so — the user started +this command without PostHog and now has it. + +Publish the report with a single `publish_handoff` call. The same call mirrors +the markdown into a shareable PostHog notebook. The notebook skill says what the result means and covers +older wizards. Do not write a report file. The handoff call and the notebook +are how the report reaches the user. + +## How you know you succeeded + +A user who reads only your report knows what their service measures, where +each number comes from, what still needs them, and where to look first. The +report went through one `publish_handoff` call. The notebook mirror is best +effort: when it was created, the user has its link, and when it wasn't, your +final message says why, and when an update failed, that the notebook holds the earlier version. A missing notebook never fails this task. diff --git a/fixtures/context-mill/agents/metrics/setup-metrics.md b/fixtures/context-mill/agents/metrics/setup-metrics.md new file mode 100644 index 000000000..de6259ae2 --- /dev/null +++ b/fixtures/context-mill/agents/metrics/setup-metrics.md @@ -0,0 +1,60 @@ +--- +type: setup-metrics +flow: metrics +seed: true +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Glob, Grep] +disallowedTools: [Write, Edit, Bash, complete_task] +dependsOn: [] +--- + +## Goal + +Plan an application-metrics setup and seed the task queue. Metrics are a +per-service concern: every service gets its own SDK install and its own +`service_name`. + +First map the repo — mechanically, before any judgment. Run one `find` per +manifest pattern across the whole tree, every time, even when the root looks +like a plain npm workspace (repos mix ecosystems, and the workspace list in a +root manifest is not the whole map): + + **/package.json **/pyproject.toml **/requirements.txt **/Pipfile + **/go.mod **/composer.json **/Gemfile + +Every directory holding a hit is a package. Classify each: a **service** runs +server-side work (server entrypoints, workers, APIs — whatever the language); +browser-only apps and libraries are not services and get no chain (the report +notes them). Ignore installed-dependency and scaffolding directories +(`node_modules`, `.claude`, caches) — they are not packages. + +Then seed, per service: + +- `verify-sdk`, with no dependencies — it settles that service's SDK question + (installed, new enough, initialized for metrics) before any + instrumentation. Pass `inputs: { package: "", service_name: "" }` + so the task knows which package it owns; omit `package` in a single-package + repo. +- `instrument-metrics`, after that service's `verify-sdk`, with the same + inputs. + +Chains for different services are independent — do not wire edges between +them, so they run in parallel. Last, one `report` that depends on every +`instrument-metrics`. It writes the handoff last, so it describes what +actually shipped. + +Metrics ride each service's existing PostHog SDK (`posthog.metrics`), so the +graph is the same whether or not the repo has PostHog today — `verify-sdk` +absorbs the difference. Never plan an identify, capture, or dashboard task: +this run sets up application metrics, not the full integration. + +## How you know you succeeded + +Every service has its own verify → instrument chain carrying its package and +service name, the chains share no edges, the report depends on all of them, +and every `verify-sdk` is runnable. Keep labels short — the action in a few +words, naming the service when there are several. diff --git a/fixtures/context-mill/agents/metrics/verify-sdk.md b/fixtures/context-mill/agents/metrics/verify-sdk.md new file mode 100644 index 000000000..a17445f0a --- /dev/null +++ b/fixtures/context-mill/agents/metrics/verify-sdk.md @@ -0,0 +1,46 @@ +--- +type: verify-sdk +flow: metrics +label: Verify the PostHog SDK is ready for metrics +model_pi: openai/gpt-5.6-sol +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [] +allowedTools: [Read, Edit, Glob, Grep, Bash, load_skill_menu, install_skill] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Leave your service with a PostHog SDK that can record metrics. When your +task input names a `package`, that package is your whole world — its +manifest, its init site, its `service_name`; do not touch sibling packages. +First call +`load_skill_menu` with `category: "metrics"` and `install_skill` for the +variant matching the project's platform — the menu is the source of truth, +one variant per platform, and a full-stack app takes the server variant +because metrics measure service work. The installed skill carries the +platform's install and init specifics. Then three checks, in order: + +1. **Installed?** Look for the SDK in the dependency manifest. Missing → + install it with the project's own package manager and let it resolve the + version — never invent one. +2. **New enough?** `posthog.metrics` ships in recent SDK releases only — the + skill states the version floor for this platform. Below it → bump with the + package manager's upgrade command. At or above → leave it alone and say so + in your handoff. +3. **Initialized for metrics?** Find where the client is constructed. Add the + `metrics` config (a service name) to that existing client, as the skill + shows. No client anywhere → initialize one, following the skill. Never + construct a second client beside a working one, and never touch identify + calls, event capture, or other init options. + +## How you know you succeeded + +The manifest holds the SDK at a metrics-capable version and exactly one client +init carries the metrics config — or your handoff plainly says why the +environment stopped you. Name the skill variant you installed, the manifest, the version, and the +init site in your handoff, so instrumentation installs the same skill and +knows what to import and where. diff --git a/fixtures/context-mill/agents/replay-vision/enable-replay.md b/fixtures/context-mill/agents/replay-vision/enable-replay.md new file mode 100644 index 000000000..666c64e67 --- /dev/null +++ b/fixtures/context-mill/agents/replay-vision/enable-replay.md @@ -0,0 +1,46 @@ +--- +type: enable-replay +flow: replay-vision +label: Make session replay record +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [replay-vision-enable-replay] +allowedTools: [Read, Edit, Glob, Grep, posthog_exec] +disallowedTools: [Write, Bash, enqueue_task] +dependsOn: [install, init] +--- + +## Goal + +Make session replay actually record. Recording has a server half and a client +half, and either one can silently cancel the other. + +Server half: call `products-enable` (via `exec`: `info products-enable`, then +`call products-enable {"products": ["session_replay"]}`). It is idempotent and +server-owned; `"enabled"` and `"already_enabled"` are both success. + +- **Tool missing on this deploy**: don't fail the task — record a follow-up in + your handoff telling the user to turn on "Record user sessions" under + Settings → Session replay, and finish. +- **Permission rejection**: record a follow-up to enable it from a + project-admin account, and finish — scanners created later sit idle until + recording is on, then start working with no re-setup. + +Client half, web apps only: check the `posthog.init(...)` options. +`disable_session_recording: true` cancels the server flip — remove it (or set +it `false`). If nothing overrides recording, leave the init alone. This is the +only code edit this task may make: never restructure the init, never add new +instrumentation. If you can't confidently locate or edit the init, record a +follow-up instead of guessing. + +Pure backend or mobile app with no web surface: nothing records browser +sessions here. Say so in your handoff and finish — scanner tasks read your +handoff and skip what doesn't apply. + +## How you know you succeeded + +Recording is on server-side and nothing in the client init cancels it — or +your handoff names exactly which half needs the user and why. Later tasks +trust your handoff, so state plainly whether recordings will flow. diff --git a/fixtures/context-mill/agents/replay-vision/init.md b/fixtures/context-mill/agents/replay-vision/init.md new file mode 100644 index 000000000..b4c614142 --- /dev/null +++ b/fixtures/context-mill/agents/replay-vision/init.md @@ -0,0 +1,33 @@ +--- +type: init +flow: replay-vision +label: Set up PostHog initialization +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [integration-v2-init, posthog-best-practices] +allowedTools: [Read, Write, Edit, Glob, Grep] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Make sure PostHog is initialized. If the project already has a working +`posthog.init(...)` (or the framework's equivalent) with its env keys wired, +leave it alone and say so in your handoff. If it doesn't, create it following +your skill — it owns the how: the framework's init point, the env-var wiring +through the wizard tools, and `.env.example`. + +You only exist in this flow because the user asked for Replay vision on a +repo without PostHog. Initialize the SDK so recordings can flow and stop — +no instrumentation, no extras. Don't touch session-recording options either +way; the enable-replay task after you owns those. + +## How you know you succeeded + +An init point exists with the PostHog env keys present — whether it already +did or you just created it — keys in the env file, never hardcoded. Your +handoff names the files involved and how the client is constructed, so the +enable-replay task can find the init options without re-discovering them. diff --git a/fixtures/context-mill/agents/replay-vision/install.md b/fixtures/context-mill/agents/replay-vision/install.md new file mode 100644 index 000000000..7cbd0230e --- /dev/null +++ b/fixtures/context-mill/agents/replay-vision/install.md @@ -0,0 +1,30 @@ +--- +type: install +flow: replay-vision +label: Add the PostHog SDK to the manifest +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-haiku-4-5 +skills: [integration-v2-install] +allowedTools: [Read, Edit, Glob, Grep, Bash] +disallowedTools: [enqueue_task] +dependsOn: [] +--- + +## Goal + +Make sure the PostHog SDK is in the manifest. If it's already installed, +leave it alone and say so in your handoff. If it isn't, install it following +your skill — it owns the how: the package manager rules, the version rules, +what counts as an environment failure, and the fallback. + +You only exist in this flow because the user asked for Replay vision on a +repo without PostHog. Install the client library (plus the server library if +the app sends events server-side) and stop — no instrumentation, no extras. + +## How you know you succeeded + +The SDK is declared in the manifest at a real version — whether it already +was or you just installed it — or your handoff plainly says why the +environment stopped you. Your handoff names the manifest and the package, so +later steps import it under the name they will actually get. diff --git a/fixtures/context-mill/agents/replay-vision/report.md b/fixtures/context-mill/agents/replay-vision/report.md new file mode 100644 index 000000000..010a9a2ab --- /dev/null +++ b/fixtures/context-mill/agents/replay-vision/report.md @@ -0,0 +1,38 @@ +--- +type: report +flow: replay-vision +label: Report and hand off +sink: true +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [] +allowedTools: [Read, Glob, Grep, Write, posthog_exec] +disallowedTools: [enqueue_task] +dependsOn: [scanner-broken-experiences, scanner-user-frustration, scanner-session-summaries] +--- + +## Goal + +Tell the user what Replay vision is now doing for them, from the handoffs of +every task in the run. Briefly and concretely: + +- What is now recording (or the follow-up needed to make it record). +- Each scanner created or updated: its name, what it watches, its query + scope, and its estimated monthly credit spend. +- Anything skipped or deferred, with the reason — a skipped scanner on a + backend-only project is an outcome, not an apology. +- Where results appear: the Replay vision page in PostHog, with the first + observations arriving as new recordings complete. + +If the run also installed and initialized the SDK, say so — the user started +this command without PostHog and now has it. + +Write the report to `./posthog-replay-vision-report.md` (the wizard shows this +file at the end of the run), then publish the same content as your handoff. + +## How you know you succeeded + +A user who reads only your report knows what watches their product, what it +costs, what still needs them, and where to look first. diff --git a/fixtures/context-mill/agents/replay-vision/scanner-broken-experiences.md b/fixtures/context-mill/agents/replay-vision/scanner-broken-experiences.md new file mode 100644 index 000000000..da3dbb7ff --- /dev/null +++ b/fixtures/context-mill/agents/replay-vision/scanner-broken-experiences.md @@ -0,0 +1,40 @@ +--- +type: scanner-broken-experiences +flow: replay-vision +label: Breakage scanner +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [replay-vision-scanners-core, replay-vision-scanner-broken-experiences] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [Write, Edit, Bash, enqueue_task] +dependsOn: [enable-replay] +--- + +## Goal + +Create the breakage monitor: the product visibly breaking, on the flow where +breaking costs the most — named and written for this product. The brief, the +locked scaffold, and the create/re-run mechanics are in your skills — you +fill the blanks from the repo: + +- **`name`** — what it watches, in this product's own words. +- **`query`** — this product's key completion flow plus its immediate + predecessors. Checkout, signup, booking, publish — whatever this product's + "done" is. Read router files and page/route directories to find the real + paths; never guess at `/checkout` if this app calls it `/booking`. +- **`{{WATCH_FOR}}`** — the concrete failure modes of this flow, on screen, + in the product's vocabulary. +- **`{{PRODUCT_CONTEXT}}`** — one plain factual sentence. + +If there is no identifiable completion flow, don't invent one — fall back to +the handful of highest-traffic paths and record in your handoff that you +couldn't identify a completion flow. If the enable-replay handoff says this +product has no web surface, skip creation entirely and say why — that is a +correct outcome. + +## How you know you succeeded + +The scanner exists in PostHog scoped to this product's real completion flow, +or your handoff says exactly why it was skipped or deferred. diff --git a/fixtures/context-mill/agents/replay-vision/scanner-session-summaries.md b/fixtures/context-mill/agents/replay-vision/scanner-session-summaries.md new file mode 100644 index 000000000..529c81738 --- /dev/null +++ b/fixtures/context-mill/agents/replay-vision/scanner-session-summaries.md @@ -0,0 +1,37 @@ +--- +type: scanner-session-summaries +flow: replay-vision +label: Session summaries scanner +model_pi: openai/gpt-5.6-terra +effort_pi: low +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [replay-vision-scanners-core, replay-vision-scanner-session-summaries] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [Write, Edit, Bash, enqueue_task] +dependsOn: [enable-replay] +--- + +## Goal + +Create the summary scanner: a rolling sample of plain-language session +summaries in this product's own vocabulary, so the user sees the breadth of +what scanners produce. The brief, the locked scaffold, and the create/re-run +mechanics are in your skills — you fill the blanks from the repo: + +- **`name`** — in this product's own words. +- **`{{VOCABULARY}}`** — the nouns and verbs this product's UI uses for its + key flows, so summaries read like the product. +- **`{{PRODUCT_CONTEXT}}`** — one plain factual sentence. + +It samples every recording with no query scope, kept cheap by a low sampling +rate — **never raise the sampling rate during setup**. + +If the enable-replay handoff says this product has no web surface and no +recorded web sessions at all, skip creation and say why — that is a correct +outcome. + +## How you know you succeeded + +The scanner exists in PostHog at the brief's sampling rate, or your +handoff says exactly why it was skipped or deferred. diff --git a/fixtures/context-mill/agents/replay-vision/scanner-user-frustration.md b/fixtures/context-mill/agents/replay-vision/scanner-user-frustration.md new file mode 100644 index 000000000..99cc739ee --- /dev/null +++ b/fixtures/context-mill/agents/replay-vision/scanner-user-frustration.md @@ -0,0 +1,35 @@ +--- +type: scanner-user-frustration +flow: replay-vision +label: User frustration scanner +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: medium +skills: [replay-vision-scanners-core, replay-vision-scanner-user-frustration] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [Write, Edit, Bash, enqueue_task] +dependsOn: [enable-replay] +--- + +## Goal + +Create the frustration monitor: the user getting stuck, named and written +for this product. It is gated on `$rageclick` — cheap and high-precision, +because here the gating event *is* the friction. The brief, the locked +scaffold, and the create/re-run mechanics are in your skills — you fill the +blanks from the repo: + +- **`name`** — what it watches, in this product's own words. +- **`{{STUCK_MOMENTS}}`** — where a user of this product realistically gets + stuck, on screen, in the product's vocabulary. +- **`{{PRODUCT_CONTEXT}}`** — one plain factual sentence. + +If the enable-replay handoff says this product has no web surface and no +recorded web sessions at all, skip creation and say why — that is a correct +outcome. + +## How you know you succeeded + +The scanner exists in PostHog gated on `$rageclick` alone, or your handoff +says exactly why it was skipped or deferred. diff --git a/fixtures/context-mill/agents/replay-vision/setup-replay-vision.md b/fixtures/context-mill/agents/replay-vision/setup-replay-vision.md new file mode 100644 index 000000000..2719c1d9d --- /dev/null +++ b/fixtures/context-mill/agents/replay-vision/setup-replay-vision.md @@ -0,0 +1,53 @@ +--- +type: setup-replay-vision +flow: replay-vision +seed: true +model_pi: openai/gpt-5.6-terra +effort_pi: medium +model_sdk: claude-sonnet-5 +effort_sdk: high +skills: [] +allowedTools: [Read, Glob, Grep, posthog_exec] +disallowedTools: [Write, Edit, Bash, complete_task] +dependsOn: [] +--- + +## Goal + +Plan a Replay vision setup and seed the task queue. A scanner is an LLM that +watches one session recording at a time and writes an observation — a score, a +tag, or a summary — and every observation lands as a queryable PostHog event. +Scanners only see what session replay records, so the plan has two halves: +make sure recordings flow, then create scanners tailored to this product. + +First, establish one fact from the repo: **is PostHog already integrated?** +Look for `posthog-js` or a server SDK in the dependency manifests, or a +`posthog.init(...)` / snippet in the source. Check the project state for +existing events if the repo is ambiguous. + +Then seed one of two graphs: + +**PostHog is already integrated** — the common case: + +- `enable-replay`, with no dependencies. +- The three scanner tasks — `scanner-broken-experiences`, + `scanner-user-frustration`, `scanner-session-summaries` — each after + `enable-replay`, independent of one another, so they run in parallel. +- `report`, after all three scanner tasks. It writes the handoff last, so it + describes what actually shipped. + +**PostHog is not integrated** — do not stop, integrate: + +- `install` and `init`, independent of each other. +- `enable-replay`, after `install` and `init`. +- The three scanner tasks and `report`, wired exactly as above. + +Never plan an identify, capture, or dashboard task — this run sets up Replay +vision, not the full integration. The minimal SDK footprint that `install` and +`init` leave behind is enough for recordings to flow. + +## How you know you succeeded + +Every task in the chosen graph is queued with that dependency shape, the +report last, and the first task runnable. Keep labels short — the action in a +few words. diff --git a/fixtures/context-mill/skill-menu.json b/fixtures/context-mill/skill-menu.json new file mode 100644 index 000000000..256adf1aa --- /dev/null +++ b/fixtures/context-mill/skill-menu.json @@ -0,0 +1,9831 @@ +{ + "version": "1.0", + "buildVersion": "dev", + "categories": { + "ai-observability": [ + { + "id": "ai-observability-openai-python", + "name": "PostHog AI Observability integration for OpenAI (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-openai-python.zip", + "framework": "openai", + "default": true, + "title": "OpenAI (Python)", + "description": "PostHog AI Observability integration for OpenAI (Python)", + "tags": [ + "ai_observability", + "openai", + "python", + "framework:openai", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-openai-node", + "name": "PostHog AI Observability integration for OpenAI (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-openai-node.zip", + "framework": "openai", + "title": "OpenAI (Node)", + "description": "PostHog AI Observability integration for OpenAI (Node)", + "tags": [ + "ai_observability", + "openai", + "javascript_node", + "framework:openai", + "ai-observability" + ] + }, + { + "id": "ai-observability-anthropic-python", + "name": "PostHog AI Observability integration for Anthropic (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-anthropic-python.zip", + "framework": "anthropic", + "default": true, + "title": "Anthropic (Python)", + "description": "PostHog AI Observability integration for Anthropic (Python)", + "tags": [ + "ai_observability", + "anthropic", + "python", + "framework:anthropic", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-anthropic-node", + "name": "PostHog AI Observability integration for Anthropic (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-anthropic-node.zip", + "framework": "anthropic", + "title": "Anthropic (Node)", + "description": "PostHog AI Observability integration for Anthropic (Node)", + "tags": [ + "ai_observability", + "anthropic", + "javascript_node", + "framework:anthropic", + "ai-observability" + ] + }, + { + "id": "ai-observability-langchain-python", + "name": "PostHog AI Observability integration for LangChain (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-langchain-python.zip", + "framework": "langchain", + "default": true, + "title": "LangChain (Python)", + "description": "PostHog AI Observability integration for LangChain (Python)", + "tags": [ + "ai_observability", + "langchain", + "python", + "framework:langchain", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-langchain-node", + "name": "PostHog AI Observability integration for LangChain (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-langchain-node.zip", + "framework": "langchain", + "title": "LangChain (Node)", + "description": "PostHog AI Observability integration for LangChain (Node)", + "tags": [ + "ai_observability", + "langchain", + "javascript_node", + "framework:langchain", + "ai-observability" + ] + }, + { + "id": "ai-observability-vercel-ai", + "name": "PostHog AI Observability integration for Vercel AI SDK", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-vercel-ai.zip", + "framework": "vercel-ai", + "title": "Vercel AI SDK", + "description": "PostHog AI Observability integration for Vercel AI SDK", + "tags": [ + "ai_observability", + "vercel-ai", + "javascript_node", + "framework:vercel-ai", + "ai-observability" + ] + }, + { + "id": "ai-observability-google-python", + "name": "PostHog AI Observability integration for Google Gemini (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-google-python.zip", + "framework": "google-gemini", + "default": true, + "title": "Google Gemini (Python)", + "description": "PostHog AI Observability integration for Google Gemini (Python)", + "tags": [ + "ai_observability", + "google-gemini", + "python", + "framework:google-gemini", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-google-node", + "name": "PostHog AI Observability integration for Google Gemini (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-google-node.zip", + "framework": "google-gemini", + "title": "Google Gemini (Node)", + "description": "PostHog AI Observability integration for Google Gemini (Node)", + "tags": [ + "ai_observability", + "google-gemini", + "javascript_node", + "framework:google-gemini", + "ai-observability" + ] + }, + { + "id": "ai-observability-manual-capture", + "name": "PostHog AI Observability using explicit $ai_generation capture calls (no auto-instrumentation)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-manual-capture.zip", + "framework": "manual-capture", + "title": "Manual capture", + "description": "PostHog AI Observability using explicit $ai_generation capture calls (no auto-instrumentation)", + "tags": [ + "ai_observability", + "manual-capture", + "framework:manual-capture", + "ai-observability" + ] + }, + { + "id": "ai-observability-azure-openai-python", + "name": "PostHog AI Observability integration for Azure OpenAI (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-azure-openai-python.zip", + "framework": "azure-openai", + "default": true, + "title": "Azure OpenAI (Python)", + "description": "PostHog AI Observability integration for Azure OpenAI (Python)", + "tags": [ + "ai_observability", + "azure-openai", + "python", + "framework:azure-openai", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-azure-openai-node", + "name": "PostHog AI Observability integration for Azure OpenAI (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-azure-openai-node.zip", + "framework": "azure-openai", + "title": "Azure OpenAI (Node)", + "description": "PostHog AI Observability integration for Azure OpenAI (Node)", + "tags": [ + "ai_observability", + "azure-openai", + "javascript_node", + "framework:azure-openai", + "ai-observability" + ] + }, + { + "id": "ai-observability-aws-bedrock-python", + "name": "PostHog AI Observability integration for AWS Bedrock (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-aws-bedrock-python.zip", + "framework": "aws-bedrock", + "default": true, + "title": "AWS Bedrock (Python)", + "description": "PostHog AI Observability integration for AWS Bedrock (Python)", + "tags": [ + "ai_observability", + "aws-bedrock", + "python", + "framework:aws-bedrock", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-aws-bedrock-node", + "name": "PostHog AI Observability integration for AWS Bedrock (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-aws-bedrock-node.zip", + "framework": "aws-bedrock", + "title": "AWS Bedrock (Node)", + "description": "PostHog AI Observability integration for AWS Bedrock (Node)", + "tags": [ + "ai_observability", + "aws-bedrock", + "javascript_node", + "framework:aws-bedrock", + "ai-observability" + ] + }, + { + "id": "ai-observability-cerebras-python", + "name": "PostHog AI Observability integration for Cerebras (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-cerebras-python.zip", + "framework": "cerebras", + "default": true, + "title": "Cerebras (Python)", + "description": "PostHog AI Observability integration for Cerebras (Python)", + "tags": [ + "ai_observability", + "cerebras", + "python", + "framework:cerebras", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-cerebras-node", + "name": "PostHog AI Observability integration for Cerebras (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-cerebras-node.zip", + "framework": "cerebras", + "title": "Cerebras (Node)", + "description": "PostHog AI Observability integration for Cerebras (Node)", + "tags": [ + "ai_observability", + "cerebras", + "javascript_node", + "framework:cerebras", + "ai-observability" + ] + }, + { + "id": "ai-observability-cohere-python", + "name": "PostHog AI Observability integration for Cohere (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-cohere-python.zip", + "framework": "cohere", + "default": true, + "title": "Cohere (Python)", + "description": "PostHog AI Observability integration for Cohere (Python)", + "tags": [ + "ai_observability", + "cohere", + "python", + "framework:cohere", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-cohere-node", + "name": "PostHog AI Observability integration for Cohere (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-cohere-node.zip", + "framework": "cohere", + "title": "Cohere (Node)", + "description": "PostHog AI Observability integration for Cohere (Node)", + "tags": [ + "ai_observability", + "cohere", + "javascript_node", + "framework:cohere", + "ai-observability" + ] + }, + { + "id": "ai-observability-deepseek-python", + "name": "PostHog AI Observability integration for DeepSeek (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-deepseek-python.zip", + "framework": "deepseek", + "default": true, + "title": "DeepSeek (Python)", + "description": "PostHog AI Observability integration for DeepSeek (Python)", + "tags": [ + "ai_observability", + "deepseek", + "python", + "framework:deepseek", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-deepseek-node", + "name": "PostHog AI Observability integration for DeepSeek (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-deepseek-node.zip", + "framework": "deepseek", + "title": "DeepSeek (Node)", + "description": "PostHog AI Observability integration for DeepSeek (Node)", + "tags": [ + "ai_observability", + "deepseek", + "javascript_node", + "framework:deepseek", + "ai-observability" + ] + }, + { + "id": "ai-observability-fireworks-ai-python", + "name": "PostHog AI Observability integration for Fireworks AI (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-fireworks-ai-python.zip", + "framework": "fireworks-ai", + "default": true, + "title": "Fireworks AI (Python)", + "description": "PostHog AI Observability integration for Fireworks AI (Python)", + "tags": [ + "ai_observability", + "fireworks-ai", + "python", + "framework:fireworks-ai", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-fireworks-ai-node", + "name": "PostHog AI Observability integration for Fireworks AI (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-fireworks-ai-node.zip", + "framework": "fireworks-ai", + "title": "Fireworks AI (Node)", + "description": "PostHog AI Observability integration for Fireworks AI (Node)", + "tags": [ + "ai_observability", + "fireworks-ai", + "javascript_node", + "framework:fireworks-ai", + "ai-observability" + ] + }, + { + "id": "ai-observability-groq-python", + "name": "PostHog AI Observability integration for Groq (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-groq-python.zip", + "framework": "groq", + "default": true, + "title": "Groq (Python)", + "description": "PostHog AI Observability integration for Groq (Python)", + "tags": [ + "ai_observability", + "groq", + "python", + "framework:groq", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-groq-node", + "name": "PostHog AI Observability integration for Groq (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-groq-node.zip", + "framework": "groq", + "title": "Groq (Node)", + "description": "PostHog AI Observability integration for Groq (Node)", + "tags": [ + "ai_observability", + "groq", + "javascript_node", + "framework:groq", + "ai-observability" + ] + }, + { + "id": "ai-observability-hugging-face-python", + "name": "PostHog AI Observability integration for Hugging Face (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-hugging-face-python.zip", + "framework": "hugging-face", + "default": true, + "title": "Hugging Face (Python)", + "description": "PostHog AI Observability integration for Hugging Face (Python)", + "tags": [ + "ai_observability", + "hugging-face", + "python", + "framework:hugging-face", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-hugging-face-node", + "name": "PostHog AI Observability integration for Hugging Face (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-hugging-face-node.zip", + "framework": "hugging-face", + "title": "Hugging Face (Node)", + "description": "PostHog AI Observability integration for Hugging Face (Node)", + "tags": [ + "ai_observability", + "hugging-face", + "javascript_node", + "framework:hugging-face", + "ai-observability" + ] + }, + { + "id": "ai-observability-mistral-python", + "name": "PostHog AI Observability integration for Mistral (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-mistral-python.zip", + "framework": "mistral", + "default": true, + "title": "Mistral (Python)", + "description": "PostHog AI Observability integration for Mistral (Python)", + "tags": [ + "ai_observability", + "mistral", + "python", + "framework:mistral", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-mistral-node", + "name": "PostHog AI Observability integration for Mistral (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-mistral-node.zip", + "framework": "mistral", + "title": "Mistral (Node)", + "description": "PostHog AI Observability integration for Mistral (Node)", + "tags": [ + "ai_observability", + "mistral", + "javascript_node", + "framework:mistral", + "ai-observability" + ] + }, + { + "id": "ai-observability-ollama-python", + "name": "PostHog AI Observability integration for Ollama (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-ollama-python.zip", + "framework": "ollama", + "default": true, + "title": "Ollama (Python)", + "description": "PostHog AI Observability integration for Ollama (Python)", + "tags": [ + "ai_observability", + "ollama", + "python", + "framework:ollama", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-ollama-node", + "name": "PostHog AI Observability integration for Ollama (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-ollama-node.zip", + "framework": "ollama", + "title": "Ollama (Node)", + "description": "PostHog AI Observability integration for Ollama (Node)", + "tags": [ + "ai_observability", + "ollama", + "javascript_node", + "framework:ollama", + "ai-observability" + ] + }, + { + "id": "ai-observability-perplexity-python", + "name": "PostHog AI Observability integration for Perplexity (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-perplexity-python.zip", + "framework": "perplexity", + "default": true, + "title": "Perplexity (Python)", + "description": "PostHog AI Observability integration for Perplexity (Python)", + "tags": [ + "ai_observability", + "perplexity", + "python", + "framework:perplexity", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-perplexity-node", + "name": "PostHog AI Observability integration for Perplexity (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-perplexity-node.zip", + "framework": "perplexity", + "title": "Perplexity (Node)", + "description": "PostHog AI Observability integration for Perplexity (Node)", + "tags": [ + "ai_observability", + "perplexity", + "javascript_node", + "framework:perplexity", + "ai-observability" + ] + }, + { + "id": "ai-observability-together-ai-python", + "name": "PostHog AI Observability integration for Together AI (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-together-ai-python.zip", + "framework": "together-ai", + "default": true, + "title": "Together AI (Python)", + "description": "PostHog AI Observability integration for Together AI (Python)", + "tags": [ + "ai_observability", + "together-ai", + "python", + "framework:together-ai", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-together-ai-node", + "name": "PostHog AI Observability integration for Together AI (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-together-ai-node.zip", + "framework": "together-ai", + "title": "Together AI (Node)", + "description": "PostHog AI Observability integration for Together AI (Node)", + "tags": [ + "ai_observability", + "together-ai", + "javascript_node", + "framework:together-ai", + "ai-observability" + ] + }, + { + "id": "ai-observability-xai-python", + "name": "PostHog AI Observability integration for xAI (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-xai-python.zip", + "framework": "xai", + "default": true, + "title": "xAI (Python)", + "description": "PostHog AI Observability integration for xAI (Python)", + "tags": [ + "ai_observability", + "xai", + "python", + "framework:xai", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-xai-node", + "name": "PostHog AI Observability integration for xAI (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-xai-node.zip", + "framework": "xai", + "title": "xAI (Node)", + "description": "PostHog AI Observability integration for xAI (Node)", + "tags": [ + "ai_observability", + "xai", + "javascript_node", + "framework:xai", + "ai-observability" + ] + }, + { + "id": "ai-observability-autogen", + "name": "PostHog AI Observability for AutoGen (multi-agent framework, Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-autogen.zip", + "framework": "autogen", + "title": "AutoGen", + "description": "PostHog AI Observability for AutoGen (multi-agent framework, Python)", + "tags": [ + "ai_observability", + "autogen", + "python", + "framework:autogen", + "ai-observability" + ] + }, + { + "id": "ai-observability-claude-agent-sdk", + "name": "PostHog AI Observability for Anthropic's Claude Agent SDK (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-claude-agent-sdk.zip", + "framework": "claude-agent-sdk", + "title": "Claude Agent SDK", + "description": "PostHog AI Observability for Anthropic's Claude Agent SDK (Python)", + "tags": [ + "ai_observability", + "claude-agent-sdk", + "python", + "framework:claude-agent-sdk", + "ai-observability" + ] + }, + { + "id": "ai-observability-crewai", + "name": "PostHog AI Observability for CrewAI (multi-agent orchestration, Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-crewai.zip", + "framework": "crewai", + "title": "CrewAI", + "description": "PostHog AI Observability for CrewAI (multi-agent orchestration, Python)", + "tags": [ + "ai_observability", + "crewai", + "python", + "framework:crewai", + "ai-observability" + ] + }, + { + "id": "ai-observability-dspy", + "name": "PostHog AI Observability for DSPy (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-dspy.zip", + "framework": "dspy", + "title": "DSPy", + "description": "PostHog AI Observability for DSPy (Python)", + "tags": [ + "ai_observability", + "dspy", + "python", + "framework:dspy", + "ai-observability" + ] + }, + { + "id": "ai-observability-llamaindex", + "name": "PostHog AI Observability for LlamaIndex (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-llamaindex.zip", + "framework": "llamaindex", + "title": "LlamaIndex", + "description": "PostHog AI Observability for LlamaIndex (Python)", + "tags": [ + "ai_observability", + "llamaindex", + "python", + "framework:llamaindex", + "ai-observability" + ] + }, + { + "id": "ai-observability-mirascope", + "name": "PostHog AI Observability for Mirascope (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-mirascope.zip", + "framework": "mirascope", + "title": "Mirascope", + "description": "PostHog AI Observability for Mirascope (Python)", + "tags": [ + "ai_observability", + "mirascope", + "python", + "framework:mirascope", + "ai-observability" + ] + }, + { + "id": "ai-observability-openai-agents", + "name": "PostHog AI Observability for the OpenAI Agents SDK (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-openai-agents.zip", + "framework": "openai-agents", + "title": "OpenAI Agents SDK", + "description": "PostHog AI Observability for the OpenAI Agents SDK (Python)", + "tags": [ + "ai_observability", + "openai-agents", + "python", + "framework:openai-agents", + "ai-observability" + ] + }, + { + "id": "ai-observability-pydantic-ai", + "name": "PostHog AI Observability for Pydantic AI (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-pydantic-ai.zip", + "framework": "pydantic-ai", + "title": "Pydantic AI", + "description": "PostHog AI Observability for Pydantic AI (Python)", + "tags": [ + "ai_observability", + "pydantic-ai", + "python", + "framework:pydantic-ai", + "ai-observability" + ] + }, + { + "id": "ai-observability-semantic-kernel", + "name": "PostHog AI Observability for Microsoft Semantic Kernel (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-semantic-kernel.zip", + "framework": "semantic-kernel", + "title": "Semantic Kernel", + "description": "PostHog AI Observability for Microsoft Semantic Kernel (Python)", + "tags": [ + "ai_observability", + "semantic-kernel", + "python", + "framework:semantic-kernel", + "ai-observability" + ] + }, + { + "id": "ai-observability-smolagents", + "name": "PostHog AI Observability for smolagents (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-smolagents.zip", + "framework": "smolagents", + "title": "smolagents", + "description": "PostHog AI Observability for smolagents (Python)", + "tags": [ + "ai_observability", + "smolagents", + "python", + "framework:smolagents", + "ai-observability" + ] + }, + { + "id": "ai-observability-convex", + "name": "PostHog AI Observability for Convex (Node, Vercel AI SDK inside)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-convex.zip", + "framework": "convex", + "title": "Convex", + "description": "PostHog AI Observability for Convex (Node, Vercel AI SDK inside)", + "tags": [ + "ai_observability", + "convex", + "javascript_node", + "framework:convex", + "ai-observability" + ] + }, + { + "id": "ai-observability-mastra", + "name": "PostHog AI Observability for Mastra (agent framework, Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-mastra.zip", + "framework": "mastra", + "title": "Mastra", + "description": "PostHog AI Observability for Mastra (agent framework, Node)", + "tags": [ + "ai_observability", + "mastra", + "javascript_node", + "framework:mastra", + "ai-observability" + ] + }, + { + "id": "ai-observability-google-adk", + "name": "PostHog AI Observability for the Google Agent Development Kit (agent framework, Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-google-adk.zip", + "framework": "google-adk", + "title": "Google ADK", + "description": "PostHog AI Observability for the Google Agent Development Kit (agent framework, Node)", + "tags": [ + "ai_observability", + "google-adk", + "javascript_node", + "framework:google-adk", + "ai-observability" + ] + }, + { + "id": "ai-observability-instructor-python", + "name": "PostHog AI Observability integration for Instructor (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-instructor-python.zip", + "framework": "instructor", + "default": true, + "title": "Instructor (Python)", + "description": "PostHog AI Observability integration for Instructor (Python)", + "tags": [ + "ai_observability", + "instructor", + "python", + "framework:instructor", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-instructor-node", + "name": "PostHog AI Observability integration for Instructor (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-instructor-node.zip", + "framework": "instructor", + "title": "Instructor (Node)", + "description": "PostHog AI Observability integration for Instructor (Node)", + "tags": [ + "ai_observability", + "instructor", + "javascript_node", + "framework:instructor", + "ai-observability" + ] + }, + { + "id": "ai-observability-langgraph-python", + "name": "PostHog AI Observability integration for LangGraph (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-langgraph-python.zip", + "framework": "langgraph", + "default": true, + "title": "LangGraph (Python)", + "description": "PostHog AI Observability integration for LangGraph (Python)", + "tags": [ + "ai_observability", + "langgraph", + "python", + "framework:langgraph", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-langgraph-node", + "name": "PostHog AI Observability integration for LangGraph (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-langgraph-node.zip", + "framework": "langgraph", + "title": "LangGraph (Node)", + "description": "PostHog AI Observability integration for LangGraph (Node)", + "tags": [ + "ai_observability", + "langgraph", + "javascript_node", + "framework:langgraph", + "ai-observability" + ] + }, + { + "id": "ai-observability-cloudflare-ai-gateway-python", + "name": "PostHog AI Observability integration for Cloudflare AI Gateway (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-cloudflare-ai-gateway-python.zip", + "framework": "cloudflare-ai-gateway", + "default": true, + "title": "Cloudflare AI Gateway (Python)", + "description": "PostHog AI Observability integration for Cloudflare AI Gateway (Python)", + "tags": [ + "ai_observability", + "cloudflare-ai-gateway", + "python", + "framework:cloudflare-ai-gateway", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-cloudflare-ai-gateway-node", + "name": "PostHog AI Observability integration for Cloudflare AI Gateway (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-cloudflare-ai-gateway-node.zip", + "framework": "cloudflare-ai-gateway", + "title": "Cloudflare AI Gateway (Node)", + "description": "PostHog AI Observability integration for Cloudflare AI Gateway (Node)", + "tags": [ + "ai_observability", + "cloudflare-ai-gateway", + "javascript_node", + "framework:cloudflare-ai-gateway", + "ai-observability" + ] + }, + { + "id": "ai-observability-helicone-python", + "name": "PostHog AI Observability integration for Helicone (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-helicone-python.zip", + "framework": "helicone", + "default": true, + "title": "Helicone (Python)", + "description": "PostHog AI Observability integration for Helicone (Python)", + "tags": [ + "ai_observability", + "helicone", + "python", + "framework:helicone", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-helicone-node", + "name": "PostHog AI Observability integration for Helicone (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-helicone-node.zip", + "framework": "helicone", + "title": "Helicone (Node)", + "description": "PostHog AI Observability integration for Helicone (Node)", + "tags": [ + "ai_observability", + "helicone", + "javascript_node", + "framework:helicone", + "ai-observability" + ] + }, + { + "id": "ai-observability-openrouter-python", + "name": "PostHog AI Observability integration for OpenRouter (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-openrouter-python.zip", + "framework": "openrouter", + "default": true, + "title": "OpenRouter (Python)", + "description": "PostHog AI Observability integration for OpenRouter (Python)", + "tags": [ + "ai_observability", + "openrouter", + "python", + "framework:openrouter", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-openrouter-node", + "name": "PostHog AI Observability integration for OpenRouter (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-openrouter-node.zip", + "framework": "openrouter", + "title": "OpenRouter (Node)", + "description": "PostHog AI Observability integration for OpenRouter (Node)", + "tags": [ + "ai_observability", + "openrouter", + "javascript_node", + "framework:openrouter", + "ai-observability" + ] + }, + { + "id": "ai-observability-portkey-python", + "name": "PostHog AI Observability integration for Portkey (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-portkey-python.zip", + "framework": "portkey", + "default": true, + "title": "Portkey (Python)", + "description": "PostHog AI Observability integration for Portkey (Python)", + "tags": [ + "ai_observability", + "portkey", + "python", + "framework:portkey", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-portkey-node", + "name": "PostHog AI Observability integration for Portkey (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-portkey-node.zip", + "framework": "portkey", + "title": "Portkey (Node)", + "description": "PostHog AI Observability integration for Portkey (Node)", + "tags": [ + "ai_observability", + "portkey", + "javascript_node", + "framework:portkey", + "ai-observability" + ] + }, + { + "id": "ai-observability-dedalus-python", + "name": "PostHog AI Observability integration for Dedalus Labs (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-dedalus-python.zip", + "framework": "dedalus", + "default": true, + "title": "Dedalus Labs (Python)", + "description": "PostHog AI Observability integration for Dedalus Labs (Python)", + "tags": [ + "ai_observability", + "dedalus", + "python", + "framework:dedalus", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-dedalus-node", + "name": "PostHog AI Observability integration for Dedalus Labs (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-dedalus-node.zip", + "framework": "dedalus", + "title": "Dedalus Labs (Node)", + "description": "PostHog AI Observability integration for Dedalus Labs (Node)", + "tags": [ + "ai_observability", + "dedalus", + "javascript_node", + "framework:dedalus", + "ai-observability" + ] + }, + { + "id": "ai-observability-litellm", + "name": "PostHog AI Observability for LiteLLM (unified LLM SDK / proxy, Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-litellm.zip", + "framework": "litellm", + "title": "LiteLLM", + "description": "PostHog AI Observability for LiteLLM (unified LLM SDK / proxy, Python)", + "tags": [ + "ai_observability", + "litellm", + "python", + "framework:litellm", + "ai-observability" + ] + }, + { + "id": "ai-observability-opentelemetry-python", + "name": "PostHog AI Observability integration for OpenTelemetry (Python)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-opentelemetry-python.zip", + "framework": "opentelemetry", + "default": true, + "title": "OpenTelemetry (Python)", + "description": "PostHog AI Observability integration for OpenTelemetry (Python)", + "tags": [ + "ai_observability", + "opentelemetry", + "python", + "framework:opentelemetry", + "ai-observability", + "default" + ] + }, + { + "id": "ai-observability-opentelemetry-node", + "name": "PostHog AI Observability integration for OpenTelemetry (Node)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-opentelemetry-node.zip", + "framework": "opentelemetry", + "title": "OpenTelemetry (Node)", + "description": "PostHog AI Observability integration for OpenTelemetry (Node)", + "tags": [ + "ai_observability", + "opentelemetry", + "javascript_node", + "framework:opentelemetry", + "ai-observability" + ] + }, + { + "id": "ai-observability-opentelemetry-go", + "name": "PostHog AI Observability integration for OpenTelemetry (Go)", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-opentelemetry-go.zip", + "framework": "opentelemetry", + "title": "OpenTelemetry (Go)", + "description": "PostHog AI Observability integration for OpenTelemetry (Go)", + "tags": [ + "ai_observability", + "opentelemetry", + "go", + "framework:opentelemetry", + "ai-observability" + ] + }, + { + "id": "ai-observability-claude-code", + "name": "PostHog AI Observability for Anthropic Claude Code sessions via the @posthog/ai-plugin", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-claude-code.zip", + "framework": "claude-code", + "title": "Claude Code", + "description": "PostHog AI Observability for Anthropic Claude Code sessions via the @posthog/ai-plugin", + "tags": [ + "ai_observability", + "claude-code", + "framework:claude-code", + "ai-observability" + ] + }, + { + "id": "ai-observability-openclaw", + "name": "PostHog AI Observability for the OpenClaw self-hosted AI gateway via the @posthog/openclaw plugin", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-openclaw.zip", + "framework": "openclaw", + "title": "OpenClaw", + "description": "PostHog AI Observability for the OpenClaw self-hosted AI gateway via the @posthog/openclaw plugin", + "tags": [ + "ai_observability", + "openclaw", + "framework:openclaw", + "ai-observability" + ] + }, + { + "id": "ai-observability-pi", + "name": "PostHog AI Observability for the Pi terminal coding agent via the @posthog/pi extension", + "group": "ai-observability", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/ai-observability-pi.zip", + "framework": "pi", + "title": "Pi Coding Agent", + "description": "PostHog AI Observability for the Pi terminal coding agent via the @posthog/pi extension", + "tags": [ + "ai_observability", + "pi", + "framework:pi", + "ai-observability" + ] + } + ], + "audit": [ + { + "id": "audit", + "name": "Audit an existing PostHog integration for correctness and best practices", + "group": "audit", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/audit.zip", + "title": "PostHog audit", + "description": "Audit an existing PostHog integration for correctness and best practices", + "tags": [ + "best-practices", + "audit" + ] + } + ], + "audit-attribution": [ + { + "id": "audit-attribution", + "name": "Audit a PostHog integration's marketing attribution capture for UTM survival, click-id coverage, cross-subdomain identity, and consent/cookieless interactions", + "group": "audit-attribution", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/audit-attribution.zip", + "title": "PostHog audit — attribution", + "description": "Audit a PostHog integration's marketing attribution capture for UTM survival, click-id coverage, cross-subdomain identity, and consent/cookieless interactions", + "tags": [ + "best-practices", + "audit-attribution" + ] + } + ], + "audit-autocapture": [ + { + "id": "audit-autocapture", + "name": "Audit a PostHog autocapture setup for correctness and cost-optimization opportunities", + "group": "audit-autocapture", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/audit-autocapture.zip", + "title": "PostHog audit — autocapture", + "description": "Audit a PostHog autocapture setup for correctness and cost-optimization opportunities", + "tags": [ + "best-practices", + "audit-autocapture" + ] + } + ], + "audit-events": [ + { + "id": "audit-events", + "name": "Audit a PostHog integration's event capture quality and cost-optimization opportunities", + "group": "audit-events", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/audit-events.zip", + "title": "PostHog audit — events", + "description": "Audit a PostHog integration's event capture quality and cost-optimization opportunities", + "tags": [ + "best-practices", + "audit-events" + ] + } + ], + "audit-feature-flags": [ + { + "id": "audit-feature-flags", + "name": "Audit a PostHog integration's feature flag usage for correctness and cost-optimization opportunities", + "group": "audit-feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/audit-feature-flags.zip", + "title": "PostHog audit — feature flags", + "description": "Audit a PostHog integration's feature flag usage for correctness and cost-optimization opportunities", + "tags": [ + "best-practices", + "audit-feature-flags" + ] + } + ], + "audit-identify": [ + { + "id": "audit-identify", + "name": "Audit a PostHog integration's $identify implementation for correctness and cost-optimization opportunities", + "group": "audit-identify", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/audit-identify.zip", + "title": "PostHog audit — identify", + "description": "Audit a PostHog integration's $identify implementation for correctness and cost-optimization opportunities", + "tags": [ + "best-practices", + "audit-identify" + ] + } + ], + "audit-session-replay": [ + { + "id": "audit-session-replay", + "name": "Audit a PostHog session replay setup for correctness and cost-optimization opportunities", + "group": "audit-session-replay", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/audit-session-replay.zip", + "title": "PostHog audit — session replay", + "description": "Audit a PostHog session replay setup for correctness and cost-optimization opportunities", + "tags": [ + "best-practices", + "audit-session-replay" + ] + } + ], + "creating-product-tours": [ + { + "id": "creating-product-tours", + "name": "Build an in-app product tour that guides users through a feature inside the user's own application. Targeting via PostHog feature flags, tracking via PostHog events, custom reusable UI components. Use when a user asks to create a product tour, onboarding walkthrough, feature spotlight, or step-by-step guide in their app.", + "group": "creating-product-tours", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/creating-product-tours.zip", + "title": "Creating product tours", + "description": "Build an in-app product tour that guides users through a feature inside the user's own application. Targeting via PostHog feature flags, tracking via PostHog events, custom reusable UI components. Use when a user asks to create a product tour, onboarding walkthrough, feature spotlight, or step-by-step guide in their app.", + "tags": [ + "product-tours", + "feature-flags", + "product-analytics", + "creating-product-tours" + ] + } + ], + "data-warehouse-source": [ + { + "id": "data-warehouse-source-setup", + "name": "Connect a detected data source to the PostHog data warehouse", + "group": "data-warehouse-source", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/data-warehouse-source-setup.zip", + "title": "Data Warehouse Source Setup", + "description": "Connect a detected data source to the PostHog data warehouse", + "tags": [ + "data-warehouse", + "sources", + "postgres", + "stripe", + "data-warehouse-source" + ] + } + ], + "error-tracking": [ + { + "id": "error-tracking-react", + "name": "PostHog error tracking for React", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-react.zip", + "title": "React", + "description": "PostHog error tracking for React", + "tags": [ + "error-tracking", + "react", + "javascript" + ] + }, + { + "id": "error-tracking-web", + "name": "PostHog error tracking for Web (JavaScript)", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-web.zip", + "title": "Web (JavaScript)", + "description": "PostHog error tracking for Web (JavaScript)", + "tags": [ + "error-tracking", + "javascript_web", + "javascript" + ] + }, + { + "id": "error-tracking-nextjs", + "name": "PostHog error tracking for Next.js", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-nextjs.zip", + "title": "Next.js", + "description": "PostHog error tracking for Next.js", + "tags": [ + "error-tracking", + "nextjs", + "react", + "javascript" + ] + }, + { + "id": "error-tracking-node", + "name": "PostHog error tracking for Node.js", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-node.zip", + "title": "Node.js", + "description": "PostHog error tracking for Node.js", + "tags": [ + "error-tracking", + "javascript_node", + "javascript" + ] + }, + { + "id": "error-tracking-python", + "name": "PostHog error tracking for Python", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-python.zip", + "title": "Python", + "description": "PostHog error tracking for Python", + "tags": [ + "error-tracking", + "python" + ] + }, + { + "id": "error-tracking-django", + "name": "PostHog error tracking for Django", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-django.zip", + "title": "Django", + "description": "PostHog error tracking for Django", + "tags": [ + "error-tracking", + "django", + "python" + ] + }, + { + "id": "error-tracking-flask", + "name": "PostHog error tracking for Flask", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-flask.zip", + "title": "Flask", + "description": "PostHog error tracking for Flask", + "tags": [ + "error-tracking", + "flask", + "python" + ] + }, + { + "id": "error-tracking-php", + "name": "PostHog error tracking for PHP", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-php.zip", + "title": "PHP", + "description": "PostHog error tracking for PHP", + "tags": [ + "error-tracking", + "php" + ] + }, + { + "id": "error-tracking-laravel", + "name": "PostHog error tracking for Laravel", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-laravel.zip", + "title": "Laravel", + "description": "PostHog error tracking for Laravel", + "tags": [ + "error-tracking", + "laravel", + "php" + ] + }, + { + "id": "error-tracking-wordpress", + "name": "PostHog error tracking for WordPress", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-wordpress.zip", + "title": "WordPress", + "description": "PostHog error tracking for WordPress", + "tags": [ + "error-tracking", + "wordpress", + "php", + "cms" + ] + }, + { + "id": "error-tracking-ruby", + "name": "PostHog error tracking for Ruby", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-ruby.zip", + "title": "Ruby", + "description": "PostHog error tracking for Ruby", + "tags": [ + "error-tracking", + "ruby" + ] + }, + { + "id": "error-tracking-ruby-on-rails", + "name": "PostHog error tracking for Ruby on Rails", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-ruby-on-rails.zip", + "title": "Ruby on Rails", + "description": "PostHog error tracking for Ruby on Rails", + "tags": [ + "error-tracking", + "ruby-on-rails", + "ruby" + ] + }, + { + "id": "error-tracking-go", + "name": "PostHog error tracking for Go", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-go.zip", + "title": "Go", + "description": "PostHog error tracking for Go", + "tags": [ + "error-tracking", + "go" + ] + }, + { + "id": "error-tracking-rust", + "name": "PostHog error tracking for Rust", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-rust.zip", + "title": "Rust", + "description": "PostHog error tracking for Rust", + "tags": [ + "error-tracking", + "rust" + ] + }, + { + "id": "error-tracking-dotnet", + "name": "PostHog error tracking for .NET / ASP.NET Core", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-dotnet.zip", + "title": ".NET / ASP.NET Core", + "description": "PostHog error tracking for .NET / ASP.NET Core", + "tags": [ + "error-tracking", + "dotnet", + "aspnetcore", + "csharp" + ] + }, + { + "id": "error-tracking-elixir", + "name": "PostHog error tracking for Elixir", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-elixir.zip", + "title": "Elixir", + "description": "PostHog error tracking for Elixir", + "tags": [ + "error-tracking", + "elixir" + ] + }, + { + "id": "error-tracking-angular", + "name": "PostHog error tracking for Angular", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-angular.zip", + "title": "Angular", + "description": "PostHog error tracking for Angular", + "tags": [ + "error-tracking", + "angular", + "javascript" + ] + }, + { + "id": "error-tracking-svelte", + "name": "PostHog error tracking for Svelte", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-svelte.zip", + "title": "Svelte", + "description": "PostHog error tracking for Svelte", + "tags": [ + "error-tracking", + "sveltekit", + "javascript" + ] + }, + { + "id": "error-tracking-nuxt", + "name": "PostHog error tracking for Nuxt", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-nuxt.zip", + "title": "Nuxt", + "description": "PostHog error tracking for Nuxt", + "tags": [ + "error-tracking", + "nuxt", + "javascript" + ] + }, + { + "id": "error-tracking-react-native", + "name": "PostHog error tracking for React Native", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-react-native.zip", + "title": "React Native", + "description": "PostHog error tracking for React Native", + "tags": [ + "error-tracking", + "react-native", + "javascript" + ] + }, + { + "id": "error-tracking-flutter", + "name": "PostHog error tracking for Flutter", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-flutter.zip", + "title": "Flutter", + "description": "PostHog error tracking for Flutter", + "tags": [ + "error-tracking", + "flutter", + "dart" + ] + }, + { + "id": "error-tracking-ios", + "name": "PostHog error tracking for iOS", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-ios.zip", + "title": "iOS", + "description": "PostHog error tracking for iOS", + "tags": [ + "error-tracking", + "ios", + "swift" + ] + }, + { + "id": "error-tracking-android", + "name": "PostHog error tracking for Android", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-android.zip", + "title": "Android", + "description": "PostHog error tracking for Android", + "tags": [ + "error-tracking", + "android", + "java", + "kotlin" + ] + }, + { + "id": "error-tracking-hono", + "name": "PostHog error tracking for Hono", + "group": "error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-hono.zip", + "title": "Hono", + "description": "PostHog error tracking for Hono", + "tags": [ + "error-tracking", + "javascript" + ] + } + ], + "error-tracking-link-releases": [ + { + "id": "error-tracking-link-releases-python", + "name": "Link each production deploy to a PostHog Error Tracking release for Python", + "group": "error-tracking-link-releases", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-link-releases-python.zip", + "title": "Python", + "description": "Link each production deploy to a PostHog Error Tracking release for Python", + "tags": [ + "error-tracking", + "releases", + "python", + "error-tracking-link-releases" + ] + }, + { + "id": "error-tracking-link-releases-ruby", + "name": "Link each production deploy to a PostHog Error Tracking release for Ruby", + "group": "error-tracking-link-releases", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-link-releases-ruby.zip", + "title": "Ruby", + "description": "Link each production deploy to a PostHog Error Tracking release for Ruby", + "tags": [ + "error-tracking", + "releases", + "ruby", + "error-tracking-link-releases" + ] + }, + { + "id": "error-tracking-link-releases-php", + "name": "Link each production deploy to a PostHog Error Tracking release for PHP", + "group": "error-tracking-link-releases", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-link-releases-php.zip", + "title": "PHP", + "description": "Link each production deploy to a PostHog Error Tracking release for PHP", + "tags": [ + "error-tracking", + "releases", + "php", + "error-tracking-link-releases" + ] + } + ], + "error-tracking-upload-source-maps": [ + { + "id": "error-tracking-upload-source-maps-web", + "name": "Upload source maps to PostHog Error Tracking for Web (JavaScript)", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-web.zip", + "title": "Web (JavaScript)", + "description": "Upload source maps to PostHog Error Tracking for Web (JavaScript)", + "tags": [ + "error-tracking", + "source-maps", + "javascript_web", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-nextjs", + "name": "Upload source maps to PostHog Error Tracking for Next.js", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-nextjs.zip", + "title": "Next.js", + "description": "Upload source maps to PostHog Error Tracking for Next.js", + "tags": [ + "error-tracking", + "source-maps", + "nextjs", + "react", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-node", + "name": "Upload source maps to PostHog Error Tracking for Node.js", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-node.zip", + "title": "Node.js", + "description": "Upload source maps to PostHog Error Tracking for Node.js", + "tags": [ + "error-tracking", + "source-maps", + "javascript_node", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-react", + "name": "Upload source maps to PostHog Error Tracking for React", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-react.zip", + "title": "React", + "description": "Upload source maps to PostHog Error Tracking for React", + "tags": [ + "error-tracking", + "source-maps", + "react", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-angular", + "name": "Upload source maps to PostHog Error Tracking for Angular", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-angular.zip", + "title": "Angular", + "description": "Upload source maps to PostHog Error Tracking for Angular", + "tags": [ + "error-tracking", + "source-maps", + "angular", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-nuxt", + "name": "Upload source maps to PostHog Error Tracking for Nuxt", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-nuxt.zip", + "title": "Nuxt", + "description": "Upload source maps to PostHog Error Tracking for Nuxt", + "tags": [ + "error-tracking", + "source-maps", + "nuxt", + "vue", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-react-native", + "name": "Upload source maps to PostHog Error Tracking for React Native", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-react-native.zip", + "title": "React Native", + "description": "Upload source maps to PostHog Error Tracking for React Native", + "tags": [ + "error-tracking", + "source-maps", + "react-native", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-android", + "name": "Upload ProGuard / R8 mapping files to PostHog Error Tracking for Android", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-android.zip", + "title": "Android", + "description": "Upload ProGuard / R8 mapping files to PostHog Error Tracking for Android", + "tags": [ + "error-tracking", + "source-maps", + "android", + "java", + "kotlin", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-flutter", + "name": "Upload Flutter debug symbols to PostHog Error Tracking", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-flutter.zip", + "title": "Flutter", + "description": "Upload Flutter debug symbols to PostHog Error Tracking", + "tags": [ + "error-tracking", + "source-maps", + "flutter", + "dart", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-ios", + "name": "Upload dSYM debug symbols to PostHog Error Tracking for iOS", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-ios.zip", + "title": "iOS", + "description": "Upload dSYM debug symbols to PostHog Error Tracking for iOS", + "tags": [ + "error-tracking", + "source-maps", + "ios", + "swift", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-go", + "name": "Upload native debug symbols to PostHog Error Tracking for Go", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-go.zip", + "title": "Go", + "description": "Upload native debug symbols to PostHog Error Tracking for Go", + "tags": [ + "error-tracking", + "source-maps", + "go", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-rust", + "name": "Upload native debug symbols to PostHog Error Tracking for Rust", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-rust.zip", + "title": "Rust", + "description": "Upload native debug symbols to PostHog Error Tracking for Rust", + "tags": [ + "error-tracking", + "source-maps", + "rust", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-vite", + "name": "Upload source maps to PostHog Error Tracking for Vite", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-vite.zip", + "title": "Vite", + "description": "Upload source maps to PostHog Error Tracking for Vite", + "tags": [ + "error-tracking", + "source-maps", + "vite", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-webpack", + "name": "Upload source maps to PostHog Error Tracking for Webpack", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-webpack.zip", + "title": "Webpack", + "description": "Upload source maps to PostHog Error Tracking for Webpack", + "tags": [ + "error-tracking", + "source-maps", + "webpack", + "javascript", + "error-tracking-upload-source-maps" + ] + }, + { + "id": "error-tracking-upload-source-maps-rollup", + "name": "Upload source maps to PostHog Error Tracking for Rollup", + "group": "error-tracking-upload-source-maps", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/error-tracking-upload-source-maps-rollup.zip", + "title": "Rollup", + "description": "Upload source maps to PostHog Error Tracking for Rollup", + "tags": [ + "error-tracking", + "source-maps", + "rollup", + "javascript", + "error-tracking-upload-source-maps" + ] + } + ], + "events-audit": [ + { + "id": "events-audit", + "name": "Audit PostHog events in a codebase — produce an inventory of every captured event mapped to its file, area, and 30-day volume for the product team to query", + "group": "events-audit", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/events-audit.zip", + "title": "PostHog events audit", + "description": "Audit PostHog events in a codebase — produce an inventory of every captured event mapped to its file, area, and 30-day volume for the product team to query", + "tags": [ + "analytics", + "audit", + "best-practices", + "events-audit" + ] + } + ], + "feature-flags": [ + { + "id": "feature-flags-react", + "name": "PostHog feature flags for React applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-react.zip", + "title": "React", + "description": "PostHog feature flags for React applications", + "tags": [ + "feature-flags", + "react", + "javascript" + ] + }, + { + "id": "feature-flags-nextjs", + "name": "PostHog feature flags for Next.js applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-nextjs.zip", + "title": "Next.js", + "description": "PostHog feature flags for Next.js applications", + "tags": [ + "feature-flags", + "nextjs", + "nextjs-feature-flags", + "react", + "javascript" + ] + }, + { + "id": "feature-flags-react-native", + "name": "PostHog feature flags for React Native applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-react-native.zip", + "title": "React Native", + "description": "PostHog feature flags for React Native applications", + "tags": [ + "feature-flags", + "react", + "react-native", + "javascript" + ] + }, + { + "id": "feature-flags-web", + "name": "PostHog feature flags for Web (JavaScript) applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-web.zip", + "title": "Web (JavaScript)", + "description": "PostHog feature flags for Web (JavaScript) applications", + "tags": [ + "feature-flags", + "javascript" + ] + }, + { + "id": "feature-flags-nodejs", + "name": "PostHog feature flags for Node.js applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-nodejs.zip", + "title": "Node.js", + "description": "PostHog feature flags for Node.js applications", + "tags": [ + "feature-flags", + "javascript" + ] + }, + { + "id": "feature-flags-python", + "name": "PostHog feature flags for Python applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-python.zip", + "title": "Python", + "description": "PostHog feature flags for Python applications", + "tags": [ + "feature-flags", + "python" + ] + }, + { + "id": "feature-flags-django", + "name": "PostHog feature flags for Django applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-django.zip", + "title": "Django", + "description": "PostHog feature flags for Django applications", + "tags": [ + "feature-flags", + "django", + "python" + ] + }, + { + "id": "feature-flags-flask", + "name": "PostHog feature flags for Flask applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-flask.zip", + "title": "Flask", + "description": "PostHog feature flags for Flask applications", + "tags": [ + "feature-flags", + "flask", + "python" + ] + }, + { + "id": "feature-flags-php", + "name": "PostHog feature flags for PHP applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-php.zip", + "title": "PHP", + "description": "PostHog feature flags for PHP applications", + "tags": [ + "feature-flags", + "php" + ] + }, + { + "id": "feature-flags-laravel", + "name": "PostHog feature flags for Laravel applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-laravel.zip", + "title": "Laravel", + "description": "PostHog feature flags for Laravel applications", + "tags": [ + "feature-flags", + "laravel", + "php" + ] + }, + { + "id": "feature-flags-wordpress", + "name": "PostHog feature flags for WordPress applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-wordpress.zip", + "title": "WordPress", + "description": "PostHog feature flags for WordPress applications", + "tags": [ + "feature-flags", + "wordpress", + "php", + "cms" + ] + }, + { + "id": "feature-flags-ruby", + "name": "PostHog feature flags for Ruby applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-ruby.zip", + "title": "Ruby", + "description": "PostHog feature flags for Ruby applications", + "tags": [ + "feature-flags", + "ruby" + ] + }, + { + "id": "feature-flags-ruby-on-rails", + "name": "PostHog feature flags for Ruby on Rails applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-ruby-on-rails.zip", + "title": "Ruby on Rails", + "description": "PostHog feature flags for Ruby on Rails applications", + "tags": [ + "feature-flags", + "ruby-on-rails", + "ruby" + ] + }, + { + "id": "feature-flags-go", + "name": "PostHog feature flags for Go applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-go.zip", + "title": "Go", + "description": "PostHog feature flags for Go applications", + "tags": [ + "feature-flags", + "go" + ] + }, + { + "id": "feature-flags-java", + "name": "PostHog feature flags for Java applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-java.zip", + "title": "Java", + "description": "PostHog feature flags for Java applications", + "tags": [ + "feature-flags", + "java" + ] + }, + { + "id": "feature-flags-rust", + "name": "PostHog feature flags for Rust applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-rust.zip", + "title": "Rust", + "description": "PostHog feature flags for Rust applications", + "tags": [ + "feature-flags", + "rust" + ] + }, + { + "id": "feature-flags-dotnet", + "name": "PostHog feature flags for .NET applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-dotnet.zip", + "title": ".NET", + "description": "PostHog feature flags for .NET applications", + "tags": [ + "feature-flags", + "dotnet", + "csharp" + ] + }, + { + "id": "feature-flags-aspnetcore-feature-management", + "name": "PostHog feature flags for ASP.NET Core applications using Microsoft.FeatureManagement", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-aspnetcore-feature-management.zip", + "title": "ASP.NET Core Feature Management", + "description": "PostHog feature flags for ASP.NET Core applications using Microsoft.FeatureManagement", + "tags": [ + "feature-flags", + "aspnetcore", + "dotnet", + "csharp", + "feature-management" + ] + }, + { + "id": "feature-flags-elixir", + "name": "PostHog feature flags for Elixir applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-elixir.zip", + "title": "Elixir", + "description": "PostHog feature flags for Elixir applications", + "tags": [ + "feature-flags", + "elixir" + ] + }, + { + "id": "feature-flags-android", + "name": "PostHog feature flags for Android applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-android.zip", + "title": "Android", + "description": "PostHog feature flags for Android applications", + "tags": [ + "feature-flags", + "android", + "java" + ] + }, + { + "id": "feature-flags-ios", + "name": "PostHog feature flags for iOS applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-ios.zip", + "title": "iOS", + "description": "PostHog feature flags for iOS applications", + "tags": [ + "feature-flags", + "ios", + "swift" + ] + }, + { + "id": "feature-flags-flutter", + "name": "PostHog feature flags for Flutter applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-flutter.zip", + "title": "Flutter", + "description": "PostHog feature flags for Flutter applications", + "tags": [ + "feature-flags", + "flutter", + "dart" + ] + }, + { + "id": "feature-flags-api", + "name": "PostHog feature flags for API applications", + "group": "feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/feature-flags-api.zip", + "title": "API", + "description": "PostHog feature flags for API applications", + "tags": [ + "feature-flags", + "api" + ] + } + ], + "integration": [ + { + "id": "integration-nextjs-app-router", + "name": "PostHog integration for Next.js App Router applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-nextjs-app-router.zip", + "framework": "nextjs", + "default": true, + "title": "Next.js App Router", + "description": "PostHog integration for Next.js App Router applications", + "tags": [ + "nextjs", + "react", + "ssr", + "app-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration", + "default" + ] + }, + { + "id": "integration-nextjs-pages-router", + "name": "PostHog integration for Next.js Pages Router applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-nextjs-pages-router.zip", + "framework": "nextjs", + "title": "Next.js Pages Router", + "description": "PostHog integration for Next.js Pages Router applications", + "tags": [ + "nextjs", + "react", + "ssr", + "pages-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration" + ] + }, + { + "id": "integration-react-react-router-6", + "name": "PostHog integration for React Router v6 applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-react-react-router-6.zip", + "framework": "react-router", + "default": true, + "title": "React Router v6", + "description": "PostHog integration for React Router v6 applications", + "tags": [ + "react", + "react-router", + "v6", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration", + "default" + ] + }, + { + "id": "integration-react-react-router-7-framework", + "name": "PostHog integration for React Router v7 - Framework mode applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-react-react-router-7-framework.zip", + "framework": "react-router", + "title": "React Router v7 - Framework mode", + "description": "PostHog integration for React Router v7 - Framework mode applications", + "tags": [ + "react", + "react-router", + "v7", + "framework", + "ssr", + "javascript", + "javascript_node", + "javascript_web", + "framework:react-router", + "integration" + ] + }, + { + "id": "integration-react-react-router-7-data", + "name": "PostHog integration for React Router v7 - Data mode applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-react-react-router-7-data.zip", + "framework": "react-router", + "title": "React Router v7 - Data mode", + "description": "PostHog integration for React Router v7 - Data mode applications", + "tags": [ + "react", + "react-router", + "v7", + "data", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration" + ] + }, + { + "id": "integration-react-react-router-7-declarative", + "name": "PostHog integration for React Router v7 - Declarative mode applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-react-react-router-7-declarative.zip", + "framework": "react-router", + "title": "React Router v7 - Declarative mode", + "description": "PostHog integration for React Router v7 - Declarative mode applications", + "tags": [ + "react", + "react-router", + "v7", + "declarative", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration" + ] + }, + { + "id": "integration-react-vite", + "name": "PostHog integration for React applications built with Vite (no router)", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-react-vite.zip", + "title": "React (Vite)", + "description": "PostHog integration for React applications built with Vite (no router)", + "tags": [ + "react", + "vite", + "spa", + "javascript", + "javascript_web", + "integration" + ] + }, + { + "id": "integration-nuxt-3-6", + "name": "PostHog integration for Nuxt versions 3.0 to 3.6", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-nuxt-3-6.zip", + "framework": "nuxt", + "default": true, + "title": "Nuxt 3.6", + "description": "PostHog integration for Nuxt versions 3.0 to 3.6", + "tags": [ + "nuxt", + "javascript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration", + "default" + ] + }, + { + "id": "integration-nuxt-4", + "name": "PostHog integration for Nuxt 4 applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-nuxt-4.zip", + "framework": "nuxt", + "title": "Nuxt 4", + "description": "PostHog integration for Nuxt 4 applications", + "tags": [ + "nuxt", + "vue", + "ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration" + ] + }, + { + "id": "integration-vue-3", + "name": "PostHog integration for Vue 3 applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-vue-3.zip", + "framework": "vue", + "title": "Vue 3", + "description": "PostHog integration for Vue 3 applications", + "tags": [ + "vue", + "javascript", + "typescript", + "javascript_web", + "framework:vue", + "integration" + ] + }, + { + "id": "integration-django", + "name": "PostHog integration for Django applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-django.zip", + "framework": "django", + "title": "Django", + "description": "PostHog integration for Django applications", + "tags": [ + "django", + "python", + "framework:django", + "integration" + ] + }, + { + "id": "integration-flask", + "name": "PostHog integration for Flask applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-flask.zip", + "framework": "flask", + "title": "Flask", + "description": "PostHog integration for Flask applications", + "tags": [ + "flask", + "python", + "framework:flask", + "integration" + ] + }, + { + "id": "integration-fastapi", + "name": "PostHog integration for FastAPI applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-fastapi.zip", + "framework": "fastapi", + "title": "FastAPI", + "description": "PostHog integration for FastAPI applications", + "tags": [ + "fastapi", + "python", + "framework:fastapi", + "integration" + ] + }, + { + "id": "integration-react-tanstack-router-file-based", + "name": "PostHog integration for React applications using TanStack Router with file-based routing", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-react-tanstack-router-file-based.zip", + "framework": "tanstack-router", + "title": "React with TanStack Router (file-based)", + "description": "PostHog integration for React applications using TanStack Router with file-based routing", + "tags": [ + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration" + ] + }, + { + "id": "integration-react-tanstack-router-code-based", + "name": "PostHog integration for React applications using TanStack Router with code-based routing", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-react-tanstack-router-code-based.zip", + "framework": "tanstack-router", + "default": true, + "title": "React with TanStack Router (code-based)", + "description": "PostHog integration for React applications using TanStack Router with code-based routing", + "tags": [ + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration", + "default" + ] + }, + { + "id": "integration-tanstack-start", + "name": "PostHog integration for TanStack Start full-stack applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-tanstack-start.zip", + "framework": "tanstack-start", + "title": "TanStack Start", + "description": "PostHog integration for TanStack Start full-stack applications", + "tags": [ + "react", + "tanstack-start", + "tanstack-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:tanstack-start", + "integration" + ] + }, + { + "id": "integration-laravel", + "name": "PostHog integration for Laravel applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-laravel.zip", + "framework": "laravel", + "title": "Laravel", + "description": "PostHog integration for Laravel applications", + "tags": [ + "laravel", + "php", + "framework:laravel", + "integration" + ] + }, + { + "id": "integration-php", + "name": "PostHog integration for any PHP application using the PHP SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-php.zip", + "title": "PHP", + "description": "PostHog integration for any PHP application using the PHP SDK", + "tags": [ + "php", + "integration" + ] + }, + { + "id": "integration-wordpress", + "name": "PostHog integration for self-hosted WordPress sites and plugins, combining client-side autocapture with server-side PHP SDK capture", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-wordpress.zip", + "framework": "wordpress", + "title": "WordPress", + "description": "PostHog integration for self-hosted WordPress sites and plugins, combining client-side autocapture with server-side PHP SDK capture", + "tags": [ + "wordpress", + "php", + "cms", + "framework:wordpress", + "integration" + ] + }, + { + "id": "integration-ruby-on-rails", + "name": "PostHog integration for Ruby on Rails applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-ruby-on-rails.zip", + "framework": "rails", + "title": "Ruby on Rails", + "description": "PostHog integration for Ruby on Rails applications", + "tags": [ + "ruby-on-rails", + "ruby", + "framework:rails", + "integration" + ] + }, + { + "id": "integration-android", + "name": "PostHog integration for Android applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-android.zip", + "framework": "android", + "title": "Android", + "description": "PostHog integration for Android applications", + "tags": [ + "android", + "java", + "kotlin", + "framework:android", + "integration" + ] + }, + { + "id": "integration-sveltekit", + "name": "PostHog integration for SvelteKit applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-sveltekit.zip", + "framework": "sveltekit", + "title": "SvelteKit", + "description": "PostHog integration for SvelteKit applications", + "tags": [ + "sveltekit", + "svelte", + "javascript", + "javascript_web", + "javascript_node", + "framework:sveltekit", + "integration" + ] + }, + { + "id": "integration-python", + "name": "PostHog integration for any Python application using the Python SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-python.zip", + "framework": "python", + "title": "Python", + "description": "PostHog integration for any Python application using the Python SDK", + "tags": [ + "python", + "framework:python", + "integration" + ] + }, + { + "id": "integration-javascript_node", + "name": "PostHog integration for server-side Node.js applications using posthog-node", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-javascript_node.zip", + "framework": "javascript_node", + "title": "JavaScript Node", + "description": "PostHog integration for server-side Node.js applications using posthog-node", + "tags": [ + "javascript_node", + "javascript", + "framework:javascript_node", + "integration" + ] + }, + { + "id": "integration-javascript_web", + "name": "PostHog integration for client-side web JavaScript applications using posthog-js", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-javascript_web.zip", + "framework": "javascript_web", + "title": "JavaScript Web", + "description": "PostHog integration for client-side web JavaScript applications using posthog-js", + "tags": [ + "javascript_web", + "javascript", + "framework:javascript_web", + "integration" + ] + }, + { + "id": "integration-ruby", + "name": "PostHog integration for any Ruby application using the Ruby SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-ruby.zip", + "framework": "ruby", + "title": "Ruby", + "description": "PostHog integration for any Ruby application using the Ruby SDK", + "tags": [ + "ruby", + "framework:ruby", + "integration" + ] + }, + { + "id": "integration-elixir", + "name": "PostHog integration for Elixir and Phoenix applications using the posthog SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-elixir.zip", + "framework": "elixir", + "title": "Elixir", + "description": "PostHog integration for Elixir and Phoenix applications using the posthog SDK", + "tags": [ + "elixir", + "phoenix", + "plug", + "framework:elixir", + "integration" + ] + }, + { + "id": "integration-java", + "name": "PostHog integration for Java and Spring Boot applications using the posthog-server SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-java.zip", + "framework": "java", + "title": "Java (Spring Boot)", + "description": "PostHog integration for Java and Spring Boot applications using the posthog-server SDK", + "tags": [ + "java", + "java-server", + "framework:java", + "integration" + ] + }, + { + "id": "integration-go", + "name": "PostHog integration for Go applications using the posthog-go SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-go.zip", + "framework": "go", + "title": "Go", + "description": "PostHog integration for Go applications using the posthog-go SDK", + "tags": [ + "go", + "framework:go", + "integration" + ] + }, + { + "id": "integration-rust", + "name": "PostHog integration for Rust applications using the posthog-rs SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-rust.zip", + "framework": "rust", + "title": "Rust", + "description": "PostHog integration for Rust applications using the posthog-rs SDK", + "tags": [ + "rust", + "framework:rust", + "integration" + ] + }, + { + "id": "integration-swift", + "name": "PostHog integration for Swift iOS and macOS applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-swift.zip", + "framework": "swift", + "title": "Swift (iOS/macOS)", + "description": "PostHog integration for Swift iOS and macOS applications", + "tags": [ + "swift", + "ios", + "macos", + "swiftui", + "xcodegen", + "framework:swift", + "integration" + ] + }, + { + "id": "integration-flutter", + "name": "PostHog integration for Flutter applications using the posthog_flutter SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-flutter.zip", + "framework": "flutter", + "title": "Flutter", + "description": "PostHog integration for Flutter applications using the posthog_flutter SDK", + "tags": [ + "flutter", + "dart", + "mobile", + "framework:flutter", + "integration" + ] + }, + { + "id": "integration-kmp", + "name": "PostHog integration for Kotlin Multiplatform (KMP) shared code targeting Android, iOS, and web using the posthog-kmp SDK", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-kmp.zip", + "framework": "kmp", + "title": "Kotlin Multiplatform", + "description": "PostHog integration for Kotlin Multiplatform (KMP) shared code targeting Android, iOS, and web using the posthog-kmp SDK", + "tags": [ + "kmp", + "kotlin", + "multiplatform", + "mobile", + "framework:kmp", + "integration" + ] + }, + { + "id": "integration-react-native", + "name": "PostHog integration for React Native applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-react-native.zip", + "framework": "react-native", + "default": true, + "title": "React Native", + "description": "PostHog integration for React Native applications", + "tags": [ + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration", + "default" + ] + }, + { + "id": "integration-expo", + "name": "PostHog integration for Expo applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-expo.zip", + "framework": "react-native", + "title": "Expo", + "description": "PostHog integration for Expo applications", + "tags": [ + "expo", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration" + ] + }, + { + "id": "integration-astro-static", + "name": "PostHog integration for static Astro sites using SSG", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-astro-static.zip", + "framework": "astro", + "title": "Astro (Static)", + "description": "PostHog integration for static Astro sites using SSG", + "tags": [ + "astro", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration" + ] + }, + { + "id": "integration-astro-view-transitions", + "name": "PostHog integration for Astro with ClientRouter view transitions", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-astro-view-transitions.zip", + "framework": "astro", + "title": "Astro (View Transitions)", + "description": "PostHog integration for Astro with ClientRouter view transitions", + "tags": [ + "astro", + "astro-view-transitions", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration" + ] + }, + { + "id": "integration-astro-ssr", + "name": "PostHog integration for server-rendered Astro applications with API routes", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-astro-ssr.zip", + "framework": "astro", + "title": "Astro (SSR)", + "description": "PostHog integration for server-rendered Astro applications with API routes", + "tags": [ + "astro", + "astro-ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration" + ] + }, + { + "id": "integration-astro-hybrid", + "name": "PostHog integration for Astro hybrid rendering with both static and server-rendered pages", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-astro-hybrid.zip", + "framework": "astro", + "default": true, + "title": "Astro (Hybrid)", + "description": "PostHog integration for Astro hybrid rendering with both static and server-rendered pages", + "tags": [ + "astro", + "astro-hybrid", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration", + "default" + ] + }, + { + "id": "integration-angular", + "name": "PostHog integration for Angular applications", + "group": "integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-angular.zip", + "framework": "angular", + "title": "Angular", + "description": "PostHog integration for Angular applications", + "tags": [ + "angular", + "javascript", + "typescript", + "javascript_web", + "framework:angular", + "integration" + ] + } + ], + "integration-v2/build": [ + { + "id": "integration-v2-build", + "name": "Install dependencies and verify the project builds", + "group": "integration-v2-build", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-build.zip", + "title": "PostHog build step", + "description": "Install dependencies and verify the project builds", + "tags": [ + "orchestrator", + "build", + "integration-v2-build" + ] + } + ], + "integration-v2/capture": [ + { + "id": "integration-v2-capture", + "name": "Instrument the planned events with PostHog capture calls", + "group": "integration-v2-capture", + "bundle": true, + "variants": [ + { + "id": "integration-v2-capture-nextjs-app-router", + "framework": "nextjs", + "default": true, + "title": "Next.js App Router", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "nextjs", + "react", + "ssr", + "app-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-capture", + "default" + ] + }, + { + "id": "integration-v2-capture-nextjs-pages-router", + "framework": "nextjs", + "title": "Next.js Pages Router", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "nextjs", + "react", + "ssr", + "pages-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-react-react-router-6", + "framework": "react-router", + "default": true, + "title": "React Router v6", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react", + "react-router", + "v6", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-capture", + "default" + ] + }, + { + "id": "integration-v2-capture-react-react-router-7-framework", + "framework": "react-router", + "title": "React Router v7 - Framework mode", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react", + "react-router", + "v7", + "framework", + "ssr", + "javascript", + "javascript_node", + "javascript_web", + "framework:react-router", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-react-react-router-7-data", + "framework": "react-router", + "title": "React Router v7 - Data mode", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react", + "react-router", + "v7", + "data", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-react-react-router-7-declarative", + "framework": "react-router", + "title": "React Router v7 - Declarative mode", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react", + "react-router", + "v7", + "declarative", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-react-vite", + "title": "React (Vite)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react", + "vite", + "spa", + "javascript", + "javascript_web", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-nuxt-3-6", + "framework": "nuxt", + "default": true, + "title": "Nuxt 3.6", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "nuxt", + "javascript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-capture", + "default" + ] + }, + { + "id": "integration-v2-capture-nuxt-4", + "framework": "nuxt", + "title": "Nuxt 4", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "nuxt", + "vue", + "ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-vue-3", + "framework": "vue", + "title": "Vue 3", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "vue", + "javascript", + "typescript", + "javascript_web", + "framework:vue", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-django", + "framework": "django", + "title": "Django", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "django", + "python", + "framework:django", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-flask", + "framework": "flask", + "title": "Flask", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "flask", + "python", + "framework:flask", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-fastapi", + "framework": "fastapi", + "title": "FastAPI", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "fastapi", + "python", + "framework:fastapi", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-react-tanstack-router-file-based", + "framework": "tanstack-router", + "title": "React with TanStack Router (file-based)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-react-tanstack-router-code-based", + "framework": "tanstack-router", + "default": true, + "title": "React with TanStack Router (code-based)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-capture", + "default" + ] + }, + { + "id": "integration-v2-capture-tanstack-start", + "framework": "tanstack-start", + "title": "TanStack Start", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react", + "tanstack-start", + "tanstack-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:tanstack-start", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-laravel", + "framework": "laravel", + "title": "Laravel", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "laravel", + "php", + "framework:laravel", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-php", + "title": "PHP", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "php", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-wordpress", + "framework": "wordpress", + "title": "WordPress", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "wordpress", + "php", + "cms", + "framework:wordpress", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-ruby-on-rails", + "framework": "rails", + "title": "Ruby on Rails", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "ruby-on-rails", + "ruby", + "framework:rails", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-android", + "framework": "android", + "title": "Android", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "android", + "java", + "kotlin", + "framework:android", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-sveltekit", + "framework": "sveltekit", + "title": "SvelteKit", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "sveltekit", + "svelte", + "javascript", + "javascript_web", + "javascript_node", + "framework:sveltekit", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-python", + "framework": "python", + "title": "Python", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "python", + "framework:python", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-javascript_node", + "framework": "javascript_node", + "title": "JavaScript Node", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "javascript_node", + "javascript", + "framework:javascript_node", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-javascript_web", + "framework": "javascript_web", + "title": "JavaScript Web", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "javascript_web", + "javascript", + "framework:javascript_web", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-ruby", + "framework": "ruby", + "title": "Ruby", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "ruby", + "framework:ruby", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-elixir", + "framework": "elixir", + "title": "Elixir", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "elixir", + "phoenix", + "plug", + "framework:elixir", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-java", + "framework": "java", + "title": "Java (Spring Boot)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "java", + "java-server", + "framework:java", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-go", + "framework": "go", + "title": "Go", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "go", + "framework:go", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-rust", + "framework": "rust", + "title": "Rust", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "rust", + "framework:rust", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-swift", + "framework": "swift", + "title": "Swift (iOS/macOS)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "swift", + "ios", + "macos", + "swiftui", + "xcodegen", + "framework:swift", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-flutter", + "framework": "flutter", + "title": "Flutter", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "flutter", + "dart", + "mobile", + "framework:flutter", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-kmp", + "framework": "kmp", + "title": "Kotlin Multiplatform", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "kmp", + "kotlin", + "multiplatform", + "mobile", + "framework:kmp", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-react-native", + "framework": "react-native", + "default": true, + "title": "React Native", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-capture", + "default" + ] + }, + { + "id": "integration-v2-capture-expo", + "framework": "react-native", + "title": "Expo", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "expo", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-astro-static", + "framework": "astro", + "title": "Astro (Static)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "astro", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-astro-view-transitions", + "framework": "astro", + "title": "Astro (View Transitions)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "astro", + "astro-view-transitions", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-astro-ssr", + "framework": "astro", + "title": "Astro (SSR)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "astro", + "astro-ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-capture" + ] + }, + { + "id": "integration-v2-capture-astro-hybrid", + "framework": "astro", + "default": true, + "title": "Astro (Hybrid)", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "astro", + "astro-hybrid", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-capture", + "default" + ] + }, + { + "id": "integration-v2-capture-angular", + "framework": "angular", + "title": "Angular", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "angular", + "javascript", + "typescript", + "javascript_web", + "framework:angular", + "integration-v2-capture" + ] + } + ], + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-capture.json", + "title": "Instrument the planned events with PostHog capture calls", + "description": "Instrument the planned events with PostHog capture calls", + "tags": [ + "orchestrator", + "capture", + "integration-v2-capture" + ] + } + ], + "integration-v2/dashboard": [ + { + "id": "integration-v2-dashboard", + "name": "Create a starter PostHog dashboard from the captured events", + "group": "integration-v2-dashboard", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-dashboard.zip", + "title": "PostHog dashboard step", + "description": "Create a starter PostHog dashboard from the captured events", + "tags": [ + "orchestrator", + "dashboard", + "integration-v2-dashboard" + ] + } + ], + "integration-v2/error-tracking-step": [ + { + "id": "integration-v2-error-tracking-step", + "name": "Capture exceptions with PostHog around critical flows", + "group": "integration-v2-error-tracking-step", + "bundle": true, + "variants": [ + { + "id": "integration-v2-error-tracking-step-nextjs-app-router", + "framework": "nextjs", + "default": true, + "title": "Next.js App Router", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "nextjs", + "react", + "ssr", + "app-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-error-tracking-step", + "default" + ] + }, + { + "id": "integration-v2-error-tracking-step-nextjs-pages-router", + "framework": "nextjs", + "title": "Next.js Pages Router", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "nextjs", + "react", + "ssr", + "pages-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-react-react-router-6", + "framework": "react-router", + "default": true, + "title": "React Router v6", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react", + "react-router", + "v6", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-error-tracking-step", + "default" + ] + }, + { + "id": "integration-v2-error-tracking-step-react-react-router-7-framework", + "framework": "react-router", + "title": "React Router v7 - Framework mode", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react", + "react-router", + "v7", + "framework", + "ssr", + "javascript", + "javascript_node", + "javascript_web", + "framework:react-router", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-react-react-router-7-data", + "framework": "react-router", + "title": "React Router v7 - Data mode", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react", + "react-router", + "v7", + "data", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-react-react-router-7-declarative", + "framework": "react-router", + "title": "React Router v7 - Declarative mode", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react", + "react-router", + "v7", + "declarative", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-react-vite", + "title": "React (Vite)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react", + "vite", + "spa", + "javascript", + "javascript_web", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-nuxt-3-6", + "framework": "nuxt", + "title": "Nuxt 3.6", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "nuxt", + "javascript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-nuxt-4", + "framework": "nuxt", + "default": true, + "title": "Nuxt 4", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "nuxt", + "vue", + "ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-error-tracking-step", + "default" + ] + }, + { + "id": "integration-v2-error-tracking-step-vue-3", + "framework": "vue", + "title": "Vue 3", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "vue", + "javascript", + "typescript", + "javascript_web", + "framework:vue", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-django", + "framework": "django", + "title": "Django", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "django", + "python", + "framework:django", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-flask", + "framework": "flask", + "title": "Flask", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "flask", + "python", + "framework:flask", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-fastapi", + "framework": "fastapi", + "title": "FastAPI", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "fastapi", + "python", + "framework:fastapi", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-react-tanstack-router-file-based", + "framework": "tanstack-router", + "title": "React with TanStack Router (file-based)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-react-tanstack-router-code-based", + "framework": "tanstack-router", + "default": true, + "title": "React with TanStack Router (code-based)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-error-tracking-step", + "default" + ] + }, + { + "id": "integration-v2-error-tracking-step-tanstack-start", + "framework": "tanstack-start", + "title": "TanStack Start", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react", + "tanstack-start", + "tanstack-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:tanstack-start", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-laravel", + "framework": "laravel", + "title": "Laravel", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "laravel", + "php", + "framework:laravel", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-php", + "title": "PHP", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "php", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-wordpress", + "framework": "wordpress", + "title": "WordPress", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "wordpress", + "php", + "cms", + "framework:wordpress", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-ruby-on-rails", + "framework": "rails", + "title": "Ruby on Rails", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "ruby-on-rails", + "ruby", + "framework:rails", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-android", + "framework": "android", + "title": "Android", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "android", + "java", + "kotlin", + "framework:android", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-sveltekit", + "framework": "sveltekit", + "title": "SvelteKit", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "sveltekit", + "svelte", + "javascript", + "javascript_web", + "javascript_node", + "framework:sveltekit", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-python", + "framework": "python", + "title": "Python", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "python", + "framework:python", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-javascript_node", + "framework": "javascript_node", + "title": "JavaScript Node", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "javascript_node", + "javascript", + "framework:javascript_node", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-javascript_web", + "framework": "javascript_web", + "title": "JavaScript Web", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "javascript_web", + "javascript", + "framework:javascript_web", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-ruby", + "framework": "ruby", + "title": "Ruby", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "ruby", + "framework:ruby", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-elixir", + "framework": "elixir", + "title": "Elixir", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "elixir", + "phoenix", + "plug", + "framework:elixir", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-java", + "framework": "java", + "title": "Java (Spring Boot)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "java", + "java-server", + "framework:java", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-go", + "framework": "go", + "title": "Go", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "go", + "framework:go", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-rust", + "framework": "rust", + "title": "Rust", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "rust", + "framework:rust", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-swift", + "framework": "swift", + "title": "Swift (iOS/macOS)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "swift", + "ios", + "macos", + "swiftui", + "xcodegen", + "framework:swift", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-flutter", + "framework": "flutter", + "title": "Flutter", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "flutter", + "dart", + "mobile", + "framework:flutter", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-kmp", + "framework": "kmp", + "title": "Kotlin Multiplatform", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "kmp", + "kotlin", + "multiplatform", + "mobile", + "framework:kmp", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-react-native", + "framework": "react-native", + "default": true, + "title": "React Native", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-error-tracking-step", + "default" + ] + }, + { + "id": "integration-v2-error-tracking-step-expo", + "framework": "react-native", + "title": "Expo", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "expo", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-astro-static", + "framework": "astro", + "title": "Astro (Static)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "astro", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-astro-view-transitions", + "framework": "astro", + "title": "Astro (View Transitions)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "astro", + "astro-view-transitions", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-astro-ssr", + "framework": "astro", + "title": "Astro (SSR)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "astro", + "astro-ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-error-tracking-step" + ] + }, + { + "id": "integration-v2-error-tracking-step-astro-hybrid", + "framework": "astro", + "default": true, + "title": "Astro (Hybrid)", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "astro", + "astro-hybrid", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-error-tracking-step", + "default" + ] + }, + { + "id": "integration-v2-error-tracking-step-angular", + "framework": "angular", + "title": "Angular", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "angular", + "javascript", + "typescript", + "javascript_web", + "framework:angular", + "integration-v2-error-tracking-step" + ] + } + ], + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-error-tracking-step.json", + "title": "Capture exceptions with PostHog around critical flows", + "description": "Capture exceptions with PostHog around critical flows", + "tags": [ + "orchestrator", + "error-tracking", + "integration-v2-error-tracking-step" + ] + } + ], + "integration-v2/feature-flags-step": [ + { + "id": "integration-v2-feature-flags-step-nextjs-app-router", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-nextjs-app-router.zip", + "framework": "nextjs", + "default": true, + "title": "Next.js App Router", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "nextjs", + "react", + "ssr", + "app-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-feature-flags-step", + "default" + ] + }, + { + "id": "integration-v2-feature-flags-step-nextjs-pages-router", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-nextjs-pages-router.zip", + "framework": "nextjs", + "title": "Next.js Pages Router", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "nextjs", + "react", + "ssr", + "pages-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-react-react-router-6", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-react-react-router-6.zip", + "framework": "react-router", + "default": true, + "title": "React Router v6", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react", + "react-router", + "v6", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-feature-flags-step", + "default" + ] + }, + { + "id": "integration-v2-feature-flags-step-react-react-router-7-framework", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-react-react-router-7-framework.zip", + "framework": "react-router", + "title": "React Router v7 - Framework mode", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react", + "react-router", + "v7", + "framework", + "ssr", + "javascript", + "javascript_node", + "javascript_web", + "framework:react-router", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-react-react-router-7-data", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-react-react-router-7-data.zip", + "framework": "react-router", + "title": "React Router v7 - Data mode", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react", + "react-router", + "v7", + "data", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-react-react-router-7-declarative", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-react-react-router-7-declarative.zip", + "framework": "react-router", + "title": "React Router v7 - Declarative mode", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react", + "react-router", + "v7", + "declarative", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-react-vite", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-react-vite.zip", + "title": "React (Vite)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react", + "vite", + "spa", + "javascript", + "javascript_web", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-nuxt-3-6", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-nuxt-3-6.zip", + "framework": "nuxt", + "title": "Nuxt 3.6", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "nuxt", + "javascript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-nuxt-4", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-nuxt-4.zip", + "framework": "nuxt", + "default": true, + "title": "Nuxt 4", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "nuxt", + "vue", + "ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-feature-flags-step", + "default" + ] + }, + { + "id": "integration-v2-feature-flags-step-vue-3", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-vue-3.zip", + "framework": "vue", + "title": "Vue 3", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "vue", + "javascript", + "typescript", + "javascript_web", + "framework:vue", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-django", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-django.zip", + "framework": "django", + "title": "Django", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "django", + "python", + "framework:django", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-flask", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-flask.zip", + "framework": "flask", + "title": "Flask", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "flask", + "python", + "framework:flask", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-fastapi", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-fastapi.zip", + "framework": "fastapi", + "title": "FastAPI", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "fastapi", + "python", + "framework:fastapi", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-react-tanstack-router-file-based", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-react-tanstack-router-file-based.zip", + "framework": "tanstack-router", + "title": "React with TanStack Router (file-based)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-react-tanstack-router-code-based", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-react-tanstack-router-code-based.zip", + "framework": "tanstack-router", + "default": true, + "title": "React with TanStack Router (code-based)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-feature-flags-step", + "default" + ] + }, + { + "id": "integration-v2-feature-flags-step-tanstack-start", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-tanstack-start.zip", + "framework": "tanstack-start", + "title": "TanStack Start", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react", + "tanstack-start", + "tanstack-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:tanstack-start", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-laravel", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-laravel.zip", + "framework": "laravel", + "title": "Laravel", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "laravel", + "php", + "framework:laravel", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-php", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-php.zip", + "title": "PHP", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "php", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-wordpress", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-wordpress.zip", + "framework": "wordpress", + "title": "WordPress", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "wordpress", + "php", + "cms", + "framework:wordpress", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-ruby-on-rails", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-ruby-on-rails.zip", + "framework": "rails", + "title": "Ruby on Rails", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "ruby-on-rails", + "ruby", + "framework:rails", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-android", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-android.zip", + "framework": "android", + "title": "Android", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "android", + "java", + "kotlin", + "framework:android", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-sveltekit", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-sveltekit.zip", + "framework": "sveltekit", + "title": "SvelteKit", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "sveltekit", + "svelte", + "javascript", + "javascript_web", + "javascript_node", + "framework:sveltekit", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-python", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-python.zip", + "framework": "python", + "title": "Python", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "python", + "framework:python", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-javascript_node", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-javascript_node.zip", + "framework": "javascript_node", + "title": "JavaScript Node", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "javascript_node", + "javascript", + "framework:javascript_node", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-javascript_web", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-javascript_web.zip", + "framework": "javascript_web", + "title": "JavaScript Web", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "javascript_web", + "javascript", + "framework:javascript_web", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-ruby", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-ruby.zip", + "framework": "ruby", + "title": "Ruby", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "ruby", + "framework:ruby", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-elixir", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-elixir.zip", + "framework": "elixir", + "title": "Elixir", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "elixir", + "phoenix", + "plug", + "framework:elixir", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-java", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-java.zip", + "framework": "java", + "title": "Java (Spring Boot)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "java", + "java-server", + "framework:java", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-go", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-go.zip", + "framework": "go", + "title": "Go", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "go", + "framework:go", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-rust", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-rust.zip", + "framework": "rust", + "title": "Rust", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "rust", + "framework:rust", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-swift", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-swift.zip", + "framework": "swift", + "title": "Swift (iOS/macOS)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "swift", + "ios", + "macos", + "swiftui", + "xcodegen", + "framework:swift", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-flutter", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-flutter.zip", + "framework": "flutter", + "title": "Flutter", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "flutter", + "dart", + "mobile", + "framework:flutter", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-kmp", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-kmp.zip", + "framework": "kmp", + "title": "Kotlin Multiplatform", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "kmp", + "kotlin", + "multiplatform", + "mobile", + "framework:kmp", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-react-native", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-react-native.zip", + "framework": "react-native", + "default": true, + "title": "React Native", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-feature-flags-step", + "default" + ] + }, + { + "id": "integration-v2-feature-flags-step-expo", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-expo.zip", + "framework": "react-native", + "title": "Expo", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "expo", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-astro-static", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-astro-static.zip", + "framework": "astro", + "title": "Astro (Static)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "astro", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-astro-view-transitions", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-astro-view-transitions.zip", + "framework": "astro", + "title": "Astro (View Transitions)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "astro", + "astro-view-transitions", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-astro-ssr", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-astro-ssr.zip", + "framework": "astro", + "title": "Astro (SSR)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "astro", + "astro-ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-feature-flags-step" + ] + }, + { + "id": "integration-v2-feature-flags-step-astro-hybrid", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-astro-hybrid.zip", + "framework": "astro", + "default": true, + "title": "Astro (Hybrid)", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "astro", + "astro-hybrid", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-feature-flags-step", + "default" + ] + }, + { + "id": "integration-v2-feature-flags-step-angular", + "name": "Evaluate the example PostHog feature flags, one per side of the app", + "group": "integration-v2-feature-flags-step", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-feature-flags-step-angular.zip", + "framework": "angular", + "title": "Angular", + "description": "Evaluate the example PostHog feature flags, one per side of the app", + "tags": [ + "orchestrator", + "feature-flags", + "angular", + "javascript", + "typescript", + "javascript_web", + "framework:angular", + "integration-v2-feature-flags-step" + ] + } + ], + "integration-v2/identify": [ + { + "id": "integration-v2-identify", + "name": "Identify users at login and signup", + "group": "integration-v2-identify", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-identify.zip", + "title": "PostHog identify step", + "description": "Identify users at login and signup", + "tags": [ + "orchestrator", + "identify", + "integration-v2-identify" + ] + } + ], + "integration-v2/init": [ + { + "id": "integration-v2-init", + "name": "Initialize PostHog and set its environment variables", + "group": "integration-v2-init", + "bundle": true, + "variants": [ + { + "id": "integration-v2-init-nextjs-app-router", + "framework": "nextjs", + "default": true, + "title": "Next.js App Router", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "nextjs", + "react", + "ssr", + "app-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-init", + "default" + ] + }, + { + "id": "integration-v2-init-nextjs-pages-router", + "framework": "nextjs", + "title": "Next.js Pages Router", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "nextjs", + "react", + "ssr", + "pages-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-react-react-router-6", + "framework": "react-router", + "default": true, + "title": "React Router v6", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react", + "react-router", + "v6", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-init", + "default" + ] + }, + { + "id": "integration-v2-init-react-react-router-7-framework", + "framework": "react-router", + "title": "React Router v7 - Framework mode", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react", + "react-router", + "v7", + "framework", + "ssr", + "javascript", + "javascript_node", + "javascript_web", + "framework:react-router", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-react-react-router-7-data", + "framework": "react-router", + "title": "React Router v7 - Data mode", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react", + "react-router", + "v7", + "data", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-react-react-router-7-declarative", + "framework": "react-router", + "title": "React Router v7 - Declarative mode", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react", + "react-router", + "v7", + "declarative", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-react-vite", + "title": "React (Vite)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react", + "vite", + "spa", + "javascript", + "javascript_web", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-nuxt-3-6", + "framework": "nuxt", + "default": true, + "title": "Nuxt 3.6", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "nuxt", + "javascript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-init", + "default" + ] + }, + { + "id": "integration-v2-init-nuxt-4", + "framework": "nuxt", + "title": "Nuxt 4", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "nuxt", + "vue", + "ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-vue-3", + "framework": "vue", + "title": "Vue 3", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "vue", + "javascript", + "typescript", + "javascript_web", + "framework:vue", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-django", + "framework": "django", + "title": "Django", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "django", + "python", + "framework:django", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-flask", + "framework": "flask", + "title": "Flask", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "flask", + "python", + "framework:flask", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-fastapi", + "framework": "fastapi", + "title": "FastAPI", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "fastapi", + "python", + "framework:fastapi", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-react-tanstack-router-file-based", + "framework": "tanstack-router", + "title": "React with TanStack Router (file-based)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-react-tanstack-router-code-based", + "framework": "tanstack-router", + "default": true, + "title": "React with TanStack Router (code-based)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-init", + "default" + ] + }, + { + "id": "integration-v2-init-tanstack-start", + "framework": "tanstack-start", + "title": "TanStack Start", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react", + "tanstack-start", + "tanstack-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:tanstack-start", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-laravel", + "framework": "laravel", + "title": "Laravel", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "laravel", + "php", + "framework:laravel", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-php", + "title": "PHP", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "php", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-wordpress", + "framework": "wordpress", + "title": "WordPress", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "wordpress", + "php", + "cms", + "framework:wordpress", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-ruby-on-rails", + "framework": "rails", + "title": "Ruby on Rails", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "ruby-on-rails", + "ruby", + "framework:rails", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-android", + "framework": "android", + "title": "Android", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "android", + "java", + "kotlin", + "framework:android", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-sveltekit", + "framework": "sveltekit", + "title": "SvelteKit", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "sveltekit", + "svelte", + "javascript", + "javascript_web", + "javascript_node", + "framework:sveltekit", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-python", + "framework": "python", + "title": "Python", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "python", + "framework:python", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-javascript_node", + "framework": "javascript_node", + "title": "JavaScript Node", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "javascript_node", + "javascript", + "framework:javascript_node", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-javascript_web", + "framework": "javascript_web", + "title": "JavaScript Web", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "javascript_web", + "javascript", + "framework:javascript_web", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-ruby", + "framework": "ruby", + "title": "Ruby", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "ruby", + "framework:ruby", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-elixir", + "framework": "elixir", + "title": "Elixir", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "elixir", + "phoenix", + "plug", + "framework:elixir", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-java", + "framework": "java", + "title": "Java (Spring Boot)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "java", + "java-server", + "framework:java", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-go", + "framework": "go", + "title": "Go", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "go", + "framework:go", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-rust", + "framework": "rust", + "title": "Rust", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "rust", + "framework:rust", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-swift", + "framework": "swift", + "title": "Swift (iOS/macOS)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "swift", + "ios", + "macos", + "swiftui", + "xcodegen", + "framework:swift", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-flutter", + "framework": "flutter", + "title": "Flutter", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "flutter", + "dart", + "mobile", + "framework:flutter", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-kmp", + "framework": "kmp", + "title": "Kotlin Multiplatform", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "kmp", + "kotlin", + "multiplatform", + "mobile", + "framework:kmp", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-react-native", + "framework": "react-native", + "default": true, + "title": "React Native", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-init", + "default" + ] + }, + { + "id": "integration-v2-init-expo", + "framework": "react-native", + "title": "Expo", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "expo", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-astro-static", + "framework": "astro", + "title": "Astro (Static)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "astro", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-astro-view-transitions", + "framework": "astro", + "title": "Astro (View Transitions)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "astro", + "astro-view-transitions", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-astro-ssr", + "framework": "astro", + "title": "Astro (SSR)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "astro", + "astro-ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-init" + ] + }, + { + "id": "integration-v2-init-astro-hybrid", + "framework": "astro", + "default": true, + "title": "Astro (Hybrid)", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "astro", + "astro-hybrid", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-init", + "default" + ] + }, + { + "id": "integration-v2-init-angular", + "framework": "angular", + "title": "Angular", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "angular", + "javascript", + "typescript", + "javascript_web", + "framework:angular", + "integration-v2-init" + ] + } + ], + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-init.json", + "title": "Initialize PostHog and set its environment variables", + "description": "Initialize PostHog and set its environment variables", + "tags": [ + "orchestrator", + "init", + "integration-v2-init" + ] + } + ], + "integration-v2/insight": [ + { + "id": "integration-v2-insight", + "name": "Create PostHog insights (trends, funnels) attached to a dashboard", + "group": "integration-v2-insight", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-insight.zip", + "title": "PostHog insight step", + "description": "Create PostHog insights (trends, funnels) attached to a dashboard", + "tags": [ + "orchestrator", + "insight", + "integration-v2-insight" + ] + } + ], + "integration-v2/install": [ + { + "id": "integration-v2-install", + "name": "Install the PostHog SDK with the project's package manager", + "group": "integration-v2-install", + "bundle": true, + "variants": [ + { + "id": "integration-v2-install-nextjs-app-router", + "framework": "nextjs", + "default": true, + "title": "Next.js App Router", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "nextjs", + "react", + "ssr", + "app-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-install", + "default" + ] + }, + { + "id": "integration-v2-install-nextjs-pages-router", + "framework": "nextjs", + "title": "Next.js Pages Router", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "nextjs", + "react", + "ssr", + "pages-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-react-react-router-6", + "framework": "react-router", + "default": true, + "title": "React Router v6", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react", + "react-router", + "v6", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-install", + "default" + ] + }, + { + "id": "integration-v2-install-react-react-router-7-framework", + "framework": "react-router", + "title": "React Router v7 - Framework mode", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react", + "react-router", + "v7", + "framework", + "ssr", + "javascript", + "javascript_node", + "javascript_web", + "framework:react-router", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-react-react-router-7-data", + "framework": "react-router", + "title": "React Router v7 - Data mode", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react", + "react-router", + "v7", + "data", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-react-react-router-7-declarative", + "framework": "react-router", + "title": "React Router v7 - Declarative mode", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react", + "react-router", + "v7", + "declarative", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-react-vite", + "title": "React (Vite)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react", + "vite", + "spa", + "javascript", + "javascript_web", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-nuxt-3-6", + "framework": "nuxt", + "default": true, + "title": "Nuxt 3.6", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "nuxt", + "javascript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-install", + "default" + ] + }, + { + "id": "integration-v2-install-nuxt-4", + "framework": "nuxt", + "title": "Nuxt 4", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "nuxt", + "vue", + "ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-vue-3", + "framework": "vue", + "title": "Vue 3", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "vue", + "javascript", + "typescript", + "javascript_web", + "framework:vue", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-django", + "framework": "django", + "title": "Django", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "django", + "python", + "framework:django", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-flask", + "framework": "flask", + "title": "Flask", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "flask", + "python", + "framework:flask", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-fastapi", + "framework": "fastapi", + "title": "FastAPI", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "fastapi", + "python", + "framework:fastapi", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-react-tanstack-router-file-based", + "framework": "tanstack-router", + "title": "React with TanStack Router (file-based)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-react-tanstack-router-code-based", + "framework": "tanstack-router", + "default": true, + "title": "React with TanStack Router (code-based)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "integration-v2-install", + "default" + ] + }, + { + "id": "integration-v2-install-tanstack-start", + "framework": "tanstack-start", + "title": "TanStack Start", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react", + "tanstack-start", + "tanstack-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:tanstack-start", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-laravel", + "framework": "laravel", + "title": "Laravel", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "laravel", + "php", + "framework:laravel", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-php", + "title": "PHP", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "php", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-wordpress", + "framework": "wordpress", + "title": "WordPress", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "wordpress", + "php", + "cms", + "framework:wordpress", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-ruby-on-rails", + "framework": "rails", + "title": "Ruby on Rails", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "ruby-on-rails", + "ruby", + "framework:rails", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-android", + "framework": "android", + "title": "Android", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "android", + "java", + "kotlin", + "framework:android", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-sveltekit", + "framework": "sveltekit", + "title": "SvelteKit", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "sveltekit", + "svelte", + "javascript", + "javascript_web", + "javascript_node", + "framework:sveltekit", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-python", + "framework": "python", + "title": "Python", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "python", + "framework:python", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-javascript_node", + "framework": "javascript_node", + "title": "JavaScript Node", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "javascript_node", + "javascript", + "framework:javascript_node", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-javascript_web", + "framework": "javascript_web", + "title": "JavaScript Web", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "javascript_web", + "javascript", + "framework:javascript_web", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-ruby", + "framework": "ruby", + "title": "Ruby", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "ruby", + "framework:ruby", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-elixir", + "framework": "elixir", + "title": "Elixir", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "elixir", + "phoenix", + "plug", + "framework:elixir", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-java", + "framework": "java", + "title": "Java (Spring Boot)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "java", + "java-server", + "framework:java", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-go", + "framework": "go", + "title": "Go", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "go", + "framework:go", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-rust", + "framework": "rust", + "title": "Rust", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "rust", + "framework:rust", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-swift", + "framework": "swift", + "title": "Swift (iOS/macOS)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "swift", + "ios", + "macos", + "swiftui", + "xcodegen", + "framework:swift", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-flutter", + "framework": "flutter", + "title": "Flutter", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "flutter", + "dart", + "mobile", + "framework:flutter", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-kmp", + "framework": "kmp", + "title": "Kotlin Multiplatform", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "kmp", + "kotlin", + "multiplatform", + "mobile", + "framework:kmp", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-react-native", + "framework": "react-native", + "default": true, + "title": "React Native", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-install", + "default" + ] + }, + { + "id": "integration-v2-install-expo", + "framework": "react-native", + "title": "Expo", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "expo", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-astro-static", + "framework": "astro", + "title": "Astro (Static)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "astro", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-astro-view-transitions", + "framework": "astro", + "title": "Astro (View Transitions)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "astro", + "astro-view-transitions", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-astro-ssr", + "framework": "astro", + "title": "Astro (SSR)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "astro", + "astro-ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-install" + ] + }, + { + "id": "integration-v2-install-astro-hybrid", + "framework": "astro", + "default": true, + "title": "Astro (Hybrid)", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "astro", + "astro-hybrid", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "integration-v2-install", + "default" + ] + }, + { + "id": "integration-v2-install-angular", + "framework": "angular", + "title": "Angular", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "angular", + "javascript", + "typescript", + "javascript_web", + "framework:angular", + "integration-v2-install" + ] + } + ], + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-install.json", + "title": "Install the PostHog SDK with the project's package manager", + "description": "Install the PostHog SDK with the project's package manager", + "tags": [ + "orchestrator", + "install", + "integration-v2-install" + ] + } + ], + "integration-v2/mcp": [ + { + "id": "integration-v2-mcp", + "name": "How to call PostHog MCP tools (discover, inspect, then call)", + "group": "integration-v2-mcp", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-mcp.zip", + "title": "PostHog MCP step", + "description": "How to call PostHog MCP tools (discover, inspect, then call)", + "tags": [ + "orchestrator", + "mcp", + "integration-v2-mcp" + ] + } + ], + "integration-v2/notebook": [ + { + "id": "integration-v2-notebook", + "name": "Mirror the setup report into a shareable PostHog notebook", + "group": "integration-v2-notebook", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-notebook.zip", + "title": "PostHog notebook step", + "description": "Mirror the setup report into a shareable PostHog notebook", + "tags": [ + "orchestrator", + "notebook", + "integration-v2-notebook" + ] + } + ], + "integration-v2/report": [ + { + "id": "integration-v2-report", + "name": "Publish the PostHog setup report from the run's handoffs", + "group": "integration-v2-report", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-report.zip", + "title": "PostHog report step", + "description": "Publish the PostHog setup report from the run's handoffs", + "tags": [ + "orchestrator", + "report", + "integration-v2-report" + ] + } + ], + "integration-v2/warehouse": [ + { + "id": "integration-v2-warehouse", + "name": "Connect the detected data sources to the PostHog data warehouse", + "group": "integration-v2-warehouse", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/integration-v2-warehouse.zip", + "title": "PostHog warehouse step", + "description": "Connect the detected data sources to the PostHog data warehouse", + "tags": [ + "orchestrator", + "data-warehouse", + "sources", + "integration-v2-warehouse" + ] + } + ], + "llm-analytics": [ + { + "id": "llm-analytics-setup", + "name": "PostHog AI Observability for all supported providers", + "group": "llm-analytics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/llm-analytics-setup.zip", + "title": "all supported providers", + "description": "PostHog AI Observability for all supported providers", + "tags": [ + "llm-analytics", + "python", + "javascript" + ] + }, + { + "id": "llm-analytics-dotnet-openai", + "name": "PostHog AI Observability for .NET applications using PostHog.AI with OpenAI or Azure OpenAI", + "group": "llm-analytics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/llm-analytics-dotnet-openai.zip", + "title": ".NET OpenAI / Azure OpenAI (PostHog.AI)", + "description": "PostHog AI Observability for .NET applications using PostHog.AI with OpenAI or Azure OpenAI", + "tags": [ + "llm-analytics", + "dotnet", + "aspnetcore", + "csharp", + "openai", + "azure-openai" + ] + } + ], + "logs": [ + { + "id": "logs-javascript", + "name": "PostHog logs for Web (JavaScript)", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-javascript.zip", + "title": "Web (JavaScript)", + "description": "PostHog logs for Web (JavaScript)", + "tags": [ + "logs", + "javascript_web", + "javascript" + ] + }, + { + "id": "logs-nextjs", + "name": "PostHog logs for Next.js", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-nextjs.zip", + "title": "Next.js", + "description": "PostHog logs for Next.js", + "tags": [ + "logs", + "nextjs", + "javascript" + ] + }, + { + "id": "logs-nodejs", + "name": "PostHog logs for Node.js", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-nodejs.zip", + "title": "Node.js", + "description": "PostHog logs for Node.js", + "tags": [ + "logs", + "javascript" + ] + }, + { + "id": "logs-python", + "name": "PostHog logs for Python", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-python.zip", + "title": "Python", + "description": "PostHog logs for Python", + "tags": [ + "logs", + "python" + ] + }, + { + "id": "logs-go", + "name": "PostHog logs for Go", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-go.zip", + "title": "Go", + "description": "PostHog logs for Go", + "tags": [ + "logs", + "go" + ] + }, + { + "id": "logs-java", + "name": "PostHog logs for Java", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-java.zip", + "title": "Java", + "description": "PostHog logs for Java", + "tags": [ + "logs", + "java" + ] + }, + { + "id": "logs-datadog", + "name": "PostHog logs for Datadog", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-datadog.zip", + "title": "Datadog", + "description": "PostHog logs for Datadog", + "tags": [ + "logs", + "datadog" + ] + }, + { + "id": "logs-react-native", + "name": "PostHog logs for React Native", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-react-native.zip", + "title": "React Native", + "description": "PostHog logs for React Native", + "tags": [ + "logs", + "react-native", + "javascript" + ] + }, + { + "id": "logs-android", + "name": "PostHog logs for Android", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-android.zip", + "title": "Android", + "description": "PostHog logs for Android", + "tags": [ + "logs", + "android", + "kotlin", + "java" + ] + }, + { + "id": "logs-ios", + "name": "PostHog logs for iOS", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-ios.zip", + "title": "iOS", + "description": "PostHog logs for iOS", + "tags": [ + "logs", + "ios", + "swift" + ] + }, + { + "id": "logs-flutter", + "name": "PostHog logs for Flutter", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-flutter.zip", + "title": "Flutter", + "description": "PostHog logs for Flutter", + "tags": [ + "logs", + "flutter", + "dart" + ] + }, + { + "id": "logs-other", + "name": "PostHog logs for Other Languages", + "group": "logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/logs-other.zip", + "title": "Other Languages", + "description": "PostHog logs for Other Languages", + "tags": [ + "logs" + ] + } + ], + "mcp-analytics": [ + { + "id": "mcp-analytics", + "name": "Add PostHog MCP analytics to a TypeScript, JavaScript, or Python MCP server. Captures tool calls, agent intent, failures, and protocol revision, plus self-reported model identity on supported TypeScript paths. Both SDKs support legacy sessions and the handshake-free 2026-07-28 revision. Detects the server style and wires in compatible instrumentation, credentials, conversation correlation, and graceful shutdown.", + "group": "mcp-analytics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/mcp-analytics.zip", + "title": "any TypeScript or JavaScript MCP server", + "description": "Add PostHog MCP analytics to a TypeScript, JavaScript, or Python MCP server. Captures tool calls, agent intent, failures, and protocol revision, plus self-reported model identity on supported TypeScript paths. Both SDKs support legacy sessions and the handshake-free 2026-07-28 revision. Detects the server style and wires in compatible instrumentation, credentials, conversation correlation, and graceful shutdown.", + "tags": [ + "mcp-analytics", + "mcp", + "javascript_node" + ] + }, + { + "id": "mcp-analytics-python", + "name": "Add PostHog MCP analytics to a TypeScript, JavaScript, or Python MCP server. Captures tool calls, agent intent, failures, and protocol revision, plus self-reported model identity on supported TypeScript paths. Both SDKs support legacy sessions and the handshake-free 2026-07-28 revision. Detects the server style and wires in compatible instrumentation, credentials, conversation correlation, and graceful shutdown.", + "group": "mcp-analytics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/mcp-analytics-python.zip", + "title": "any Python MCP server", + "description": "Add PostHog MCP analytics to a TypeScript, JavaScript, or Python MCP server. Captures tool calls, agent intent, failures, and protocol revision, plus self-reported model identity on supported TypeScript paths. Both SDKs support legacy sessions and the handshake-free 2026-07-28 revision. Detects the server style and wires in compatible instrumentation, credentials, conversation correlation, and graceful shutdown.", + "tags": [ + "mcp-analytics", + "mcp", + "python" + ] + } + ], + "metrics": [ + { + "id": "metrics-javascript", + "name": "PostHog metrics for Web (JavaScript)", + "group": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/metrics-javascript.zip", + "title": "Web (JavaScript)", + "description": "PostHog metrics for Web (JavaScript)", + "tags": [ + "metrics", + "javascript_web", + "javascript" + ] + }, + { + "id": "metrics-nodejs", + "name": "PostHog metrics for Node.js", + "group": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/metrics-nodejs.zip", + "title": "Node.js", + "description": "PostHog metrics for Node.js", + "tags": [ + "metrics", + "javascript" + ] + }, + { + "id": "metrics-python", + "name": "PostHog metrics for Python", + "group": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/metrics-python.zip", + "title": "Python", + "description": "PostHog metrics for Python", + "tags": [ + "metrics", + "python" + ] + }, + { + "id": "metrics-kubernetes", + "name": "PostHog metrics for Kubernetes", + "group": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/metrics-kubernetes.zip", + "title": "Kubernetes", + "description": "PostHog metrics for Kubernetes", + "tags": [ + "metrics", + "kubernetes" + ] + }, + { + "id": "metrics-other", + "name": "PostHog metrics for Other Languages", + "group": "metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/metrics-other.zip", + "title": "Other Languages", + "description": "PostHog metrics for Other Languages", + "tags": [ + "metrics" + ] + } + ], + "migrate": [ + { + "id": "migrate-statsig", + "name": "Migrate an existing analytics or feature-flag vendor to PostHog. Replaces SDK call sites in-place, removes the source package, and writes a migration report. Replacement-only, doesn't adds new instrumentation.", + "group": "migrate", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/migrate-statsig.zip", + "title": "Statsig → PostHog", + "description": "Migrate an existing analytics or feature-flag vendor to PostHog. Replaces SDK call sites in-place, removes the source package, and writes a migration report. Replacement-only, doesn't adds new instrumentation.", + "tags": [ + "migration", + "statsig", + "migrate" + ] + } + ], + "omnibus/instrument-error-tracking": [ + { + "id": "omnibus-instrument-error-tracking", + "name": "Add PostHog error tracking to capture and monitor exceptions. Use after implementing features or reviewing PRs to ensure errors are tracked with stack traces and source maps. Also handles initial PostHog SDK setup if not yet installed.", + "group": "omnibus-instrument-error-tracking", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/omnibus-instrument-error-tracking.zip", + "title": "all supported platforms", + "description": "Add PostHog error tracking to capture and monitor exceptions. Use after implementing features or reviewing PRs to ensure errors are tracked with stack traces and source maps. Also handles initial PostHog SDK setup if not yet installed.", + "tags": [ + "error-tracking", + "omnibus-instrument-error-tracking" + ] + } + ], + "omnibus/instrument-feature-flags": [ + { + "id": "omnibus-instrument-feature-flags", + "name": "Add PostHog feature flags to gate new functionality. Use after implementing features or reviewing PRs to ensure safe rollouts with feature flag controls. Also handles initial PostHog SDK setup if not yet installed.", + "group": "omnibus-instrument-feature-flags", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/omnibus-instrument-feature-flags.zip", + "title": "all supported platforms", + "description": "Add PostHog feature flags to gate new functionality. Use after implementing features or reviewing PRs to ensure safe rollouts with feature flag controls. Also handles initial PostHog SDK setup if not yet installed.", + "tags": [ + "feature-flags", + "omnibus-instrument-feature-flags" + ] + } + ], + "omnibus/instrument-integration": [ + { + "id": "omnibus-instrument-integration", + "name": "Add PostHog SDK integration to your application. Use when setting up PostHog for the first time or reviewing PRs that need PostHog initialization. Covers SDK installation, provider setup, and basic configuration for any framework.", + "group": "omnibus-instrument-integration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/omnibus-instrument-integration.zip", + "title": "all supported frameworks", + "description": "Add PostHog SDK integration to your application. Use when setting up PostHog for the first time or reviewing PRs that need PostHog initialization. Covers SDK installation, provider setup, and basic configuration for any framework.", + "tags": [ + "omnibus-instrument-integration" + ] + } + ], + "omnibus/instrument-llm-analytics": [ + { + "id": "omnibus-instrument-llm-analytics", + "name": "Add PostHog AI Observability to trace AI model usage. Use after implementing LLM features or reviewing PRs to ensure all generations are captured with token counts, latency, and costs. Also handles initial PostHog SDK setup if not yet installed.", + "group": "omnibus-instrument-llm-analytics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/omnibus-instrument-llm-analytics.zip", + "title": "all supported providers", + "description": "Add PostHog AI Observability to trace AI model usage. Use after implementing LLM features or reviewing PRs to ensure all generations are captured with token counts, latency, and costs. Also handles initial PostHog SDK setup if not yet installed.", + "tags": [ + "llm-analytics", + "omnibus-instrument-llm-analytics" + ] + } + ], + "omnibus/instrument-logs": [ + { + "id": "omnibus-instrument-logs", + "name": "Add PostHog log capture to track application logs. Use after implementing features or reviewing PRs to ensure meaningful log events are captured with structured properties. Also handles initial OTLP exporter setup if not yet configured.", + "group": "omnibus-instrument-logs", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/omnibus-instrument-logs.zip", + "title": "all supported platforms", + "description": "Add PostHog log capture to track application logs. Use after implementing features or reviewing PRs to ensure meaningful log events are captured with structured properties. Also handles initial OTLP exporter setup if not yet configured.", + "tags": [ + "logs", + "omnibus-instrument-logs" + ] + } + ], + "omnibus/instrument-metrics": [ + { + "id": "omnibus-instrument-metrics", + "name": "Add PostHog metric capture to track counters, gauges, and histograms. Use after implementing features or reviewing PRs to ensure key operations are measured, or when asked to add metrics, counters, or track a value over time. Also handles mirroring existing Prometheus/StatsD/OpenTelemetry metrics into PostHog and initial OTLP exporter setup.", + "group": "omnibus-instrument-metrics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/omnibus-instrument-metrics.zip", + "title": "all supported platforms", + "description": "Add PostHog metric capture to track counters, gauges, and histograms. Use after implementing features or reviewing PRs to ensure key operations are measured, or when asked to add metrics, counters, or track a value over time. Also handles mirroring existing Prometheus/StatsD/OpenTelemetry metrics into PostHog and initial OTLP exporter setup.", + "tags": [ + "metrics", + "omnibus-instrument-metrics" + ] + } + ], + "omnibus/instrument-product-analytics": [ + { + "id": "omnibus-instrument-product-analytics", + "name": "Add PostHog product analytics events to track user behavior. Use after implementing new features or reviewing PRs to ensure meaningful user actions are captured. Also handles initial PostHog SDK setup if not yet installed.", + "group": "omnibus-instrument-product-analytics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/omnibus-instrument-product-analytics.zip", + "title": "all supported frameworks", + "description": "Add PostHog product analytics events to track user behavior. Use after implementing new features or reviewing PRs to ensure meaningful user actions are captured. Also handles initial PostHog SDK setup if not yet installed.", + "tags": [ + "omnibus-instrument-product-analytics" + ] + } + ], + "omnibus/instrument-tracing": [ + { + "id": "omnibus-instrument-tracing", + "name": "Add PostHog distributed tracing to see how requests flow through services and where time goes. Use after implementing features or reviewing PRs to ensure request entry points, outbound calls, and background jobs produce spans, or when asked to add tracing or spans. Also handles pointing existing OpenTelemetry tracing at PostHog and initial OTLP exporter setup.", + "group": "omnibus-instrument-tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/omnibus-instrument-tracing.zip", + "title": "all supported platforms", + "description": "Add PostHog distributed tracing to see how requests flow through services and where time goes. Use after implementing features or reviewing PRs to ensure request entry points, outbound calls, and background jobs produce spans, or when asked to add tracing or spans. Also handles pointing existing OpenTelemetry tracing at PostHog and initial OTLP exporter setup.", + "tags": [ + "tracing", + "omnibus-instrument-tracing" + ] + } + ], + "posthog-best-practices": [ + { + "id": "posthog-best-practices", + "name": "Framework-agnostic, distilled best practices for using PostHog", + "group": "posthog-best-practices", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/posthog-best-practices.zip", + "title": "PostHog best practices", + "description": "Framework-agnostic, distilled best practices for using PostHog", + "tags": [ + "best-practices", + "posthog-best-practices" + ] + } + ], + "quack": [ + { + "id": "quack-quack", + "name": "Add QUACK QUACK comments to your codebase (for internal dev and testing)", + "group": "quack", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/quack-quack.zip", + "title": "Quack Quack Duck Comments (for internal dev and testing)", + "description": "Add QUACK QUACK comments to your codebase (for internal dev and testing)", + "tags": [ + "quack", + "internal-test" + ] + } + ], + "replay-vision": [ + { + "id": "replay-vision-setup", + "name": "Set up PostHog Replay vision. Makes sure session replay is recording (server-side enable plus a posthog-js init check), then creates vision scanners scoped to the product's key flows, read out of the repo. Scanners watch each new session recording with an LLM and report scores, tags, and summaries as queryable events.", + "group": "replay-vision", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/replay-vision-setup.zip", + "title": "PostHog Replay vision", + "description": "Set up PostHog Replay vision. Makes sure session replay is recording (server-side enable plus a posthog-js init check), then creates vision scanners scoped to the product's key flows, read out of the repo. Scanners watch each new session recording with an LLM and report scores, tags, and summaries as queryable events.", + "tags": [ + "replay-vision", + "session-replay" + ] + } + ], + "replay-vision-enable-replay": [ + { + "id": "replay-vision-enable-replay", + "name": "Make session replay record for Next.js App Router", + "group": "replay-vision-enable-replay", + "bundle": true, + "variants": [ + { + "id": "replay-vision-enable-replay-nextjs-app-router", + "framework": "nextjs", + "default": true, + "title": "Next.js App Router", + "description": "Make session replay record for Next.js App Router", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "nextjs", + "react", + "ssr", + "app-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "replay-vision-enable-replay", + "default" + ] + }, + { + "id": "replay-vision-enable-replay-nextjs-pages-router", + "framework": "nextjs", + "title": "Next.js Pages Router", + "description": "Make session replay record for Next.js Pages Router", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "nextjs", + "react", + "ssr", + "pages-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:nextjs", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-react-react-router-6", + "framework": "react-router", + "default": true, + "title": "React Router v6", + "description": "Make session replay record for React Router v6", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react", + "react-router", + "v6", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "replay-vision-enable-replay", + "default" + ] + }, + { + "id": "replay-vision-enable-replay-react-react-router-7-framework", + "framework": "react-router", + "title": "React Router v7 - Framework mode", + "description": "Make session replay record for React Router v7 - Framework mode", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react", + "react-router", + "v7", + "framework", + "ssr", + "javascript", + "javascript_node", + "javascript_web", + "framework:react-router", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-react-react-router-7-data", + "framework": "react-router", + "title": "React Router v7 - Data mode", + "description": "Make session replay record for React Router v7 - Data mode", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react", + "react-router", + "v7", + "data", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-react-react-router-7-declarative", + "framework": "react-router", + "title": "React Router v7 - Declarative mode", + "description": "Make session replay record for React Router v7 - Declarative mode", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react", + "react-router", + "v7", + "declarative", + "spa", + "javascript", + "javascript_web", + "framework:react-router", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-react-vite", + "title": "React (Vite)", + "description": "Make session replay record for React (Vite)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react", + "vite", + "spa", + "javascript", + "javascript_web", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-nuxt-3-6", + "framework": "nuxt", + "default": true, + "title": "Nuxt 3.6", + "description": "Make session replay record for Nuxt 3.6", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "nuxt", + "javascript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "replay-vision-enable-replay", + "default" + ] + }, + { + "id": "replay-vision-enable-replay-nuxt-4", + "framework": "nuxt", + "title": "Nuxt 4", + "description": "Make session replay record for Nuxt 4", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "nuxt", + "vue", + "ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:nuxt", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-vue-3", + "framework": "vue", + "title": "Vue 3", + "description": "Make session replay record for Vue 3", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "vue", + "javascript", + "typescript", + "javascript_web", + "framework:vue", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-django", + "framework": "django", + "title": "Django", + "description": "Make session replay record for Django", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "django", + "python", + "framework:django", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-flask", + "framework": "flask", + "title": "Flask", + "description": "Make session replay record for Flask", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "flask", + "python", + "framework:flask", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-fastapi", + "framework": "fastapi", + "title": "FastAPI", + "description": "Make session replay record for FastAPI", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "fastapi", + "python", + "framework:fastapi", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-react-tanstack-router-file-based", + "framework": "tanstack-router", + "title": "React with TanStack Router (file-based)", + "description": "Make session replay record for React with TanStack Router (file-based)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-react-tanstack-router-code-based", + "framework": "tanstack-router", + "default": true, + "title": "React with TanStack Router (code-based)", + "description": "Make session replay record for React with TanStack Router (code-based)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react", + "tanstack-router", + "spa", + "javascript", + "javascript_web", + "framework:tanstack-router", + "replay-vision-enable-replay", + "default" + ] + }, + { + "id": "replay-vision-enable-replay-tanstack-start", + "framework": "tanstack-start", + "title": "TanStack Start", + "description": "Make session replay record for TanStack Start", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react", + "tanstack-start", + "tanstack-router", + "javascript", + "javascript_web", + "javascript_node", + "framework:tanstack-start", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-laravel", + "framework": "laravel", + "title": "Laravel", + "description": "Make session replay record for Laravel", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "laravel", + "php", + "framework:laravel", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-php", + "title": "PHP", + "description": "Make session replay record for PHP", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "php", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-wordpress", + "framework": "wordpress", + "title": "WordPress", + "description": "Make session replay record for WordPress", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "wordpress", + "php", + "cms", + "framework:wordpress", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-ruby-on-rails", + "framework": "rails", + "title": "Ruby on Rails", + "description": "Make session replay record for Ruby on Rails", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "ruby-on-rails", + "ruby", + "framework:rails", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-android", + "framework": "android", + "title": "Android", + "description": "Make session replay record for Android", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "android", + "java", + "kotlin", + "framework:android", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-sveltekit", + "framework": "sveltekit", + "title": "SvelteKit", + "description": "Make session replay record for SvelteKit", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "sveltekit", + "svelte", + "javascript", + "javascript_web", + "javascript_node", + "framework:sveltekit", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-python", + "framework": "python", + "title": "Python", + "description": "Make session replay record for Python", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "python", + "framework:python", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-javascript_node", + "framework": "javascript_node", + "title": "JavaScript Node", + "description": "Make session replay record for JavaScript Node", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "javascript_node", + "javascript", + "framework:javascript_node", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-javascript_web", + "framework": "javascript_web", + "title": "JavaScript Web", + "description": "Make session replay record for JavaScript Web", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "javascript_web", + "javascript", + "framework:javascript_web", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-ruby", + "framework": "ruby", + "title": "Ruby", + "description": "Make session replay record for Ruby", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "ruby", + "framework:ruby", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-elixir", + "framework": "elixir", + "title": "Elixir", + "description": "Make session replay record for Elixir", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "elixir", + "phoenix", + "plug", + "framework:elixir", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-java", + "framework": "java", + "title": "Java (Spring Boot)", + "description": "Make session replay record for Java (Spring Boot)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "java", + "java-server", + "framework:java", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-go", + "framework": "go", + "title": "Go", + "description": "Make session replay record for Go", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "go", + "framework:go", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-rust", + "framework": "rust", + "title": "Rust", + "description": "Make session replay record for Rust", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "rust", + "framework:rust", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-swift", + "framework": "swift", + "title": "Swift (iOS/macOS)", + "description": "Make session replay record for Swift (iOS/macOS)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "swift", + "ios", + "macos", + "swiftui", + "xcodegen", + "framework:swift", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-flutter", + "framework": "flutter", + "title": "Flutter", + "description": "Make session replay record for Flutter", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "flutter", + "dart", + "mobile", + "framework:flutter", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-kmp", + "framework": "kmp", + "title": "Kotlin Multiplatform", + "description": "Make session replay record for Kotlin Multiplatform", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "kmp", + "kotlin", + "multiplatform", + "mobile", + "framework:kmp", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-react-native", + "framework": "react-native", + "default": true, + "title": "React Native", + "description": "Make session replay record for React Native", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "replay-vision-enable-replay", + "default" + ] + }, + { + "id": "replay-vision-enable-replay-expo", + "framework": "react-native", + "title": "Expo", + "description": "Make session replay record for Expo", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "expo", + "react-native", + "javascript", + "typescript", + "framework:react-native", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-astro-static", + "framework": "astro", + "title": "Astro (Static)", + "description": "Make session replay record for Astro (Static)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "astro", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-astro-view-transitions", + "framework": "astro", + "title": "Astro (View Transitions)", + "description": "Make session replay record for Astro (View Transitions)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "astro", + "astro-view-transitions", + "javascript", + "typescript", + "javascript_web", + "framework:astro", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-astro-ssr", + "framework": "astro", + "title": "Astro (SSR)", + "description": "Make session replay record for Astro (SSR)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "astro", + "astro-ssr", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "replay-vision-enable-replay" + ] + }, + { + "id": "replay-vision-enable-replay-astro-hybrid", + "framework": "astro", + "default": true, + "title": "Astro (Hybrid)", + "description": "Make session replay record for Astro (Hybrid)", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "astro", + "astro-hybrid", + "javascript", + "typescript", + "javascript_web", + "javascript_node", + "framework:astro", + "replay-vision-enable-replay", + "default" + ] + }, + { + "id": "replay-vision-enable-replay-angular", + "framework": "angular", + "title": "Angular", + "description": "Make session replay record for Angular", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "angular", + "javascript", + "typescript", + "javascript_web", + "framework:angular", + "replay-vision-enable-replay" + ] + } + ], + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/replay-vision-enable-replay.json", + "title": "Make session replay record for Next.js App Router", + "description": "Make session replay record for Next.js App Router", + "tags": [ + "orchestrator", + "replay-vision", + "session-replay", + "replay-vision-enable-replay" + ] + } + ], + "replay-vision-scanner-broken-experiences": [ + { + "id": "replay-vision-scanner-broken-experiences", + "name": "The breakage monitor brief for Replay vision", + "group": "replay-vision-scanner-broken-experiences", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/replay-vision-scanner-broken-experiences.zip", + "title": "Breakage scanner", + "description": "The breakage monitor brief for Replay vision", + "tags": [ + "orchestrator", + "replay-vision", + "replay-vision-scanner-broken-experiences" + ] + } + ], + "replay-vision-scanner-session-summaries": [ + { + "id": "replay-vision-scanner-session-summaries", + "name": "The summary scanner brief for Replay vision", + "group": "replay-vision-scanner-session-summaries", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/replay-vision-scanner-session-summaries.zip", + "title": "Summary scanner", + "description": "The summary scanner brief for Replay vision", + "tags": [ + "orchestrator", + "replay-vision", + "replay-vision-scanner-session-summaries" + ] + } + ], + "replay-vision-scanner-user-frustration": [ + { + "id": "replay-vision-scanner-user-frustration", + "name": "The frustration monitor brief for Replay vision", + "group": "replay-vision-scanner-user-frustration", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/replay-vision-scanner-user-frustration.zip", + "title": "Frustration scanner", + "description": "The frustration monitor brief for Replay vision", + "tags": [ + "orchestrator", + "replay-vision", + "replay-vision-scanner-user-frustration" + ] + } + ], + "replay-vision-scanners-core": [ + { + "id": "replay-vision-scanners-core", + "name": "Shared mechanics for creating Replay vision scanners", + "group": "replay-vision-scanners-core", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/replay-vision-scanners-core.zip", + "title": "Replay vision scanner mechanics", + "description": "Shared mechanics for creating Replay vision scanners", + "tags": [ + "orchestrator", + "replay-vision", + "replay-vision-scanners-core" + ] + } + ], + "revenue-analytics": [ + { + "id": "revenue-analytics-setup", + "name": "Set up Stripe revenue analytics with PostHog", + "group": "revenue-analytics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/revenue-analytics-setup.zip", + "title": "Stripe Revenue Analytics", + "description": "Set up Stripe revenue analytics with PostHog", + "tags": [ + "revenue-analytics", + "stripe" + ] + } + ], + "self-driving": [ + { + "id": "self-driving-setup", + "name": "Set up PostHog Self-driving — enable the right signal sources, tune the scout troop, and design custom scouts", + "group": "self-driving", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/self-driving-setup.zip", + "title": "PostHog Self-driving", + "description": "Set up PostHog Self-driving — enable the right signal sources, tune the scout troop, and design custom scouts", + "tags": [ + "signals", + "self-driving" + ] + } + ], + "tools-and-features": [ + { + "id": "tools-and-features-hogql", + "name": "HogQL queries for PostHog analytics", + "group": "tools-and-features", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tools-and-features-hogql.zip", + "title": "HogQL", + "description": "HogQL queries for PostHog analytics", + "tags": [ + "hogql", + "tools-and-features" + ] + } + ], + "tracing": [ + { + "id": "tracing-nodejs", + "name": "PostHog distributed tracing for Node.js", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-nodejs.zip", + "title": "Node.js", + "description": "PostHog distributed tracing for Node.js", + "tags": [ + "tracing", + "javascript" + ] + }, + { + "id": "tracing-nextjs", + "name": "PostHog distributed tracing for Next.js", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-nextjs.zip", + "title": "Next.js", + "description": "PostHog distributed tracing for Next.js", + "tags": [ + "tracing", + "nextjs", + "javascript" + ] + }, + { + "id": "tracing-python", + "name": "PostHog distributed tracing for Python", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-python.zip", + "title": "Python", + "description": "PostHog distributed tracing for Python", + "tags": [ + "tracing", + "python" + ] + }, + { + "id": "tracing-go", + "name": "PostHog distributed tracing for Go", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-go.zip", + "title": "Go", + "description": "PostHog distributed tracing for Go", + "tags": [ + "tracing", + "go" + ] + }, + { + "id": "tracing-java", + "name": "PostHog distributed tracing for Java", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-java.zip", + "title": "Java", + "description": "PostHog distributed tracing for Java", + "tags": [ + "tracing", + "java" + ] + }, + { + "id": "tracing-dotnet", + "name": "PostHog distributed tracing for .NET", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-dotnet.zip", + "title": ".NET", + "description": "PostHog distributed tracing for .NET", + "tags": [ + "tracing", + "dotnet", + "csharp" + ] + }, + { + "id": "tracing-php", + "name": "PostHog distributed tracing for PHP", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-php.zip", + "title": "PHP", + "description": "PostHog distributed tracing for PHP", + "tags": [ + "tracing", + "php" + ] + }, + { + "id": "tracing-ruby", + "name": "PostHog distributed tracing for Ruby", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-ruby.zip", + "title": "Ruby", + "description": "PostHog distributed tracing for Ruby", + "tags": [ + "tracing", + "ruby" + ] + }, + { + "id": "tracing-other", + "name": "PostHog distributed tracing for Other Languages", + "group": "tracing", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/tracing-other.zip", + "title": "Other Languages", + "description": "PostHog distributed tracing for Other Languages", + "tags": [ + "tracing" + ] + } + ], + "web-analytics": [ + { + "id": "web-analytics-doctor", + "name": "Audit and fix common PostHog web analytics misconfigurations", + "group": "web-analytics", + "downloadUrl": "https://github.com/PostHog/context-mill/releases/latest/download/web-analytics-doctor.zip", + "title": "Web Analytics Doctor", + "description": "Audit and fix common PostHog web analytics misconfigurations", + "tags": [ + "web-analytics", + "audit" + ] + } + ] + }, + "cliEntries": [ + { + "skillId": "mcp-analytics", + "role": "command", + "command": "mcp-analytics", + "displayName": "any TypeScript or JavaScript MCP server", + "description": "Add PostHog MCP analytics to a TypeScript, JavaScript, or Python MCP server. Captures tool calls, agent intent, failures, and protocol revision, plus self-reported model identity on supported TypeScript paths. Both SDKs support legacy sessions and the handshake-free 2026-07-28 revision. Detects the server style and wires in compatible instrumentation, credentials, conversation correlation, and graceful shutdown." + }, + { + "skillId": "mcp-analytics-python", + "role": "command", + "command": "mcp-analytics", + "displayName": "any Python MCP server", + "description": "Add PostHog MCP analytics to a TypeScript, JavaScript, or Python MCP server. Captures tool calls, agent intent, failures, and protocol revision, plus self-reported model identity on supported TypeScript paths. Both SDKs support legacy sessions and the handshake-free 2026-07-28 revision. Detects the server style and wires in compatible instrumentation, credentials, conversation correlation, and graceful shutdown." + }, + { + "skillId": "migrate-statsig", + "role": "command", + "command": "migrate", + "displayName": "Statsig → PostHog", + "description": "Migrate an existing analytics or feature-flag vendor to PostHog. Replaces SDK call sites in-place, removes the source package, and writes a migration report. Replacement-only, doesn't adds new instrumentation." + }, + { + "skillId": "replay-vision-setup", + "role": "command", + "command": "replay-vision", + "displayName": "PostHog Replay vision", + "description": "Set up PostHog Replay vision. Makes sure session replay is recording (server-side enable plus a posthog-js init check), then creates vision scanners scoped to the product's key flows, read out of the repo. Scanners watch each new session recording with an LLM and report scores, tags, and summaries as queryable events." + }, + { + "skillId": "revenue-analytics-setup", + "role": "command", + "command": "revenue-analytics", + "displayName": "Stripe Revenue Analytics", + "description": "Set up Stripe revenue analytics with PostHog" + }, + { + "skillId": "audit", + "role": "command", + "parentCommand": "audit", + "command": "all", + "default": true, + "displayName": "PostHog audit", + "description": "Audit an existing PostHog integration for correctness and best practices" + }, + { + "skillId": "audit-attribution", + "role": "command", + "parentCommand": "audit", + "command": "attribution", + "displayName": "PostHog audit — attribution", + "description": "Audit a PostHog integration's marketing attribution capture for UTM survival, click-id coverage, cross-subdomain identity, and consent/cookieless interactions" + }, + { + "skillId": "audit-autocapture", + "role": "command", + "parentCommand": "audit", + "command": "autocapture", + "displayName": "PostHog audit — autocapture", + "description": "Audit a PostHog autocapture setup for correctness and cost-optimization opportunities" + }, + { + "skillId": "audit-events", + "role": "command", + "parentCommand": "audit", + "command": "events", + "displayName": "PostHog audit — events", + "description": "Audit a PostHog integration's event capture quality and cost-optimization opportunities" + }, + { + "skillId": "audit-feature-flags", + "role": "command", + "parentCommand": "audit", + "command": "feature-flags", + "displayName": "PostHog audit — feature flags", + "description": "Audit a PostHog integration's feature flag usage for correctness and cost-optimization opportunities" + }, + { + "skillId": "audit-identify", + "role": "command", + "parentCommand": "audit", + "command": "identify", + "displayName": "PostHog audit — identify", + "description": "Audit a PostHog integration's $identify implementation for correctness and cost-optimization opportunities" + }, + { + "skillId": "audit-session-replay", + "role": "command", + "parentCommand": "audit", + "command": "session-replay", + "displayName": "PostHog audit — session replay", + "description": "Audit a PostHog session replay setup for correctness and cost-optimization opportunities" + }, + { + "skillId": "ai-observability-openai-python", + "role": "skill", + "displayName": "OpenAI (Python)", + "description": "PostHog AI Observability integration for OpenAI (Python)" + }, + { + "skillId": "ai-observability-openai-node", + "role": "skill", + "displayName": "OpenAI (Node)", + "description": "PostHog AI Observability integration for OpenAI (Node)" + }, + { + "skillId": "ai-observability-anthropic-python", + "role": "skill", + "displayName": "Anthropic (Python)", + "description": "PostHog AI Observability integration for Anthropic (Python)" + }, + { + "skillId": "ai-observability-anthropic-node", + "role": "skill", + "displayName": "Anthropic (Node)", + "description": "PostHog AI Observability integration for Anthropic (Node)" + }, + { + "skillId": "ai-observability-langchain-python", + "role": "skill", + "displayName": "LangChain (Python)", + "description": "PostHog AI Observability integration for LangChain (Python)" + }, + { + "skillId": "ai-observability-langchain-node", + "role": "skill", + "displayName": "LangChain (Node)", + "description": "PostHog AI Observability integration for LangChain (Node)" + }, + { + "skillId": "ai-observability-vercel-ai", + "role": "skill", + "displayName": "Vercel AI SDK", + "description": "PostHog AI Observability integration for Vercel AI SDK" + }, + { + "skillId": "ai-observability-google-python", + "role": "skill", + "displayName": "Google Gemini (Python)", + "description": "PostHog AI Observability integration for Google Gemini (Python)" + }, + { + "skillId": "ai-observability-google-node", + "role": "skill", + "displayName": "Google Gemini (Node)", + "description": "PostHog AI Observability integration for Google Gemini (Node)" + }, + { + "skillId": "ai-observability-manual-capture", + "role": "skill", + "displayName": "Manual capture", + "description": "PostHog AI Observability using explicit $ai_generation capture calls (no auto-instrumentation)" + }, + { + "skillId": "ai-observability-azure-openai-python", + "role": "skill", + "displayName": "Azure OpenAI (Python)", + "description": "PostHog AI Observability integration for Azure OpenAI (Python)" + }, + { + "skillId": "ai-observability-azure-openai-node", + "role": "skill", + "displayName": "Azure OpenAI (Node)", + "description": "PostHog AI Observability integration for Azure OpenAI (Node)" + }, + { + "skillId": "ai-observability-aws-bedrock-python", + "role": "skill", + "displayName": "AWS Bedrock (Python)", + "description": "PostHog AI Observability integration for AWS Bedrock (Python)" + }, + { + "skillId": "ai-observability-aws-bedrock-node", + "role": "skill", + "displayName": "AWS Bedrock (Node)", + "description": "PostHog AI Observability integration for AWS Bedrock (Node)" + }, + { + "skillId": "ai-observability-cerebras-python", + "role": "skill", + "displayName": "Cerebras (Python)", + "description": "PostHog AI Observability integration for Cerebras (Python)" + }, + { + "skillId": "ai-observability-cerebras-node", + "role": "skill", + "displayName": "Cerebras (Node)", + "description": "PostHog AI Observability integration for Cerebras (Node)" + }, + { + "skillId": "ai-observability-cohere-python", + "role": "skill", + "displayName": "Cohere (Python)", + "description": "PostHog AI Observability integration for Cohere (Python)" + }, + { + "skillId": "ai-observability-cohere-node", + "role": "skill", + "displayName": "Cohere (Node)", + "description": "PostHog AI Observability integration for Cohere (Node)" + }, + { + "skillId": "ai-observability-deepseek-python", + "role": "skill", + "displayName": "DeepSeek (Python)", + "description": "PostHog AI Observability integration for DeepSeek (Python)" + }, + { + "skillId": "ai-observability-deepseek-node", + "role": "skill", + "displayName": "DeepSeek (Node)", + "description": "PostHog AI Observability integration for DeepSeek (Node)" + }, + { + "skillId": "ai-observability-fireworks-ai-python", + "role": "skill", + "displayName": "Fireworks AI (Python)", + "description": "PostHog AI Observability integration for Fireworks AI (Python)" + }, + { + "skillId": "ai-observability-fireworks-ai-node", + "role": "skill", + "displayName": "Fireworks AI (Node)", + "description": "PostHog AI Observability integration for Fireworks AI (Node)" + }, + { + "skillId": "ai-observability-groq-python", + "role": "skill", + "displayName": "Groq (Python)", + "description": "PostHog AI Observability integration for Groq (Python)" + }, + { + "skillId": "ai-observability-groq-node", + "role": "skill", + "displayName": "Groq (Node)", + "description": "PostHog AI Observability integration for Groq (Node)" + }, + { + "skillId": "ai-observability-hugging-face-python", + "role": "skill", + "displayName": "Hugging Face (Python)", + "description": "PostHog AI Observability integration for Hugging Face (Python)" + }, + { + "skillId": "ai-observability-hugging-face-node", + "role": "skill", + "displayName": "Hugging Face (Node)", + "description": "PostHog AI Observability integration for Hugging Face (Node)" + }, + { + "skillId": "ai-observability-mistral-python", + "role": "skill", + "displayName": "Mistral (Python)", + "description": "PostHog AI Observability integration for Mistral (Python)" + }, + { + "skillId": "ai-observability-mistral-node", + "role": "skill", + "displayName": "Mistral (Node)", + "description": "PostHog AI Observability integration for Mistral (Node)" + }, + { + "skillId": "ai-observability-ollama-python", + "role": "skill", + "displayName": "Ollama (Python)", + "description": "PostHog AI Observability integration for Ollama (Python)" + }, + { + "skillId": "ai-observability-ollama-node", + "role": "skill", + "displayName": "Ollama (Node)", + "description": "PostHog AI Observability integration for Ollama (Node)" + }, + { + "skillId": "ai-observability-perplexity-python", + "role": "skill", + "displayName": "Perplexity (Python)", + "description": "PostHog AI Observability integration for Perplexity (Python)" + }, + { + "skillId": "ai-observability-perplexity-node", + "role": "skill", + "displayName": "Perplexity (Node)", + "description": "PostHog AI Observability integration for Perplexity (Node)" + }, + { + "skillId": "ai-observability-together-ai-python", + "role": "skill", + "displayName": "Together AI (Python)", + "description": "PostHog AI Observability integration for Together AI (Python)" + }, + { + "skillId": "ai-observability-together-ai-node", + "role": "skill", + "displayName": "Together AI (Node)", + "description": "PostHog AI Observability integration for Together AI (Node)" + }, + { + "skillId": "ai-observability-xai-python", + "role": "skill", + "displayName": "xAI (Python)", + "description": "PostHog AI Observability integration for xAI (Python)" + }, + { + "skillId": "ai-observability-xai-node", + "role": "skill", + "displayName": "xAI (Node)", + "description": "PostHog AI Observability integration for xAI (Node)" + }, + { + "skillId": "ai-observability-autogen", + "role": "skill", + "displayName": "AutoGen", + "description": "PostHog AI Observability for AutoGen (multi-agent framework, Python)" + }, + { + "skillId": "ai-observability-claude-agent-sdk", + "role": "skill", + "displayName": "Claude Agent SDK", + "description": "PostHog AI Observability for Anthropic's Claude Agent SDK (Python)" + }, + { + "skillId": "ai-observability-crewai", + "role": "skill", + "displayName": "CrewAI", + "description": "PostHog AI Observability for CrewAI (multi-agent orchestration, Python)" + }, + { + "skillId": "ai-observability-dspy", + "role": "skill", + "displayName": "DSPy", + "description": "PostHog AI Observability for DSPy (Python)" + }, + { + "skillId": "ai-observability-llamaindex", + "role": "skill", + "displayName": "LlamaIndex", + "description": "PostHog AI Observability for LlamaIndex (Python)" + }, + { + "skillId": "ai-observability-mirascope", + "role": "skill", + "displayName": "Mirascope", + "description": "PostHog AI Observability for Mirascope (Python)" + }, + { + "skillId": "ai-observability-openai-agents", + "role": "skill", + "displayName": "OpenAI Agents SDK", + "description": "PostHog AI Observability for the OpenAI Agents SDK (Python)" + }, + { + "skillId": "ai-observability-pydantic-ai", + "role": "skill", + "displayName": "Pydantic AI", + "description": "PostHog AI Observability for Pydantic AI (Python)" + }, + { + "skillId": "ai-observability-semantic-kernel", + "role": "skill", + "displayName": "Semantic Kernel", + "description": "PostHog AI Observability for Microsoft Semantic Kernel (Python)" + }, + { + "skillId": "ai-observability-smolagents", + "role": "skill", + "displayName": "smolagents", + "description": "PostHog AI Observability for smolagents (Python)" + }, + { + "skillId": "ai-observability-convex", + "role": "skill", + "displayName": "Convex", + "description": "PostHog AI Observability for Convex (Node, Vercel AI SDK inside)" + }, + { + "skillId": "ai-observability-mastra", + "role": "skill", + "displayName": "Mastra", + "description": "PostHog AI Observability for Mastra (agent framework, Node)" + }, + { + "skillId": "ai-observability-google-adk", + "role": "skill", + "displayName": "Google ADK", + "description": "PostHog AI Observability for the Google Agent Development Kit (agent framework, Node)" + }, + { + "skillId": "ai-observability-instructor-python", + "role": "skill", + "displayName": "Instructor (Python)", + "description": "PostHog AI Observability integration for Instructor (Python)" + }, + { + "skillId": "ai-observability-instructor-node", + "role": "skill", + "displayName": "Instructor (Node)", + "description": "PostHog AI Observability integration for Instructor (Node)" + }, + { + "skillId": "ai-observability-langgraph-python", + "role": "skill", + "displayName": "LangGraph (Python)", + "description": "PostHog AI Observability integration for LangGraph (Python)" + }, + { + "skillId": "ai-observability-langgraph-node", + "role": "skill", + "displayName": "LangGraph (Node)", + "description": "PostHog AI Observability integration for LangGraph (Node)" + }, + { + "skillId": "ai-observability-cloudflare-ai-gateway-python", + "role": "skill", + "displayName": "Cloudflare AI Gateway (Python)", + "description": "PostHog AI Observability integration for Cloudflare AI Gateway (Python)" + }, + { + "skillId": "ai-observability-cloudflare-ai-gateway-node", + "role": "skill", + "displayName": "Cloudflare AI Gateway (Node)", + "description": "PostHog AI Observability integration for Cloudflare AI Gateway (Node)" + }, + { + "skillId": "ai-observability-helicone-python", + "role": "skill", + "displayName": "Helicone (Python)", + "description": "PostHog AI Observability integration for Helicone (Python)" + }, + { + "skillId": "ai-observability-helicone-node", + "role": "skill", + "displayName": "Helicone (Node)", + "description": "PostHog AI Observability integration for Helicone (Node)" + }, + { + "skillId": "ai-observability-openrouter-python", + "role": "skill", + "displayName": "OpenRouter (Python)", + "description": "PostHog AI Observability integration for OpenRouter (Python)" + }, + { + "skillId": "ai-observability-openrouter-node", + "role": "skill", + "displayName": "OpenRouter (Node)", + "description": "PostHog AI Observability integration for OpenRouter (Node)" + }, + { + "skillId": "ai-observability-portkey-python", + "role": "skill", + "displayName": "Portkey (Python)", + "description": "PostHog AI Observability integration for Portkey (Python)" + }, + { + "skillId": "ai-observability-portkey-node", + "role": "skill", + "displayName": "Portkey (Node)", + "description": "PostHog AI Observability integration for Portkey (Node)" + }, + { + "skillId": "ai-observability-dedalus-python", + "role": "skill", + "displayName": "Dedalus Labs (Python)", + "description": "PostHog AI Observability integration for Dedalus Labs (Python)" + }, + { + "skillId": "ai-observability-dedalus-node", + "role": "skill", + "displayName": "Dedalus Labs (Node)", + "description": "PostHog AI Observability integration for Dedalus Labs (Node)" + }, + { + "skillId": "ai-observability-litellm", + "role": "skill", + "displayName": "LiteLLM", + "description": "PostHog AI Observability for LiteLLM (unified LLM SDK / proxy, Python)" + }, + { + "skillId": "ai-observability-opentelemetry-python", + "role": "skill", + "displayName": "OpenTelemetry (Python)", + "description": "PostHog AI Observability integration for OpenTelemetry (Python)" + }, + { + "skillId": "ai-observability-opentelemetry-node", + "role": "skill", + "displayName": "OpenTelemetry (Node)", + "description": "PostHog AI Observability integration for OpenTelemetry (Node)" + }, + { + "skillId": "ai-observability-opentelemetry-go", + "role": "skill", + "displayName": "OpenTelemetry (Go)", + "description": "PostHog AI Observability integration for OpenTelemetry (Go)" + }, + { + "skillId": "ai-observability-claude-code", + "role": "skill", + "displayName": "Claude Code", + "description": "PostHog AI Observability for Anthropic Claude Code sessions via the @posthog/ai-plugin" + }, + { + "skillId": "ai-observability-openclaw", + "role": "skill", + "displayName": "OpenClaw", + "description": "PostHog AI Observability for the OpenClaw self-hosted AI gateway via the @posthog/openclaw plugin" + }, + { + "skillId": "ai-observability-pi", + "role": "skill", + "displayName": "Pi Coding Agent", + "description": "PostHog AI Observability for the Pi terminal coding agent via the @posthog/pi extension" + }, + { + "skillId": "creating-product-tours", + "role": "skill", + "displayName": "Creating product tours", + "description": "Build an in-app product tour that guides users through a feature inside the user's own application. Targeting via PostHog feature flags, tracking via PostHog events, custom reusable UI components. Use when a user asks to create a product tour, onboarding walkthrough, feature spotlight, or step-by-step guide in their app." + }, + { + "skillId": "integration-v2-build", + "role": "internal", + "displayName": "PostHog build step", + "description": "Install dependencies and verify the project builds" + }, + { + "skillId": "integration-v2-capture-nextjs-app-router", + "role": "internal", + "displayName": "Next.js App Router", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-nextjs-pages-router", + "role": "internal", + "displayName": "Next.js Pages Router", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-react-react-router-6", + "role": "internal", + "displayName": "React Router v6", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-react-react-router-7-framework", + "role": "internal", + "displayName": "React Router v7 - Framework mode", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-react-react-router-7-data", + "role": "internal", + "displayName": "React Router v7 - Data mode", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-react-react-router-7-declarative", + "role": "internal", + "displayName": "React Router v7 - Declarative mode", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-react-vite", + "role": "internal", + "displayName": "React (Vite)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-nuxt-3-6", + "role": "internal", + "displayName": "Nuxt 3.6", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-nuxt-4", + "role": "internal", + "displayName": "Nuxt 4", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-vue-3", + "role": "internal", + "displayName": "Vue 3", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-django", + "role": "internal", + "displayName": "Django", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-flask", + "role": "internal", + "displayName": "Flask", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-fastapi", + "role": "internal", + "displayName": "FastAPI", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-react-tanstack-router-file-based", + "role": "internal", + "displayName": "React with TanStack Router (file-based)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-react-tanstack-router-code-based", + "role": "internal", + "displayName": "React with TanStack Router (code-based)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-tanstack-start", + "role": "internal", + "displayName": "TanStack Start", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-laravel", + "role": "internal", + "displayName": "Laravel", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-php", + "role": "internal", + "displayName": "PHP", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-wordpress", + "role": "internal", + "displayName": "WordPress", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-ruby-on-rails", + "role": "internal", + "displayName": "Ruby on Rails", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-android", + "role": "internal", + "displayName": "Android", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-sveltekit", + "role": "internal", + "displayName": "SvelteKit", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-python", + "role": "internal", + "displayName": "Python", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-javascript_node", + "role": "internal", + "displayName": "JavaScript Node", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-javascript_web", + "role": "internal", + "displayName": "JavaScript Web", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-ruby", + "role": "internal", + "displayName": "Ruby", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-elixir", + "role": "internal", + "displayName": "Elixir", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-java", + "role": "internal", + "displayName": "Java (Spring Boot)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-go", + "role": "internal", + "displayName": "Go", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-rust", + "role": "internal", + "displayName": "Rust", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-swift", + "role": "internal", + "displayName": "Swift (iOS/macOS)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-flutter", + "role": "internal", + "displayName": "Flutter", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-kmp", + "role": "internal", + "displayName": "Kotlin Multiplatform", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-react-native", + "role": "internal", + "displayName": "React Native", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-expo", + "role": "internal", + "displayName": "Expo", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-astro-static", + "role": "internal", + "displayName": "Astro (Static)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-astro-view-transitions", + "role": "internal", + "displayName": "Astro (View Transitions)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-astro-ssr", + "role": "internal", + "displayName": "Astro (SSR)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-astro-hybrid", + "role": "internal", + "displayName": "Astro (Hybrid)", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-capture-angular", + "role": "internal", + "displayName": "Angular", + "description": "Instrument the planned events with PostHog capture calls" + }, + { + "skillId": "integration-v2-dashboard", + "role": "internal", + "displayName": "PostHog dashboard step", + "description": "Create a starter PostHog dashboard from the captured events" + }, + { + "skillId": "integration-v2-error-tracking-step-nextjs-app-router", + "role": "internal", + "displayName": "Next.js App Router", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-nextjs-pages-router", + "role": "internal", + "displayName": "Next.js Pages Router", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-react-react-router-6", + "role": "internal", + "displayName": "React Router v6", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-react-react-router-7-framework", + "role": "internal", + "displayName": "React Router v7 - Framework mode", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-react-react-router-7-data", + "role": "internal", + "displayName": "React Router v7 - Data mode", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-react-react-router-7-declarative", + "role": "internal", + "displayName": "React Router v7 - Declarative mode", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-react-vite", + "role": "internal", + "displayName": "React (Vite)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-nuxt-3-6", + "role": "internal", + "displayName": "Nuxt 3.6", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-nuxt-4", + "role": "internal", + "displayName": "Nuxt 4", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-vue-3", + "role": "internal", + "displayName": "Vue 3", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-django", + "role": "internal", + "displayName": "Django", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-flask", + "role": "internal", + "displayName": "Flask", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-fastapi", + "role": "internal", + "displayName": "FastAPI", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-react-tanstack-router-file-based", + "role": "internal", + "displayName": "React with TanStack Router (file-based)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-react-tanstack-router-code-based", + "role": "internal", + "displayName": "React with TanStack Router (code-based)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-tanstack-start", + "role": "internal", + "displayName": "TanStack Start", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-laravel", + "role": "internal", + "displayName": "Laravel", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-php", + "role": "internal", + "displayName": "PHP", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-wordpress", + "role": "internal", + "displayName": "WordPress", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-ruby-on-rails", + "role": "internal", + "displayName": "Ruby on Rails", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-android", + "role": "internal", + "displayName": "Android", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-sveltekit", + "role": "internal", + "displayName": "SvelteKit", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-python", + "role": "internal", + "displayName": "Python", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-javascript_node", + "role": "internal", + "displayName": "JavaScript Node", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-javascript_web", + "role": "internal", + "displayName": "JavaScript Web", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-ruby", + "role": "internal", + "displayName": "Ruby", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-elixir", + "role": "internal", + "displayName": "Elixir", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-java", + "role": "internal", + "displayName": "Java (Spring Boot)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-go", + "role": "internal", + "displayName": "Go", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-rust", + "role": "internal", + "displayName": "Rust", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-swift", + "role": "internal", + "displayName": "Swift (iOS/macOS)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-flutter", + "role": "internal", + "displayName": "Flutter", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-kmp", + "role": "internal", + "displayName": "Kotlin Multiplatform", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-react-native", + "role": "internal", + "displayName": "React Native", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-expo", + "role": "internal", + "displayName": "Expo", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-astro-static", + "role": "internal", + "displayName": "Astro (Static)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-astro-view-transitions", + "role": "internal", + "displayName": "Astro (View Transitions)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-astro-ssr", + "role": "internal", + "displayName": "Astro (SSR)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-astro-hybrid", + "role": "internal", + "displayName": "Astro (Hybrid)", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-error-tracking-step-angular", + "role": "internal", + "displayName": "Angular", + "description": "Capture exceptions with PostHog around critical flows" + }, + { + "skillId": "integration-v2-feature-flags-step-nextjs-app-router", + "role": "internal", + "displayName": "Next.js App Router", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-nextjs-pages-router", + "role": "internal", + "displayName": "Next.js Pages Router", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-react-react-router-6", + "role": "internal", + "displayName": "React Router v6", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-react-react-router-7-framework", + "role": "internal", + "displayName": "React Router v7 - Framework mode", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-react-react-router-7-data", + "role": "internal", + "displayName": "React Router v7 - Data mode", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-react-react-router-7-declarative", + "role": "internal", + "displayName": "React Router v7 - Declarative mode", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-react-vite", + "role": "internal", + "displayName": "React (Vite)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-nuxt-3-6", + "role": "internal", + "displayName": "Nuxt 3.6", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-nuxt-4", + "role": "internal", + "displayName": "Nuxt 4", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-vue-3", + "role": "internal", + "displayName": "Vue 3", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-django", + "role": "internal", + "displayName": "Django", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-flask", + "role": "internal", + "displayName": "Flask", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-fastapi", + "role": "internal", + "displayName": "FastAPI", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-react-tanstack-router-file-based", + "role": "internal", + "displayName": "React with TanStack Router (file-based)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-react-tanstack-router-code-based", + "role": "internal", + "displayName": "React with TanStack Router (code-based)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-tanstack-start", + "role": "internal", + "displayName": "TanStack Start", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-laravel", + "role": "internal", + "displayName": "Laravel", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-php", + "role": "internal", + "displayName": "PHP", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-wordpress", + "role": "internal", + "displayName": "WordPress", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-ruby-on-rails", + "role": "internal", + "displayName": "Ruby on Rails", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-android", + "role": "internal", + "displayName": "Android", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-sveltekit", + "role": "internal", + "displayName": "SvelteKit", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-python", + "role": "internal", + "displayName": "Python", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-javascript_node", + "role": "internal", + "displayName": "JavaScript Node", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-javascript_web", + "role": "internal", + "displayName": "JavaScript Web", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-ruby", + "role": "internal", + "displayName": "Ruby", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-elixir", + "role": "internal", + "displayName": "Elixir", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-java", + "role": "internal", + "displayName": "Java (Spring Boot)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-go", + "role": "internal", + "displayName": "Go", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-rust", + "role": "internal", + "displayName": "Rust", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-swift", + "role": "internal", + "displayName": "Swift (iOS/macOS)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-flutter", + "role": "internal", + "displayName": "Flutter", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-kmp", + "role": "internal", + "displayName": "Kotlin Multiplatform", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-react-native", + "role": "internal", + "displayName": "React Native", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-expo", + "role": "internal", + "displayName": "Expo", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-astro-static", + "role": "internal", + "displayName": "Astro (Static)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-astro-view-transitions", + "role": "internal", + "displayName": "Astro (View Transitions)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-astro-ssr", + "role": "internal", + "displayName": "Astro (SSR)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-astro-hybrid", + "role": "internal", + "displayName": "Astro (Hybrid)", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-feature-flags-step-angular", + "role": "internal", + "displayName": "Angular", + "description": "Evaluate the example PostHog feature flags, one per side of the app" + }, + { + "skillId": "integration-v2-identify", + "role": "internal", + "displayName": "PostHog identify step", + "description": "Identify users at login and signup" + }, + { + "skillId": "integration-v2-init-nextjs-app-router", + "role": "internal", + "displayName": "Next.js App Router", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-nextjs-pages-router", + "role": "internal", + "displayName": "Next.js Pages Router", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-react-react-router-6", + "role": "internal", + "displayName": "React Router v6", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-react-react-router-7-framework", + "role": "internal", + "displayName": "React Router v7 - Framework mode", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-react-react-router-7-data", + "role": "internal", + "displayName": "React Router v7 - Data mode", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-react-react-router-7-declarative", + "role": "internal", + "displayName": "React Router v7 - Declarative mode", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-react-vite", + "role": "internal", + "displayName": "React (Vite)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-nuxt-3-6", + "role": "internal", + "displayName": "Nuxt 3.6", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-nuxt-4", + "role": "internal", + "displayName": "Nuxt 4", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-vue-3", + "role": "internal", + "displayName": "Vue 3", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-django", + "role": "internal", + "displayName": "Django", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-flask", + "role": "internal", + "displayName": "Flask", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-fastapi", + "role": "internal", + "displayName": "FastAPI", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-react-tanstack-router-file-based", + "role": "internal", + "displayName": "React with TanStack Router (file-based)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-react-tanstack-router-code-based", + "role": "internal", + "displayName": "React with TanStack Router (code-based)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-tanstack-start", + "role": "internal", + "displayName": "TanStack Start", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-laravel", + "role": "internal", + "displayName": "Laravel", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-php", + "role": "internal", + "displayName": "PHP", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-wordpress", + "role": "internal", + "displayName": "WordPress", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-ruby-on-rails", + "role": "internal", + "displayName": "Ruby on Rails", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-android", + "role": "internal", + "displayName": "Android", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-sveltekit", + "role": "internal", + "displayName": "SvelteKit", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-python", + "role": "internal", + "displayName": "Python", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-javascript_node", + "role": "internal", + "displayName": "JavaScript Node", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-javascript_web", + "role": "internal", + "displayName": "JavaScript Web", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-ruby", + "role": "internal", + "displayName": "Ruby", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-elixir", + "role": "internal", + "displayName": "Elixir", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-java", + "role": "internal", + "displayName": "Java (Spring Boot)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-go", + "role": "internal", + "displayName": "Go", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-rust", + "role": "internal", + "displayName": "Rust", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-swift", + "role": "internal", + "displayName": "Swift (iOS/macOS)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-flutter", + "role": "internal", + "displayName": "Flutter", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-kmp", + "role": "internal", + "displayName": "Kotlin Multiplatform", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-react-native", + "role": "internal", + "displayName": "React Native", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-expo", + "role": "internal", + "displayName": "Expo", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-astro-static", + "role": "internal", + "displayName": "Astro (Static)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-astro-view-transitions", + "role": "internal", + "displayName": "Astro (View Transitions)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-astro-ssr", + "role": "internal", + "displayName": "Astro (SSR)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-astro-hybrid", + "role": "internal", + "displayName": "Astro (Hybrid)", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-init-angular", + "role": "internal", + "displayName": "Angular", + "description": "Initialize PostHog and set its environment variables" + }, + { + "skillId": "integration-v2-insight", + "role": "internal", + "displayName": "PostHog insight step", + "description": "Create PostHog insights (trends, funnels) attached to a dashboard" + }, + { + "skillId": "integration-v2-install-nextjs-app-router", + "role": "internal", + "displayName": "Next.js App Router", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-nextjs-pages-router", + "role": "internal", + "displayName": "Next.js Pages Router", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-react-react-router-6", + "role": "internal", + "displayName": "React Router v6", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-react-react-router-7-framework", + "role": "internal", + "displayName": "React Router v7 - Framework mode", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-react-react-router-7-data", + "role": "internal", + "displayName": "React Router v7 - Data mode", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-react-react-router-7-declarative", + "role": "internal", + "displayName": "React Router v7 - Declarative mode", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-react-vite", + "role": "internal", + "displayName": "React (Vite)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-nuxt-3-6", + "role": "internal", + "displayName": "Nuxt 3.6", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-nuxt-4", + "role": "internal", + "displayName": "Nuxt 4", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-vue-3", + "role": "internal", + "displayName": "Vue 3", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-django", + "role": "internal", + "displayName": "Django", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-flask", + "role": "internal", + "displayName": "Flask", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-fastapi", + "role": "internal", + "displayName": "FastAPI", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-react-tanstack-router-file-based", + "role": "internal", + "displayName": "React with TanStack Router (file-based)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-react-tanstack-router-code-based", + "role": "internal", + "displayName": "React with TanStack Router (code-based)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-tanstack-start", + "role": "internal", + "displayName": "TanStack Start", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-laravel", + "role": "internal", + "displayName": "Laravel", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-php", + "role": "internal", + "displayName": "PHP", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-wordpress", + "role": "internal", + "displayName": "WordPress", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-ruby-on-rails", + "role": "internal", + "displayName": "Ruby on Rails", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-android", + "role": "internal", + "displayName": "Android", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-sveltekit", + "role": "internal", + "displayName": "SvelteKit", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-python", + "role": "internal", + "displayName": "Python", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-javascript_node", + "role": "internal", + "displayName": "JavaScript Node", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-javascript_web", + "role": "internal", + "displayName": "JavaScript Web", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-ruby", + "role": "internal", + "displayName": "Ruby", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-elixir", + "role": "internal", + "displayName": "Elixir", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-java", + "role": "internal", + "displayName": "Java (Spring Boot)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-go", + "role": "internal", + "displayName": "Go", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-rust", + "role": "internal", + "displayName": "Rust", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-swift", + "role": "internal", + "displayName": "Swift (iOS/macOS)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-flutter", + "role": "internal", + "displayName": "Flutter", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-kmp", + "role": "internal", + "displayName": "Kotlin Multiplatform", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-react-native", + "role": "internal", + "displayName": "React Native", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-expo", + "role": "internal", + "displayName": "Expo", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-astro-static", + "role": "internal", + "displayName": "Astro (Static)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-astro-view-transitions", + "role": "internal", + "displayName": "Astro (View Transitions)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-astro-ssr", + "role": "internal", + "displayName": "Astro (SSR)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-astro-hybrid", + "role": "internal", + "displayName": "Astro (Hybrid)", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-install-angular", + "role": "internal", + "displayName": "Angular", + "description": "Install the PostHog SDK with the project's package manager" + }, + { + "skillId": "integration-v2-mcp", + "role": "internal", + "displayName": "PostHog MCP step", + "description": "How to call PostHog MCP tools (discover, inspect, then call)" + }, + { + "skillId": "integration-v2-notebook", + "role": "internal", + "displayName": "PostHog notebook step", + "description": "Mirror the setup report into a shareable PostHog notebook" + }, + { + "skillId": "integration-v2-report", + "role": "internal", + "displayName": "PostHog report step", + "description": "Publish the PostHog setup report from the run's handoffs" + }, + { + "skillId": "integration-v2-warehouse", + "role": "internal", + "displayName": "PostHog warehouse step", + "description": "Connect the detected data sources to the PostHog data warehouse" + }, + { + "skillId": "replay-vision-enable-replay-nextjs-app-router", + "role": "internal", + "displayName": "Next.js App Router", + "description": "Make session replay record for Next.js App Router" + }, + { + "skillId": "replay-vision-enable-replay-nextjs-pages-router", + "role": "internal", + "displayName": "Next.js Pages Router", + "description": "Make session replay record for Next.js Pages Router" + }, + { + "skillId": "replay-vision-enable-replay-react-react-router-6", + "role": "internal", + "displayName": "React Router v6", + "description": "Make session replay record for React Router v6" + }, + { + "skillId": "replay-vision-enable-replay-react-react-router-7-framework", + "role": "internal", + "displayName": "React Router v7 - Framework mode", + "description": "Make session replay record for React Router v7 - Framework mode" + }, + { + "skillId": "replay-vision-enable-replay-react-react-router-7-data", + "role": "internal", + "displayName": "React Router v7 - Data mode", + "description": "Make session replay record for React Router v7 - Data mode" + }, + { + "skillId": "replay-vision-enable-replay-react-react-router-7-declarative", + "role": "internal", + "displayName": "React Router v7 - Declarative mode", + "description": "Make session replay record for React Router v7 - Declarative mode" + }, + { + "skillId": "replay-vision-enable-replay-react-vite", + "role": "internal", + "displayName": "React (Vite)", + "description": "Make session replay record for React (Vite)" + }, + { + "skillId": "replay-vision-enable-replay-nuxt-3-6", + "role": "internal", + "displayName": "Nuxt 3.6", + "description": "Make session replay record for Nuxt 3.6" + }, + { + "skillId": "replay-vision-enable-replay-nuxt-4", + "role": "internal", + "displayName": "Nuxt 4", + "description": "Make session replay record for Nuxt 4" + }, + { + "skillId": "replay-vision-enable-replay-vue-3", + "role": "internal", + "displayName": "Vue 3", + "description": "Make session replay record for Vue 3" + }, + { + "skillId": "replay-vision-enable-replay-django", + "role": "internal", + "displayName": "Django", + "description": "Make session replay record for Django" + }, + { + "skillId": "replay-vision-enable-replay-flask", + "role": "internal", + "displayName": "Flask", + "description": "Make session replay record for Flask" + }, + { + "skillId": "replay-vision-enable-replay-fastapi", + "role": "internal", + "displayName": "FastAPI", + "description": "Make session replay record for FastAPI" + }, + { + "skillId": "replay-vision-enable-replay-react-tanstack-router-file-based", + "role": "internal", + "displayName": "React with TanStack Router (file-based)", + "description": "Make session replay record for React with TanStack Router (file-based)" + }, + { + "skillId": "replay-vision-enable-replay-react-tanstack-router-code-based", + "role": "internal", + "displayName": "React with TanStack Router (code-based)", + "description": "Make session replay record for React with TanStack Router (code-based)" + }, + { + "skillId": "replay-vision-enable-replay-tanstack-start", + "role": "internal", + "displayName": "TanStack Start", + "description": "Make session replay record for TanStack Start" + }, + { + "skillId": "replay-vision-enable-replay-laravel", + "role": "internal", + "displayName": "Laravel", + "description": "Make session replay record for Laravel" + }, + { + "skillId": "replay-vision-enable-replay-php", + "role": "internal", + "displayName": "PHP", + "description": "Make session replay record for PHP" + }, + { + "skillId": "replay-vision-enable-replay-wordpress", + "role": "internal", + "displayName": "WordPress", + "description": "Make session replay record for WordPress" + }, + { + "skillId": "replay-vision-enable-replay-ruby-on-rails", + "role": "internal", + "displayName": "Ruby on Rails", + "description": "Make session replay record for Ruby on Rails" + }, + { + "skillId": "replay-vision-enable-replay-android", + "role": "internal", + "displayName": "Android", + "description": "Make session replay record for Android" + }, + { + "skillId": "replay-vision-enable-replay-sveltekit", + "role": "internal", + "displayName": "SvelteKit", + "description": "Make session replay record for SvelteKit" + }, + { + "skillId": "replay-vision-enable-replay-python", + "role": "internal", + "displayName": "Python", + "description": "Make session replay record for Python" + }, + { + "skillId": "replay-vision-enable-replay-javascript_node", + "role": "internal", + "displayName": "JavaScript Node", + "description": "Make session replay record for JavaScript Node" + }, + { + "skillId": "replay-vision-enable-replay-javascript_web", + "role": "internal", + "displayName": "JavaScript Web", + "description": "Make session replay record for JavaScript Web" + }, + { + "skillId": "replay-vision-enable-replay-ruby", + "role": "internal", + "displayName": "Ruby", + "description": "Make session replay record for Ruby" + }, + { + "skillId": "replay-vision-enable-replay-elixir", + "role": "internal", + "displayName": "Elixir", + "description": "Make session replay record for Elixir" + }, + { + "skillId": "replay-vision-enable-replay-java", + "role": "internal", + "displayName": "Java (Spring Boot)", + "description": "Make session replay record for Java (Spring Boot)" + }, + { + "skillId": "replay-vision-enable-replay-go", + "role": "internal", + "displayName": "Go", + "description": "Make session replay record for Go" + }, + { + "skillId": "replay-vision-enable-replay-rust", + "role": "internal", + "displayName": "Rust", + "description": "Make session replay record for Rust" + }, + { + "skillId": "replay-vision-enable-replay-swift", + "role": "internal", + "displayName": "Swift (iOS/macOS)", + "description": "Make session replay record for Swift (iOS/macOS)" + }, + { + "skillId": "replay-vision-enable-replay-flutter", + "role": "internal", + "displayName": "Flutter", + "description": "Make session replay record for Flutter" + }, + { + "skillId": "replay-vision-enable-replay-kmp", + "role": "internal", + "displayName": "Kotlin Multiplatform", + "description": "Make session replay record for Kotlin Multiplatform" + }, + { + "skillId": "replay-vision-enable-replay-react-native", + "role": "internal", + "displayName": "React Native", + "description": "Make session replay record for React Native" + }, + { + "skillId": "replay-vision-enable-replay-expo", + "role": "internal", + "displayName": "Expo", + "description": "Make session replay record for Expo" + }, + { + "skillId": "replay-vision-enable-replay-astro-static", + "role": "internal", + "displayName": "Astro (Static)", + "description": "Make session replay record for Astro (Static)" + }, + { + "skillId": "replay-vision-enable-replay-astro-view-transitions", + "role": "internal", + "displayName": "Astro (View Transitions)", + "description": "Make session replay record for Astro (View Transitions)" + }, + { + "skillId": "replay-vision-enable-replay-astro-ssr", + "role": "internal", + "displayName": "Astro (SSR)", + "description": "Make session replay record for Astro (SSR)" + }, + { + "skillId": "replay-vision-enable-replay-astro-hybrid", + "role": "internal", + "displayName": "Astro (Hybrid)", + "description": "Make session replay record for Astro (Hybrid)" + }, + { + "skillId": "replay-vision-enable-replay-angular", + "role": "internal", + "displayName": "Angular", + "description": "Make session replay record for Angular" + }, + { + "skillId": "replay-vision-scanner-broken-experiences", + "role": "internal", + "displayName": "Breakage scanner", + "description": "The breakage monitor brief for Replay vision" + }, + { + "skillId": "replay-vision-scanner-session-summaries", + "role": "internal", + "displayName": "Summary scanner", + "description": "The summary scanner brief for Replay vision" + }, + { + "skillId": "replay-vision-scanner-user-frustration", + "role": "internal", + "displayName": "Frustration scanner", + "description": "The frustration monitor brief for Replay vision" + }, + { + "skillId": "replay-vision-scanners-core", + "role": "internal", + "displayName": "Replay vision scanner mechanics", + "description": "Shared mechanics for creating Replay vision scanners" + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index ee34a5c31..d190d3613 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,8 @@ "wizard-ci-explore": "tsx scripts/wizard-ci-explore.no-jest.ts", "wizard-ci-replay": "tsx scripts/tui-replay.no-jest.ts", "decisions-detect": "tsx scripts/decisions-detect.no-jest.ts", - "check:decisions-bundle": "tsx scripts/check-decisions-bundle.no-jest.ts" + "check:decisions-bundle": "tsx scripts/check-decisions-bundle.no-jest.ts", + "record:context-mill-fixtures": "tsx scripts/record-context-mill-fixtures.no-jest.ts" }, "lint-staged": { ".claude/settings.json": "sh -c 'printf \"\\n\\033[31mDo not commit .claude/settings.json — use .claude/settings.local.json (gitignored).\\nUnstage with: git restore --staged .claude/settings.json\\033[0m\\n\\n\" >&2 && exit 1'", diff --git a/scripts/record-context-mill-fixtures.no-jest.ts b/scripts/record-context-mill-fixtures.no-jest.ts new file mode 100644 index 000000000..0b244b9fe --- /dev/null +++ b/scripts/record-context-mill-fixtures.no-jest.ts @@ -0,0 +1,64 @@ +/** + * Records a context-mill release as the fixtures the behavior checks compare + * against: the skill menu, the agent menu and every agent prompt it lists. + * Run with `pnpm record:context-mill-fixtures [base-url]`; commit the result on + * its own, with the reason, since a changed fixture changes what "unchanged" means. + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const BASE_URL = + process.argv[2] ?? + 'https://github.com/PostHog/context-mill/releases/latest/download'; +const OUT_DIR = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '..', + 'fixtures', + 'context-mill', +); + +type AgentMenu = { + agents: { id: string; flow?: string; downloadUrl: string }[]; +}; + +async function fetchText(url: string): Promise { + const res = await fetch(url, { redirect: 'follow' }); + if (!res.ok) throw new Error(`${url}: HTTP ${res.status}`); + return res.text(); +} + +async function main(): Promise { + const skillMenu = await fetchText(`${BASE_URL}/skill-menu.json`); + const agentMenuText = await fetchText(`${BASE_URL}/agent-menu.json`); + const agentMenu = JSON.parse(agentMenuText) as AgentMenu; + + fs.rmSync(OUT_DIR, { recursive: true, force: true }); + fs.mkdirSync(path.join(OUT_DIR, 'agents'), { recursive: true }); + fs.writeFileSync(path.join(OUT_DIR, 'skill-menu.json'), skillMenu); + fs.writeFileSync(path.join(OUT_DIR, 'agent-menu.json'), agentMenuText); + + for (const entry of agentMenu.agents) { + const flow = entry.flow ?? 'unscoped'; + const dir = path.join(OUT_DIR, 'agents', flow); + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync( + path.join(dir, `${entry.id}.md`), + await fetchText(entry.downloadUrl), + ); + } + + const version = (JSON.parse(skillMenu) as { buildVersion?: string }) + .buildVersion; + console.log( + `Recorded context-mill ${version ?? 'unknown version'}: ${ + agentMenu.agents.length + } agent prompts into ${path.relative(process.cwd(), OUT_DIR)}`, + ); +} + +main().catch((error: unknown) => { + console.error(error); + process.exit(1); +}); diff --git a/src/agent/runner/sequence/README.md b/src/agent/runner/sequence/README.md index c35a98cb9..a031deeda 100644 --- a/src/agent/runner/sequence/README.md +++ b/src/agent/runner/sequence/README.md @@ -44,6 +44,13 @@ frontmatter contract rather than copying an old manifest example: required prompt compatibility. - `skills`, `allowedTools`, and `disallowedTools` shape the task's capabilities. Inspect the selected harness's effective tool inventory. + [skill-picks.ts](orchestrator/skill-picks.ts) turns each skill id into the + menu id to install. The exact-match pick (the id itself, else its group's + variant for the run's framework) decides; the criteria resolver in + `@shared/skill-resolution` picks beside it from menu tags and the run's + project traits (`RunConfig.traitTags`), and each disagreement is logged as + `orchestrator skill resolver disagreement`. With `wizard-agent-dag` on, the + criteria pick decides and the exact match is its fallback. - `dependsOn` has different consumers: planner-enqueued tasks use actual task IDs supplied to `enqueue_task`, while runner-seeded tasks resolve declared task types after planning. It is not a universal automatic graph built from diff --git a/src/agent/runner/sequence/orchestrator/__tests__/delivered-report.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/delivered-report.test.ts index 748f9dfe3..f4c4dd9eb 100644 --- a/src/agent/runner/sequence/orchestrator/__tests__/delivered-report.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/delivered-report.test.ts @@ -24,6 +24,7 @@ vi.mock('../../../switchboard', async () => { resolveHarness: () => ({ harness: 'pi', model: [...VALID_MODELS][0] }), resolveStageOverrides: () => ({}), areSeededTasksEnabled: () => false, + isAgentDagEnabled: () => false, getHarness: () => ({ runTask: (inputs: unknown) => harnessRun(inputs) }), }; }); diff --git a/src/agent/runner/sequence/orchestrator/__tests__/skill-equivalence.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/skill-equivalence.test.ts new file mode 100644 index 000000000..810c62599 --- /dev/null +++ b/src/agent/runner/sequence/orchestrator/__tests__/skill-equivalence.test.ts @@ -0,0 +1,71 @@ +import fs from 'fs'; +import path from 'path'; +import { describe, expect, it, vi } from 'vitest'; +import { expandBundleEntry, type SkillMenu } from '@shared/skill-menu'; +import { parseAgentPrompt } from '../../../../agent-prompt-loader'; +import { createSkillPicker, resolveSkillVariantId } from '../skill-picks'; + +vi.mock('@utils/analytics', () => ({ + analytics: { wizardCapture: vi.fn() }, +})); + +const FIXTURES = path.resolve(__dirname, '../../../../../../fixtures'); + +// The recorded release, plus a context-mill build when CONTEXT_MILL_MENU names its skill-menu.json. +const MENUS: Array<[string, string]> = [ + ['recorded release', path.join(FIXTURES, 'context-mill', 'skill-menu.json')], + ...(process.env.CONTEXT_MILL_MENU + ? [['CONTEXT_MILL_MENU', process.env.CONTEXT_MILL_MENU] as [string, string]] + : []), +]; + +/** Every skill id an agent prompt names, plus the framework reference. */ +function promptSkillIds(): string[] { + const root = path.join(FIXTURES, 'context-mill', 'agents'); + const ids = new Set(['integration']); + for (const flow of fs.readdirSync(root)) { + for (const file of fs.readdirSync(path.join(root, flow))) { + const text = fs.readFileSync(path.join(root, flow, file), 'utf8'); + for (const id of parseAgentPrompt(text, file).skills) ids.add(id); + } + } + return [...ids].sort(); +} + +describe.each(MENUS)('criteria resolver equivalence (%s)', (_, file) => { + const menu = JSON.parse(fs.readFileSync(file, 'utf8')) as SkillMenu; + const entries = Object.values(menu.categories) + .flat() + .flatMap(expandBundleEntry); + const frameworks = [ + undefined, + ...new Set(entries.flatMap((e) => (e.framework ? [e.framework] : []))), + ]; + + it('picks what the exact-match resolver picks, for every prompt skill and framework', () => { + const disagreements: string[] = []; + for (const framework of frameworks) { + const picker = createSkillPicker({ + entries, + framework, + traits: {}, + useCriteria: true, + }); + for (const skillId of promptSkillIds()) { + const legacy = resolveSkillVariantId(entries, skillId, framework); + const judged = + skillId === 'integration' && framework + ? picker.reference() + : picker.pick('task', skillId); + if (judged !== legacy) { + disagreements.push( + `${skillId} @ ${framework ?? 'none'}: ${legacy ?? 'none'} vs ${ + judged ?? 'none' + }`, + ); + } + } + } + expect(disagreements).toEqual([]); + }); +}); diff --git a/src/agent/runner/sequence/orchestrator/orchestrator-runner.ts b/src/agent/runner/sequence/orchestrator/orchestrator-runner.ts index 846174a72..76e5a5d87 100644 --- a/src/agent/runner/sequence/orchestrator/orchestrator-runner.ts +++ b/src/agent/runner/sequence/orchestrator/orchestrator-runner.ts @@ -61,6 +61,7 @@ import { createAskBridge } from '../../shared/ask'; import { areSeededTasksEnabled, getHarness, + isAgentDagEnabled, resolveHarness, resolveStageOverrides, type HarnessPick, @@ -84,6 +85,7 @@ import { import { RunMetrics } from './run-metrics'; import { dependencyClosure, uncoveredBySink } from './queue-tools'; import { deferSeededTasks } from './seeded-deps'; +import { createSkillPicker } from './skill-picks'; import { LONGER_ASK_TIMEOUT_MS, shouldDisableAsk } from '@shared/ask-policy'; import { agentRunTools, @@ -226,31 +228,7 @@ async function fetchSkillMenuEntries( return Object.values(menu.categories).flat(); } -/** Menu id for a bare skill id + framework via the menu's declared group/framework/default fields; undefined when nothing matches. */ -export function resolveSkillVariantId( - entries: readonly SkillEntry[], - skillId: string, - framework: string | undefined, -): string | undefined { - if (entries.some((e) => e.id === skillId)) return skillId; - if (!framework) return undefined; - const family = entries.filter( - (e) => e.group === skillId && e.framework === framework, - ); - return (family.find((e) => e.default) ?? family[0])?.id; -} - -/** - * The framework reference is the full `integration` skill. `input.skillId` is - * the bare framework (e.g. `django`), but the skill menu ids it as - * `integration-`. - */ -function resolveReferenceSkillId( - entries: readonly SkillEntry[], - framework: string, -): string | undefined { - return resolveSkillVariantId(entries, 'integration', framework); -} +export { resolveSkillVariantId } from './skill-picks'; /** * How long an optional step's notice waits for an answer. @@ -801,9 +779,14 @@ async function executeOrchestrator( // (agent-skill commands like replay-vision) would otherwise leak that id in // here as a bogus framework after the caller overwrites the detect result. const framework = input.integration ?? input.skillId ?? undefined; - const referenceSkillId = framework - ? resolveReferenceSkillId(menuSkillEntries, framework) - : undefined; + const skills = createSkillPicker({ + entries: menuSkillEntries, + framework, + traits: config.traitTags?.() ?? {}, + useCriteria: isAgentDagEnabled(boot.wizardFlags), + }); + // The framework reference is the full `integration` skill, which the menu ids as `integration-`. + const referenceSkillId = skills.reference(); if (referenceSkillId) { const ref = await installSkillById( referenceSkillId, @@ -840,9 +823,7 @@ async function executeOrchestrator( const missingVariants: string[] = []; for (const type of registry.types) { for (const skillId of registry.get(type)?.skills ?? []) { - if (resolveSkillVariantId(menuSkillEntries, skillId, framework)) { - continue; - } + if (skills.pick(type, skillId)) continue; missingVariants.push(`${type}/${skillId}`); logToFile( `[orchestrator] no skill variant type=${type} skill=${skillId} framework=${ @@ -1227,11 +1208,7 @@ async function executeOrchestrator( // Agent prompts name the bare step-skill (`integration-v2-install`); // SDK-divergent steps ship per-framework variants, so resolve against // the menu with the session's framework before installing. - const variantId = resolveSkillVariantId( - menuSkillEntries, - skillId, - framework, - ); + const variantId = skills.pick(task.type, skillId); if (!variantId) { logToFile( `[orchestrator] no skill variant type=${ diff --git a/src/agent/runner/sequence/orchestrator/skill-picks.ts b/src/agent/runner/sequence/orchestrator/skill-picks.ts new file mode 100644 index 000000000..c600a4e91 --- /dev/null +++ b/src/agent/runner/sequence/orchestrator/skill-picks.ts @@ -0,0 +1,100 @@ +/** + * Which skill each orchestrator task installs. The exact-match resolver + * decides; the criteria resolver runs beside it and every disagreement is + * logged, until `wizard-agent-dag` lets it decide, with the old pick as the + * fallback. + */ +import type { SkillEntry } from '@shared/skill-menu'; +import { + frameworkTag, + legacySkillCriteria, + resolveSkill, + type SkillCriteria, + type TraitTags, +} from '@shared/skill-resolution'; +import { analytics } from '@utils/analytics'; +import { logToFile } from '@utils/debug'; + +/** Menu id for a bare skill id + framework via the menu's declared group/framework/default fields; undefined when nothing matches. */ +export function resolveSkillVariantId( + entries: readonly SkillEntry[], + skillId: string, + framework: string | undefined, +): string | undefined { + if (entries.some((e) => e.id === skillId)) return skillId; + if (!framework) return undefined; + const family = entries.filter( + (e) => e.group === skillId && e.framework === framework, + ); + return (family.find((e) => e.default) ?? family[0])?.id; +} + +/** The framework reference skill's family. */ +const REFERENCE_SKILL = 'integration'; + +export interface SkillPicker { + /** The menu id a task's frontmatter skill id installs, or undefined when none matches. */ + pick(taskType: string, skillId: string): string | undefined; + /** The framework's reference integration skill. */ + reference(): string | undefined; +} + +export function createSkillPicker(opts: { + entries: readonly SkillEntry[]; + framework: string | undefined; + traits: TraitTags; + /** The criteria resolver decides (`wizard-agent-dag` on); the exact-match pick is its fallback. */ + useCriteria: boolean; +}): SkillPicker { + const { entries, framework, useCriteria } = opts; + const traits: TraitTags = framework + ? { ...opts.traits, framework: [frameworkTag(framework)] } + : opts.traits; + const reported = new Set(); + + const decide = ( + taskType: string, + skillId: string, + criteria: SkillCriteria, + ): string | undefined => { + const legacy = resolveSkillVariantId(entries, skillId, framework); + let judged: string | undefined; + try { + judged = resolveSkill(entries, criteria, traits)?.id; + } catch (error) { + logToFile(`[orchestrator] criteria resolver threw: ${String(error)}`); + return legacy; + } + const key = `${taskType}/${skillId}`; + if (judged !== legacy && !reported.has(key)) { + reported.add(key); + logToFile( + `[orchestrator] skill resolver disagreement ${key}: legacy=${ + legacy ?? 'none' + } criteria=${judged ?? 'none'} traits=${JSON.stringify(traits)}`, + ); + analytics.wizardCapture('orchestrator skill resolver disagreement', { + task_type: taskType, + skill: skillId, + framework, + legacy_skill: legacy ?? null, + criteria_skill: judged ?? null, + deciding: useCriteria ? 'criteria' : 'legacy', + }); + } + return useCriteria ? judged ?? legacy : legacy; + }; + + return { + pick: (taskType, skillId) => + decide(taskType, skillId, legacySkillCriteria(entries, skillId)), + reference: () => + framework + ? decide( + 'reference', + REFERENCE_SKILL, + legacySkillCriteria(entries, REFERENCE_SKILL), + ) + : undefined, + }; +} diff --git a/src/agent/runner/shared/types.ts b/src/agent/runner/shared/types.ts index d59e70666..23d07e408 100644 --- a/src/agent/runner/shared/types.ts +++ b/src/agent/runner/shared/types.ts @@ -16,6 +16,7 @@ import type { PackageManagerDetector } from '@utils/package-manager'; import type { ApiProject, ApiUser } from '@shared/api'; import type { Harness, Integration, Sequence } from '@shared/constants'; import type { ErrorCode } from '@shared/errors'; +import type { TraitTags } from '@shared/skill-resolution'; import type { LLMProvider } from '@posthog/warlock'; import type { AgentInteraction, ProgressEmitter } from '../../progress'; import type { EffortLevel } from '../switchboard/models'; @@ -217,6 +218,8 @@ export interface ResolvedRunConfig { seedTasks?: () => SeedTaskEntry[]; /** Detected facts about the project, one line each, read when the orchestrator starts. */ projectFacts?: () => readonly string[]; + /** The run's project traits as tags, which skill criteria require or prefer. Read when the orchestrator starts. */ + traitTags?: () => TraitTags; /** Completion hooks, bound by the caller. */ hooks?: RunHooks; scanReport?: 'flush' | 'defer'; // defer leaves the scan report to the outer run diff --git a/src/agent/runner/switchboard/flags/agent-dag.ts b/src/agent/runner/switchboard/flags/agent-dag.ts new file mode 100644 index 000000000..7d09de29c --- /dev/null +++ b/src/agent/runner/switchboard/flags/agent-dag.ts @@ -0,0 +1,7 @@ +/** The agent DAG switch: one boolean flag whose on path must change nothing a run does. */ +import { WIZARD_AGENT_DAG_FLAG_KEY } from '@shared/constants'; + +/** Whether the criteria resolver decides each orchestrator task's skills. Off, it runs in shadow beside the exact-match pick. */ +export function isAgentDagEnabled(flags: Record = {}): boolean { + return flags[WIZARD_AGENT_DAG_FLAG_KEY] === 'true'; +} diff --git a/src/agent/runner/switchboard/flags/index.ts b/src/agent/runner/switchboard/flags/index.ts index 3d9d4b9da..94135d94a 100644 --- a/src/agent/runner/switchboard/flags/index.ts +++ b/src/agent/runner/switchboard/flags/index.ts @@ -74,6 +74,7 @@ export function resolveStageOverrides( } export { isOrchestratorEnabled, areSeededTasksEnabled } from './orchestrator'; +export { isAgentDagEnabled } from './agent-dag'; export type { ConfigFlag, FlagRoute, diff --git a/src/agent/runner/switchboard/index.ts b/src/agent/runner/switchboard/index.ts index 5eccdf41f..eda40486f 100644 --- a/src/agent/runner/switchboard/index.ts +++ b/src/agent/runner/switchboard/index.ts @@ -143,5 +143,6 @@ export { export { isOrchestratorEnabled, areSeededTasksEnabled, + isAgentDagEnabled, resolveStageOverrides, } from './flags'; diff --git a/src/programs/program-runner/run-program.ts b/src/programs/program-runner/run-program.ts index 5a9ee54a8..04cd5e3d0 100644 --- a/src/programs/program-runner/run-program.ts +++ b/src/programs/program-runner/run-program.ts @@ -44,6 +44,7 @@ import { type ResolvedProgramCredentials, } from './credentials'; import { reportCodebaseScan } from '@services/codebase-scan'; +import { getProjectTraits, traitsToSkillTags } from '@services/project-traits'; import { IS_PRODUCTION_BUILD } from '@env'; import type { QuestionKey } from '@services/detection/decisions'; import { logIn } from './login'; @@ -431,6 +432,7 @@ async function invokeProgram( planned.config.decisions ?? [], ) : undefined, + traitTags: () => traitsToSkillTags(getProjectTraits(session())), hooks: sessionHooks(agentRun, session, (outcomes) => { if (scoped) scoped.frameworkContext[TASK_OUTCOMES_KEY] = outcomes; else store.setFrameworkContext(TASK_OUTCOMES_KEY, outcomes); diff --git a/src/services/README.md b/src/services/README.md index 94ac2773a..ff82114ca 100644 --- a/src/services/README.md +++ b/src/services/README.md @@ -32,6 +32,7 @@ folder, never a file inside one: | `@services/frameworks` | `FRAMEWORK_REGISTRY` and each framework's `FrameworkConfig` | | `@services/codebase-scan` | The codebase scan and its report | | `@services/warehouse-sources` | The warehouse tool catalog and source detection | +| `@services/project-traits` | The run's project traits from static detection (`getProjectTraits`, `traitsFromDetectors`) and their skill tags (`traitsToSkillTags`) | Each entry's `index.ts` re-exports what code outside the service uses, and nothing else. Add to it when a program needs another export. diff --git a/src/services/project-traits/__tests__/traits.test.ts b/src/services/project-traits/__tests__/traits.test.ts new file mode 100644 index 000000000..070adf29d --- /dev/null +++ b/src/services/project-traits/__tests__/traits.test.ts @@ -0,0 +1,64 @@ +import { describe, expect, it } from 'vitest'; +import { DiscoveredFeature } from '@shared/discovered-feature'; +import { Integration } from '@shared/constants'; +import { + getProjectTraits, + traitsFromDetectors, + traitsToSkillTags, +} from '@services/project-traits/traits'; + +describe('traitsFromDetectors', () => { + it('reads the framework from detection', () => { + expect( + traitsFromDetectors({ + integration: Integration.nextjs, + discoveredFeatures: [], + }), + ).toEqual({ framework: { value: 'nextjs', source: 'static' } }); + }); + + it('leaves a trait no detector settles absent', () => { + expect( + traitsFromDetectors({ integration: null, discoveredFeatures: [] }), + ).toEqual({}); + }); + + it('says yes to LLM calls when an LLM SDK is a dependency, and never no', () => { + expect( + traitsFromDetectors({ + integration: null, + discoveredFeatures: [DiscoveredFeature.LLM], + }).callsLlmApi, + ).toEqual({ value: 'yes', source: 'static' }); + expect( + traitsFromDetectors({ + integration: null, + discoveredFeatures: [DiscoveredFeature.Stripe], + }).callsLlmApi, + ).toBeUndefined(); + }); + + it('gives every program in a run the same traits', () => { + const session = { + integration: Integration.django, + discoveredFeatures: [DiscoveredFeature.LLM], + }; + expect(getProjectTraits(session)).toEqual(traitsFromDetectors(session)); + }); +}); + +describe('traitsToSkillTags', () => { + it('maps the framework to its prefixed tag', () => { + expect( + traitsToSkillTags({ + framework: { value: 'javascript_web', source: 'static' }, + }), + ).toEqual({ framework: ['framework:javascript_web'] }); + }); + + it('gives a trait without a skill tag no tags', () => { + expect( + traitsToSkillTags({ callsLlmApi: { value: 'yes', source: 'static' } }), + ).toEqual({}); + }); +}); diff --git a/src/services/project-traits/index.ts b/src/services/project-traits/index.ts new file mode 100644 index 000000000..f5206da74 --- /dev/null +++ b/src/services/project-traits/index.ts @@ -0,0 +1,9 @@ +export { + getProjectTraits, + traitsFromDetectors, + traitsToSkillTags, + type DetectionResults, + type ProjectTraits, + type Trait, + type TraitName, +} from './traits'; diff --git a/src/services/project-traits/traits.ts b/src/services/project-traits/traits.ts new file mode 100644 index 000000000..0f2039e78 --- /dev/null +++ b/src/services/project-traits/traits.ts @@ -0,0 +1,52 @@ +/** + * The run's project traits: what detection read from the user's codebase, as + * skill criteria and flow conditions see it. Traits describe the code, never + * the person running the wizard. Static detection is the only source, and + * context-mill never sees a trait name, only the tags `traitsToSkillTags` maps + * values to. + */ + +import { DiscoveredFeature } from '@shared/discovered-feature'; +import { frameworkTag, type TraitTags } from '@shared/skill-resolution'; +import type { ProgramSession } from '@programs/program-contract'; + +export type TraitName = 'framework' | 'callsLlmApi'; + +/** A predicate trait's value is `yes` or `no`; the framework's is its integration id. */ +export type Trait = { + value: string; + source: 'static'; +}; + +export type ProjectTraits = Partial>; + +/** What static detection stored on the session that a trait reads. */ +export type DetectionResults = Pick< + ProgramSession, + 'integration' | 'discoveredFeatures' +>; + +/** The traits static detection supports. A trait no detector settles is absent. */ +export function traitsFromDetectors(scan: DetectionResults): ProjectTraits { + const traits: ProjectTraits = {}; + if (scan.integration) { + traits.framework = { value: scan.integration, source: 'static' }; + } + // An LLM SDK in the dependencies says the app calls one; no SDK proves nothing, so never `no`. + if (scan.discoveredFeatures.includes(DiscoveredFeature.LLM)) { + traits.callsLlmApi = { value: 'yes', source: 'static' }; + } + return traits; +} + +/** The run's traits. Every program in a run reads the same ones. */ +export function getProjectTraits(session: DetectionResults): ProjectTraits { + return traitsFromDetectors(session); +} + +/** Each trait value as the tags skill criteria require or prefer. Only the framework has a skill tag today. */ +export function traitsToSkillTags(traits: ProjectTraits): TraitTags { + return traits.framework + ? { framework: [frameworkTag(traits.framework.value)] } + : {}; +} diff --git a/src/shared/__tests__/skill-menu.test.ts b/src/shared/__tests__/skill-menu.test.ts index bc5884f0d..2a8fdd635 100644 --- a/src/shared/__tests__/skill-menu.test.ts +++ b/src/shared/__tests__/skill-menu.test.ts @@ -1,4 +1,7 @@ import { fetchSkillMenu, type SkillMenu } from '@shared/skill-menu'; +import { analytics } from '@utils/analytics'; + +vi.mock('@utils/analytics', () => ({ analytics: { setTag: vi.fn() } })); describe('fetchSkillMenu', () => { const noSleep = () => Promise.resolve(); @@ -87,4 +90,54 @@ describe('fetchSkillMenu', () => { }, ]); }); + + it("gives each bundle variant the bundle's title and description, keeping its own tags", async () => { + const bundled: SkillMenu = { + categories: { + integration: [ + { + id: 'capture', + name: 'Capture', + group: 'capture', + bundle: true, + title: 'Capture step', + description: 'Instrument the planned events', + downloadUrl: 'http://localhost:8765/capture.json', + variants: [ + { + id: 'capture-rails', + framework: 'rails', + tags: ['framework:rails', 'capture'], + }, + { id: 'capture-react', framework: 'react', title: 'React' }, + ], + }, + ], + }, + }; + + const result = await fetchSkillMenu('http://localhost:8765', { + fetchImpl: respond(bundled) as any, + sleepImpl: noSleep, + }); + + const [rails, react] = result?.categories.integration ?? []; + expect(rails).toMatchObject({ + title: 'Capture step', + description: 'Instrument the planned events', + tags: ['framework:rails', 'capture'], + }); + expect(react.title).toBe('React'); + }); + + it('tags later events with the context-mill release that built the menu', async () => { + await fetchSkillMenu('http://localhost:8765', { + fetchImpl: respond({ ...menu, buildVersion: '1.60.0' }) as any, + sleepImpl: noSleep, + }); + expect(analytics.setTag).toHaveBeenCalledWith( + 'context_mill_version', + '1.60.0', + ); + }); }); diff --git a/src/shared/constants.ts b/src/shared/constants.ts index 9975c0daf..3e517111f 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -335,6 +335,8 @@ export const WIZARD_ORCHESTRATOR_SEEDED_TASKS_FLAG_KEY = export const WIZARD_DEFAULT_AIO_LOGS_FLAG_KEY = 'wizard-default-aio-logs'; /** Boolean flag: true runs the Decisions judgment service in shadow (ask and log, never act). */ export const WIZARD_DECISIONS_DETECTION_FLAG_KEY = 'wizard-decisions-detection'; +/** Boolean flag: true lets the criteria resolver pick each orchestrator task's skills from the run's project traits. Off, it runs in shadow beside the exact-match pick; either way the picks must match. */ +export const WIZARD_AGENT_DAG_FLAG_KEY = 'wizard-agent-dag'; // Reading a flag enters this run into that flag's experiment, so a closed set — not a // `wizard-` prefix anyone can name into — decides what a run evaluates. Test-pinned exhaustive. export const WIZARD_FLAG_KEYS = [ @@ -346,6 +348,7 @@ export const WIZARD_FLAG_KEYS = [ WIZARD_BASIC_INTEGRATION_AGENTIC_DETECTION_FLAG_KEY, WIZARD_DEFAULT_AIO_LOGS_FLAG_KEY, WIZARD_DECISIONS_DETECTION_FLAG_KEY, + WIZARD_AGENT_DAG_FLAG_KEY, ] as const; /** User-Agent for wizard HTTP requests and MCP server identification. */ export const WIZARD_USER_AGENT = `posthog/wizard; version: ${VERSION}`; diff --git a/src/shared/skill-menu.ts b/src/shared/skill-menu.ts index 41430e38c..2903cd2e5 100644 --- a/src/shared/skill-menu.ts +++ b/src/shared/skill-menu.ts @@ -5,6 +5,7 @@ * one fetch, so it lives in shared and depends on nothing in the agent. */ +import { analytics } from '@utils/analytics'; import { logToFile } from '@utils/debug'; import { fetchWithRetry, type RetryOpts } from '@shared/fetch-retry'; @@ -20,8 +21,24 @@ export type SkillEntry = { default?: boolean; /** This entry's download is a bundle JSON of every variant, not a single skill's zip. */ bundle?: boolean; + /** Human name for the skill; menus older than the criteria resolver omit it. */ + title?: string; + /** What the skill covers, for an agent choosing from a narrowed menu. */ + description?: string; + /** Tags the criteria resolver matches; see `@shared/skill-resolution`. */ + tags?: string[]; /** Menu-only: the variants inside a bundle, expanded into entries of their own on fetch. */ - variants?: { id: string; framework?: string; default?: boolean }[]; + variants?: SkillVariant[]; +}; + +/** One variant inside a bundle entry. */ +export type SkillVariant = { + id: string; + framework?: string; + default?: boolean; + title?: string; + description?: string; + tags?: string[]; }; /** @@ -41,6 +58,8 @@ export type CliEntry = { }; export interface SkillMenu { + /** The context-mill release that built the menu (`dev` for a local build). */ + buildVersion?: string; categories: Record; /** * Skills exposed as CLI commands. Optional because context-mill releases @@ -58,6 +77,10 @@ export function expandBundleEntry(entry: SkillEntry): SkillEntry[] { group: entry.group, bundle: true, downloadUrl: entry.downloadUrl, + ...(entry.title && !variant.title ? { title: entry.title } : {}), + ...(entry.description && !variant.description + ? { description: entry.description } + : {}), })); } @@ -77,6 +100,10 @@ export async function fetchSkillMenu( for (const [category, entries] of Object.entries(data.categories)) { data.categories[category] = entries.flatMap(expandBundleEntry); } + // Every later event, the terminal one included, says which release the run's skills came from. + if (data.buildVersion) { + analytics.setTag('context_mill_version', data.buildVersion); + } logToFile( `fetchSkillMenu: loaded (${ Object.keys(data.categories).length diff --git a/src/shared/skill-resolution.ts b/src/shared/skill-resolution.ts new file mode 100644 index 000000000..81f99e530 --- /dev/null +++ b/src/shared/skill-resolution.ts @@ -0,0 +1,109 @@ +/** + * Skill resolution by criteria. A task names the skills it needs by tags plus + * the run's traits, by explicit id, or as a narrowed menu its agent picks from. + * Context-mill owns each skill's tags; the wizard owns the criteria and traits. + */ + +import type { SkillEntry } from './skill-menu'; + +/** The run's trait values as tags, keyed by trait name (e.g. `framework` → `['nextjs']`). */ +export type TraitTags = Readonly>; + +/** How a task names one skill. */ +export type SkillCriteria = + | { + /** Keep only skills that carry every one of these tags. */ + tags: readonly string[]; + /** Traits whose tags a skill must carry too; a run without the trait matches nothing. */ + require?: readonly string[]; + /** Traits whose tags rank the matches; a tag no skill carries changes nothing. */ + prefer?: readonly string[]; + /** No match fails the preflight rather than running the task without the skill. */ + required?: boolean; + } + | { id: string } + | { choose: { tags: readonly string[] } }; + +/** The tag that breaks a ranking tie. */ +export const DEFAULT_SKILL_TAG = 'default'; + +/** The tag a skill carries for the framework it serves; content tags such as `python` only describe it. */ +export function frameworkTag(framework: string): string { + return `framework:${framework}`; +} + +/** + * A skill's tags, plus its `group`, `framework` and `default` fields as tags, + * so a menu published before tags resolves the same as one with them. + */ +export function skillTags(entry: SkillEntry): ReadonlySet { + const tags = new Set(entry.tags ?? []); + if (entry.group) tags.add(entry.group); + if (entry.framework) tags.add(frameworkTag(entry.framework)); + if (entry.default) tags.add(DEFAULT_SKILL_TAG); + return tags; +} + +/** The skills carrying every tag, in menu order. The menu an agent chooses from. */ +export function skillsWithTags( + entries: readonly SkillEntry[], + tags: readonly string[], +): SkillEntry[] { + return entries.filter((entry) => { + const carried = skillTags(entry); + return tags.every((tag) => carried.has(tag)); + }); +} + +/** + * The skill criteria pick, or undefined when none matches or the agent picks + * (`choose`). Ranked by preferred tags matched, then the `default` tag, then + * menu order. + */ +export function resolveSkill( + entries: readonly SkillEntry[], + criteria: SkillCriteria, + traits: TraitTags, +): SkillEntry | undefined { + if ('id' in criteria) return entries.find((e) => e.id === criteria.id); + if ('choose' in criteria) return undefined; + + let candidates = skillsWithTags(entries, criteria.tags); + for (const trait of criteria.require ?? []) { + const values = traits[trait] ?? []; + if (values.length === 0) return undefined; + candidates = candidates.filter((entry) => { + const carried = skillTags(entry); + return values.some((value) => carried.has(value)); + }); + } + + const preferred = (criteria.prefer ?? []).flatMap((t) => traits[t] ?? []); + let best: SkillEntry | undefined; + let bestScore = -1; + for (const entry of candidates) { + const carried = skillTags(entry); + const score = + preferred.filter((tag) => carried.has(tag)).length * 2 + + (carried.has(DEFAULT_SKILL_TAG) ? 1 : 0); + if (score > bestScore) { + best = entry; + bestScore = score; + } + } + return best; +} + +/** + * The criteria an orchestrator task's frontmatter skill id stands for today: + * that exact id when the menu has it, else its family's variant for the + * run's framework. + */ +export function legacySkillCriteria( + entries: readonly SkillEntry[], + skillId: string, +): SkillCriteria { + return entries.some((e) => e.id === skillId) + ? { id: skillId } + : { tags: [skillId], require: ['framework'] }; +} diff --git a/src/shared/utils/__tests__/analytics.test.ts b/src/shared/utils/__tests__/analytics.test.ts index a2f439780..4f1987bf0 100644 --- a/src/shared/utils/__tests__/analytics.test.ts +++ b/src/shared/utils/__tests__/analytics.test.ts @@ -387,6 +387,19 @@ describe('Analytics', () => { }); }); + it('stamps the wizard flags on the terminal event', async () => { + await analytics.getAllFlagsForWizard(); + analytics.setTag('program_id', 'posthog-integration'); + await analytics.shutdown('success'); + const call = mockPostHogInstance.capture.mock.calls.find( + ([arg]) => (arg as any).event === 'setup wizard finished', + ); + const props = (call?.[0] as any).properties; + expect(props['$feature/wizard-orchestrator']).toBe(true); + expect(props['$feature/unrelated-flag']).toBeUndefined(); + expect(props.status).toBe('success'); + }); + it('carries no $feature props before the fetch', () => { analytics.wizardCapture('early event'); const call = mockPostHogInstance.capture.mock.calls.find( diff --git a/src/shared/utils/analytics.ts b/src/shared/utils/analytics.ts index 13267ee12..b6a1cf97d 100644 --- a/src/shared/utils/analytics.ts +++ b/src/shared/utils/analytics.ts @@ -416,6 +416,8 @@ export class Analytics { properties: { // Flat for filtering; the nested `tags` snapshot stays for back-compat. ...this.tags, + // The run's wizard flags, so an outcome can be split by flag variant. + ...this.wizardFlagFeatureProperties(), run_id: this._runId, ...(this.sessionId ? { $session_id: this.sessionId } : {}), status, From b80dc0f55a64d41d08b672e0723b90ee0ef4fe28 Mon Sep 17 00:00:00 2001 From: Edwin Lim Date: Wed, 28 Oct 2026 17:33:03 -0700 Subject: [PATCH 2/2] refactor(traits): keep the trait vocabulary in the program contract Flows in the program contract read project traits, and the contract imports no service, so the vocabulary types live there and `@services/project-traits` produces their values. Co-Authored-By: Claude Opus 5.5 --- src/programs/program-contract/index.ts | 1 + src/programs/program-contract/project-traits.ts | 11 +++++++++++ src/services/project-traits/index.ts | 3 --- src/services/project-traits/traits.ts | 12 +----------- 4 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 src/programs/program-contract/project-traits.ts diff --git a/src/programs/program-contract/index.ts b/src/programs/program-contract/index.ts index 06dad7e87..8aa74f6ab 100644 --- a/src/programs/program-contract/index.ts +++ b/src/programs/program-contract/index.ts @@ -9,6 +9,7 @@ export { export { ProgramAbort } from './program-abort'; export type { ProgramRun } from './program-run'; export type { ProgramSession, ScanReport } from './program-session'; +export type { ProjectTraits, Trait, TraitName } from './project-traits'; export type { DecisionQuestionKey, ProgramConfig, diff --git a/src/programs/program-contract/project-traits.ts b/src/programs/program-contract/project-traits.ts new file mode 100644 index 000000000..fbdcab472 --- /dev/null +++ b/src/programs/program-contract/project-traits.ts @@ -0,0 +1,11 @@ +/** The project-trait vocabulary programs and services share; `@services/project-traits` produces the values. */ + +export type TraitName = 'framework' | 'callsLlmApi'; + +/** A predicate trait's value is `yes` or `no`; the framework's is its integration id. */ +export type Trait = { + value: string; + source: 'static'; +}; + +export type ProjectTraits = Partial>; diff --git a/src/services/project-traits/index.ts b/src/services/project-traits/index.ts index f5206da74..420d7519b 100644 --- a/src/services/project-traits/index.ts +++ b/src/services/project-traits/index.ts @@ -3,7 +3,4 @@ export { traitsFromDetectors, traitsToSkillTags, type DetectionResults, - type ProjectTraits, - type Trait, - type TraitName, } from './traits'; diff --git a/src/services/project-traits/traits.ts b/src/services/project-traits/traits.ts index 0f2039e78..09a2e2055 100644 --- a/src/services/project-traits/traits.ts +++ b/src/services/project-traits/traits.ts @@ -8,17 +8,7 @@ import { DiscoveredFeature } from '@shared/discovered-feature'; import { frameworkTag, type TraitTags } from '@shared/skill-resolution'; -import type { ProgramSession } from '@programs/program-contract'; - -export type TraitName = 'framework' | 'callsLlmApi'; - -/** A predicate trait's value is `yes` or `no`; the framework's is its integration id. */ -export type Trait = { - value: string; - source: 'static'; -}; - -export type ProjectTraits = Partial>; +import type { ProgramSession, ProjectTraits } from '@programs/program-contract'; /** What static detection stored on the session that a trait reads. */ export type DetectionResults = Pick<