From 36172a0e63cf34d2e8ed21d771f1e3dac51d2f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Tue, 20 Oct 2026 14:57:49 +0200 Subject: [PATCH] :sparkles: Add a skill to build a PostHog timeline around a bug Add the posthog-timeline skill. Given a user's email or ID, a rough time, and what failed, it uses the PostHog MCP server to list what the user did before and after the bug, pick out the errors, and count how many other users hit the same error. List it in the skills table of the README. AI-assisted-by: claude-opus-5-5 --- .agents/README.md | 1 + .agents/skills/posthog-timeline/SKILL.md | 129 +++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 .agents/skills/posthog-timeline/SKILL.md diff --git a/.agents/README.md b/.agents/README.md index 371444a89d..735442f323 100644 --- a/.agents/README.md +++ b/.agents/README.md @@ -506,6 +506,7 @@ JSON, REPL access, and so on. | [`jq-json-processor`](skills/jq-json-processor/SKILL.md) | Slice, filter, and reshape JSON output. | | [`nrepl-eval`](skills/nrepl-eval/SKILL.md) | Run Clojure or ClojureScript code in the live REPL sessions (backend and frontend). | | [`taiga`](skills/taiga/SKILL.md) | Look up Penpot issues, user stories, and tasks in Taiga. | +| [`posthog-timeline`](skills/posthog-timeline/SKILL.md) | Build a timeline from PostHog of what a user did around a bug, and check whether other users hit the same error. Needs the PostHog MCP server. | | [`testing`](skills/testing/SKILL.md) | The repo's testing rules and TDD workflow, loaded before writing tests. | | [`local-ci`](skills/local-ci/SKILL.md) | Run CI-style lint, test, and format checks for the modules you touched with `scripts/ci`, and read the logs when they fail. | | [`security-and-hardening`](skills/security-and-hardening/SKILL.md) | Security checks for code that handles user input, auth, or external services. | diff --git a/.agents/skills/posthog-timeline/SKILL.md b/.agents/skills/posthog-timeline/SKILL.md new file mode 100644 index 0000000000..98a91ea3e4 --- /dev/null +++ b/.agents/skills/posthog-timeline/SKILL.md @@ -0,0 +1,129 @@ +--- +name: posthog-timeline +description: Build a timeline from PostHog of what a Penpot user did around a bug — their actions, errors, and what came just before — and check whether other users hit the same error. Needs the PostHog MCP server. +--- + +# PostHog Timeline + +Rebuild what a user did before and after a bug, from the PostHog events +of the Penpot projects. Then check how many other users hit the same +error. + +## When to use + +- The user reports a bug from a real Penpot user and wants to know what + happened before it: "posthog timeline for this user", "what did this + user do before the crash?", "check PostHog for this report". +- The user wants to know whether an error affects one user or many. + +## Prerequisites + +- The PostHog MCP server, connected to the right project: + - **Penpot-Prod** — design.penpot.app (default). + - **Penpot-Pre** — the pre-release environment. +- If no PostHog tools are loaded, stop and tell the user to connect the + PostHog MCP server. Do not guess events. + +## Inputs + +Ask for whatever is missing, in one message: + +| Input | Required | Notes | +|---|---|---| +| User email or ID | yes | Email, PostHog distinct ID, or Penpot profile ID. | +| When it happened | yes | Rough is fine ("yesterday afternoon", "2026-10-18 ~15:00 CET"). | +| What failed | yes | One sentence. | +| File link | no | A `.../workspace?team-id=...&file-id=...&page-id=...` URL narrows events to one file. | +| Project | no | Penpot-Prod unless the user says Penpot-Pre. | + +Pull the IDs out of the file link: `file-id`, `team-id`, `page-id`. + +## Steps + +1. **Pick the project.** List the PostHog projects and switch to + Penpot-Prod or Penpot-Pre as asked. Say which one you use. + +2. **Find the person.** Look up the user by email (person property + `email`) or by distinct ID. Note every distinct ID tied to the person; + a user can have more than one (logged out, other devices). + +3. **Learn the event names.** Before you write queries, list the event + definitions and the properties you plan to filter on (file ID, URL, + exception fields). Do not assume names; check them. + +4. **Fetch the window.** Keep PostHog API use low: few queries, small + windows, only the columns you need. + + - **Anchor first.** If the report is vague, first find the error + events alone (only `timestamp` and `event`, filtered to error event + names) over the reported period. Use the first error as the anchor. + - **Then a narrow window:** 15 minutes before the anchor to 5 minutes + after. Widen in steps (30, then 60 minutes before) only when the + events so far do not explain the error. + - Never select the whole `properties` blob for every row. Select only + named properties, and read the full payload for the error events + alone. + + ```sql + SELECT timestamp, event, properties.file_id + FROM events + WHERE distinct_id = '' + AND timestamp BETWEEN '' AND '' + ORDER BY timestamp + LIMIT 200 + ``` + + Filter by `distinct_id` (from step 2) rather than by + `person.properties.email`; it is cheaper. If a file link was given, + also filter by the file ID (in the URL or in a property, whichever + step 3 showed). + +5. **Find the errors.** Pick out `$exception` events and any Penpot error + events in the window. Keep the error type, message, and the top stack + frames. If error tracking is available, fetch the matching issue. + +6. **Check other users.** For each error, count how many distinct users + hit the same type and message in the last 7 and 30 days, and when it + first appeared. Group by app version or browser if the data allows. + + ```sql + SELECT count() AS events, count(DISTINCT person_id) AS users, + min(timestamp) AS first_seen, max(timestamp) AS last_seen + FROM events + WHERE event = '$exception' + AND properties.$exception_message = '' + AND timestamp > now() - INTERVAL 30 DAY + ``` + +7. **Look for a session recording.** If the events carry a + `$session_id` and recordings exist, give the link to the session. + +## Output + +Reply in the user's language with: + +1. **Summary** — two or three sentences: what the user was doing, what + failed, and whether others hit it. +2. **Timeline** — a table in time order, UTC, around 20–40 rows. Collapse + runs of the same event ("12× `$pageview` on the same file"). Mark the + error rows and the last few actions before the first error. + + | Time (UTC) | Event | Details | + |---|---|---| + +3. **Errors** — type, message, top frames, and the PostHog issue link if + there is one. +4. **Other users** — counts for 7 and 30 days, first and last seen, and + any pattern (version, browser, OS). +5. **Leads** — what the timeline points to in the code, if anything. Name + files only after you have checked they exist. +6. **Gaps** — what you could not find (no events in the window, no + recording, user not found). + +## Rules + +- Read only. Never change PostHog data, insights, flags, or dashboards. +- Personal data stays in the reply. Do not paste emails or IDs into + GitHub issues, commits, or PRs unless the user asks. +- Quote PostHog values as they are; do not invent events to fill gaps. +- Say which project and time window each query used.