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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions packages/core/src/setup/prompts.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
import { BASE_CATEGORY_ENUM } from "@posthog/core/setup/types";

export const WIZARD_PROMPT = `/instrument-integration
// Appended to every prompt that performs the initial PostHog SDK install/init. Writing env vars to
// .env files does nothing for the deployed app, and no run can read the hosting
// provider's env, so the checklist is unconditional. Where it gets delivered is
// not: these prompts run in cloud, worktree and local modes (WorkspaceMode), and
// a PR is never opened automatically in any of them — hence the two-branch phrasing.
export const DEPLOYMENT_ENV_VAR_PROMPT = `

After the integration is wired up, also instrument error tracking and session replay (run \`/instrument-error-tracking\`, then add session replay if the framework's posthog-js config supports it).
## Required: hand off an env var checklist

Run autonomously with sensible defaults — do not ask the user questions. If the PostHog API key isn't already in the project's env files and you can't read it from the PostHog MCP server, leave a placeholder env var and note it in the PR body rather than blocking.`;
Adding env vars to \`.env\`, \`.env.local\` or \`.env.example\` only covers local development. It does not set them on the deployed app, so production will send no events until someone sets them in the hosting provider. You cannot read or set the hosting provider's env from here, so always assume they are missing and always hand off the checklist below.

Detect the deployment target from repo-root markers: \`vercel.json\` or \`.vercel/\` → Vercel; \`netlify.toml\` → Netlify; \`wrangler.toml\` or \`wrangler.jsonc\` → Cloudflare; \`fly.toml\` → Fly.io. If nothing matches, call it "your hosting provider" and give the generic steps.

Deliver it wherever this run ends, replacing <provider> in the headings below with the detected provider name (or "your hosting provider" if none matched):
- If you open a pull request, its body must lead with the checklist — above the summary of changes — under the heading "Before you merge: set environment variables in <provider>".
- If you are working against a local checkout and not opening a pull request, print the same checklist to the user as the final message of the run, under the heading "Before you deploy: set environment variables in <provider>".

Either way the checklist contains:

- Every env var key name the integration reads, exactly as it appears in the code (e.g. the PostHog public key and host vars for this framework).
- Steps for the detected provider:
- Vercel: \`vercel env add <KEY> production\` per key, or Project Settings → Environment Variables.
- Netlify: \`netlify env:set <KEY> <value>\` per key, or Site configuration → Environment variables.
- Cloudflare: \`wrangler secret put <KEY>\` per key, or \`[vars]\` in the wrangler config for non-secret values.
- Fly.io: \`fly secrets set <KEY>=<value>\` per key.
- Unknown provider: instruct the user to add each key wherever their production environment defines env vars, and to redeploy.
- A plain statement that until these are set in <provider>, the production deployment will send no events to PostHog.

Never put secret values in a PR body — key names only. Point the user at their PostHog project settings for the value.`;

const DISCOVERY_PROMPT_BASE = `You are analyzing this codebase to find the highest-value first tasks for the developer.

Expand Down
54 changes: 53 additions & 1 deletion packages/core/src/setup/suggestions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,64 @@ describe("buildPosthogSetupSuggestion", () => {
it("returns the install suggestion when not installed", () => {
const task = buildPosthogSetupSuggestion("not_installed");
expect(task.id).toBe("posthog-setup");
expect(task.prompt).toBe("/instrument-integration");
expect(task.prompt?.startsWith("/instrument-integration")).toBe(true);
});

it("returns the finish-init suggestion when installed but not initialized", () => {
const task = buildPosthogSetupSuggestion("installed_no_init");
expect(task.id).toBe("posthog-finish-init");
expect(task.prompt).toContain("skip install steps");
});

it.each(["not_installed", "installed_no_init"] as const)(
"requires a hosting-provider env var checklist (%s)",
(state) => {
const prompt = buildPosthogSetupSuggestion(state).prompt ?? "";
expect(prompt).toContain("production will send no events");
expect(prompt).toContain("Never put secret values in a PR body");
},
);

// The prompt runs in cloud, worktree and local modes, and no mode opens a PR
// automatically — so it has to name a delivery target for both endings.
it.each(["not_installed", "installed_no_init"] as const)(
"routes the checklist to a PR body or the final message, per run type (%s)",
(state) => {
const prompt = buildPosthogSetupSuggestion(state).prompt ?? "";
expect(prompt).toContain(
"Before you merge: set environment variables in <provider>",
);
expect(prompt).toContain(
"Before you deploy: set environment variables in <provider>",
);
expect(prompt).toContain("not opening a pull request");
},
);

it.each([
["Vercel", "vercel env add <KEY> production"],
["Netlify", "netlify env:set <KEY> <value>"],
["Cloudflare", "wrangler secret put <KEY>"],
["Fly.io", "fly secrets set <KEY>=<value>"],
])("gives %s-specific env var steps", (provider, command) => {
const prompt = buildPosthogSetupSuggestion("not_installed").prompt ?? "";
expect(prompt).toContain(provider);
expect(prompt).toContain(command);
});

it.each([
["vercel.json", "Vercel"],
["netlify.toml", "Netlify"],
["wrangler.toml", "Cloudflare"],
["fly.toml", "Fly.io"],
])("maps the %s marker to %s", (marker, provider) => {
const prompt = buildPosthogSetupSuggestion("not_installed").prompt ?? "";
expect(prompt).toContain(`\`${marker}\``);
expect(prompt).toContain(provider);
});

it("falls back to a generic provider when no marker matches", () => {
const prompt = buildPosthogSetupSuggestion("not_installed").prompt ?? "";
expect(prompt).toContain('call it "your hosting provider"');
});
});
12 changes: 7 additions & 5 deletions packages/core/src/setup/suggestions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DEPLOYMENT_ENV_VAR_PROMPT } from "@posthog/core/setup/prompts";
import type { DiscoveredTask } from "@posthog/core/setup/types";

export interface StaleFlagPayload {
Expand Down Expand Up @@ -62,8 +63,8 @@ export function buildPosthogSetupSuggestion(
impact:
"Without PostHog wired in, you have no visibility into how users interact with the product, no error or session-replay coverage, and no way to gate releases behind feature flags.",
recommendation:
'Click "Implement as new task" — the agent runs the bundled instrument-integration skill, sets up env vars, installs the SDK with your project\'s package manager, and opens a PR.',
prompt: "/instrument-integration",
'Click "Implement as new task" — the agent runs the bundled instrument-integration skill, sets up env vars, installs the SDK with your project\'s package manager, and opens a PR listing the env vars you still need to set in your hosting provider.',
prompt: `/instrument-integration${DEPLOYMENT_ENV_VAR_PROMPT}`,
};
}
return {
Expand All @@ -76,8 +77,9 @@ export function buildPosthogSetupSuggestion(
impact:
"Until init runs, all PostHog calls are no-ops — you'll see no events in the project, no error reports, and no session replays despite the SDK being installed.",
recommendation:
'Click "Implement as new task" — the agent adds the init call and provider component for your framework, sets up the public-token + host env vars, and opens a PR. The SDK package itself is left alone.',
prompt:
"/instrument-integration\n\nThe SDK is already declared in this repo — skip install steps and focus on adding the init call, provider, and env vars.",
'Click "Implement as new task" — the agent adds the init call and provider component for your framework, sets up the public-token + host env vars, and opens a PR listing the env vars you still need to set in your hosting provider. The SDK package itself is left alone.',
prompt: `/instrument-integration

The SDK is already declared in this repo — skip install steps and focus on adding the init call, provider, and env vars.${DEPLOYMENT_ENV_VAR_PROMPT}`,
};
}
Loading