[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-posthog-exploring-ai-failures":3,"mdc-1wlik6-key":49,"related-repo-posthog-exploring-ai-failures":904,"related-org-posthog-exploring-ai-failures":1004},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":23,"repoUrl":24,"updatedAt":25,"license":26,"forks":27,"topics":28,"repo":44,"sourceUrl":47,"mdContent":48},"exploring-ai-failures","diagnose AI application failures","Find where an AI\u002FLLM application is failing in production and surface the failure patterns, working from real traces. Use when someone wants to understand what's going wrong with an AI feature, find and categorize failure modes, triage errors, or investigate quality issues (wrong answers, ignored instructions, hallucinations, tool misuse) — \"what's failing in my agent\", \"surface error patterns\", \"why are the responses bad\", \"find the common failure modes\", \"what should I fix next\". Covers scoping to one use case, finding failing traces by whichever signal fits the context (code errors, metric outliers, trace-type slices, manual review, existing-eval spikes, clustering), and reading them into a ranked failure taxonomy.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"posthog","PostHog","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fposthog.png",[12,16,17,20],{"name":13,"slug":14,"type":15},"Observability","observability","tag",{"name":9,"slug":8,"type":15},{"name":18,"slug":19,"type":15},"LLM","llm",{"name":21,"slug":22,"type":15},"Debugging","debugging",35568,"https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog","2026-07-04T07:09:16.572174",null,2977,[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"ab-testing","ai-analytics","analytics","cdp","data-warehouse","experiments","feature-flags","javascript","product-analytics","python","react","session-replay","surveys","typescript","web-analytics",{"repoUrl":24,"stars":23,"forks":27,"topics":45,"description":46},[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"🦔 PostHog is an all-in-one developer platform for building successful products. We offer product analytics, web analytics, session replay, error tracking, feature flags, experimentation, surveys, data warehouse, a CDP, and an AI product assistant to help debug your code, ship features faster, and keep all your usage and customer data in one stack.","https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog\u002Ftree\u002FHEAD\u002Fproducts\u002Fai_observability\u002Fskills\u002Fexploring-ai-failures","---\nname: exploring-ai-failures\ndescription: >\n  Find where an AI\u002FLLM application is failing in production and surface the failure patterns, working from\n  real traces. Use when someone wants to understand what's going wrong with an AI feature, find and\n  categorize failure modes, triage errors, or investigate quality issues (wrong answers, ignored\n  instructions, hallucinations, tool misuse) — \"what's failing in my agent\", \"surface error patterns\",\n  \"why are the responses bad\", \"find the common failure modes\", \"what should I fix next\". Covers scoping\n  to one use case, finding failing traces by whichever signal fits the context (code errors, metric\n  outliers, trace-type slices, manual review, existing-eval spikes, clustering), and reading them into a\n  ranked failure taxonomy.\n---\n\n# Exploring AI failures\n\nThe highest-value thing you can do with production AI traffic is look at where it fails and name the\npatterns. The catch: **most failures are silent.** The model returns a clean response — HTTP 200, no\nexception — that is wrong, off-topic, ignores an instruction, or misuses a tool. Those never raise an\nerror, and they're usually the failures worth caring about.\n\nSo this skill is about finding failures (loud _and_ silent), **reading them**, and grouping them into a\n**ranked set of failure modes** you can act on: fix a prompt, file a bug, prioritize work, or turn the\ntop mode into an automatic eval (`creating-online-evaluations`).\n\n**Everything below serves one irreducible activity: reading real traces.** The queries only tell you\n_which_ traces to open — they are never the answer. If you report a list of problems without having\nopened traces, you've described the loud minority (the things that throw errors) and missed the job.\n\nThis is bottom-up: the failure modes emerge from real traces, not from a list of generic metrics decided\nin advance. For reading a single trace in depth, lean on `exploring-llm-traces`; for emergent grouping at\nhigh volume, `exploring-llm-clusters`.\n\n## Tools\n\n| Tool                                     | Purpose                                                                  |\n| ---------------------------------------- | ------------------------------------------------------------------------ |\n| `posthog:query-llm-traces-list`          | List candidate traces — filter by error, sort by a metric, scope by type |\n| `posthog:query-llm-trace`                | Read a trace in full to see what actually went wrong                     |\n| `posthog:execute-sql`                    | Find metric outliers, discover the trace taxonomy, count failure modes   |\n| `posthog:llma-evaluation-list`           | Find existing evals whose failures might reveal a new mode               |\n| `posthog:llma-evaluation-summary-create` | Summarize an existing eval's failures into patterns                      |\n| `posthog:generate-app-url`               | Build a region- and project-qualified deep link to a trace or list       |\n\nDetailed queries for each strategy below are in\n[references\u002Ffinding-traces.md](references\u002Ffinding-traces.md). The full `$ai_*` event schema (and the\n`events` vs `ai_events` split for heavy content like `$ai_input`\u002F`$ai_output_choices`) lives in\n`exploring-llm-traces\u002Freferences\u002Fevents-and-properties.md`.\n\n## Work with the user\n\nCollaborate on _scope and priorities_ — not on whether to do the work. Narrow with the user up front:\nwhich feature or use case? have they already seen something bad? is there a signal to follow (a\nthumbs-down, a ticket, a metric that looks off)? Once it's scoped, **go read traces and come back with\ncoded failure modes** — don't stop to ask permission before the reading; that reading is the core\nactivity, not an optional follow-up to offer. When the user doesn't know what to look for, drive the loop\nbelow and explain the reasoning as you go; keep the teaching opt-in.\n\n## Step 1 — Scope to one use case\n\nApps have a _taxonomy_ of trace types, and each fails differently — a support chat hallucinates policy, a\nsummarizer drops key points, an agent loops or misuses a tool. Evaluating or analyzing them together\naverages the signal away. **Pick one**, then find its filter (a `$ai_trace_id` prefix, a feature\nproperty, a model). If the user isn't sure how their traffic splits, discover the taxonomy first (query\nin [references\u002Ffinding-traces.md](references\u002Ffinding-traces.md)).\n\n## Step 2 — Pick which traces to read\n\nThese are ways to _select which traces to open_ — not answers in themselves. The queryable ones (error\ncounts, metric aggregates) tell you _where to look_; they are never the output. Choose by the context and\nsignals you have, and combine them:\n\n- **Code errors (`$ai_is_error`)** — the cheapest sweep and the _least_ representative signal: it only\n  catches exceptions and API failures, not the silent quality failures that matter most. Use it to grab a\n  few traces to read, not as a tally of \"the problems.\" Slightly more useful for structured-output or\n  tool-calling pipelines, where some failures do surface as parse\u002Fschema errors.\n- **Metric outliers** — sort by output\u002Finput tokens, message length, cost, or latency and open the\n  extremes. Runaway length, truncation, context bloat, and loops cluster at the tails.\n- **One trace-type slice** — narrow to a single kind of request so the traces you read share a taxonomy.\n- **Stratified sample** — when you have no specific signal (the common case), pull a mixed batch across\n  slices and outcomes and read it. This is the default, not the fallback.\n- **Existing-eval spikes** — when evals already run, a jump in an eval's failures points you at traces to\n  read (`llma-evaluation-list` + `llma-evaluation-summary-create`).\n- **Clustering** — at high volume, let groupings emerge to pick representative traces to read; see\n  `exploring-llm-clusters`.\n\n> **The trap.** It's tempting to `GROUP BY` error messages, produce a ranked table, and stop. That table\n> is the loud minority — failures that raise an exception. The failures that matter for most AI products\n> complete with HTTP 200 and only appear when a human reads the trace. **A ranking built from error or\n> metric counts you never opened is not the deliverable** — it's a pointer to what to read next. If a\n> query for silent failures comes back empty or awkward, that's a signal to _read traces_, not to give up\n> and report the loud ones.\n\n## Step 3 — Read a batch (this is the job)\n\nOpen and actually read the traces you selected — plan on roughly 20–30 for a use case. This step is not\noptional, and nothing substitutes for it. You **cannot** find silent failures with `GROUP BY` or by\ngrepping outputs for \"refusal\" \u002F \"sorry\" language, because you don't yet know the patterns to search for —\nreading is how you discover them. A clever SQL proxy that returns nothing is not evidence the failures\naren't there; it means you have to read.\n\nFor each trace, note in plain language what went wrong — and jot down the trace's earliest-event timestamp\nalongside the note (it's right there in the trace you just read, and in `query-llm-traces-list`'s\n`createdAt`). That timestamp and the trace ID is all you need to build a resolvable deep link in Step 4,\nso capturing it now saves a second round-trip later.\n\nWhen a trace fails in a chain, record the _first_ thing that broke — the root failure usually causes the\ndownstream symptoms, and fixing it clears them. Group the notes into a few named failure modes\n(\"ignores the date filter\", \"invents a policy\", \"drops the second question\"); a later pass can help\ncluster your notes, but review the groupings yourself. Keep reading until new traces stop turning up\nnew modes (tens of traces, not thousands — stop when it goes quiet).\n\n## Step 4 — Rank, link, and hand back to the user\n\nRank the modes you found _by reading_, roughly by how often they showed up in your sample — a handful\nusually dominate. Present a short, ranked list of named failure modes. For each mode, include **one or two\nexample trace deep links** on your own — don't wait to be asked, and don't make the user request them.\n\nYou read these traces, but you can misread one — a trace that looks like a hallucination may be correct in\ncontext, and some of what you flag will be you misunderstanding the trace, not a real failure. So don't\npresent the list as settled fact. Give the user a couple of linked examples per mode, ask them to open the\nlinks, then ask **which mode they want to focus on** next.\n\n(A list assembled from error messages or metric counts you never read is the loud subset, not this — go\nback to Step 3.)\n\n## When there's little to look at\n\nIf the use case is new or low-volume and you can't find enough failures: widen the time window or loosen\nthe slice first; then **stress-test** with inputs that deliberately probe the constraints you care about\n(edge cases, long or ambiguous inputs, adversarial phrasing); or **generate a small synthetic set** across\nthe dimensions that matter (request type × user scenario), run it through the system, and read those\ntraces. Treat synthetic results as a bootstrap, not ground truth — they're unreliable for high-stakes or\nniche domains.\n\n## Constructing UI links\n\n`query-llm-trace` does not return a `_posthogUrl`, so build links with `posthog:generate-app-url` —\nnever hand-write the host or the `\u002Fproject\u002F\u003Cid>\u002F` prefix. The `url` must be a canonical catalog\ntemplate; pass concrete ids via `params`, never inline them into the path.\n\n- **Traces list:** `generate-app-url {url: \"\u002Fai-observability\u002Ftraces\"}` (then filter to your use case)\n- **Single trace:** `generate-app-url {url: \"\u002Fai-observability\u002Ftraces\u002F{id}\", params: {id: \"\u003Ctrace_id>\"}}`,\n  then append `?timestamp=\u003Curl_encoded_timestamp>` to the returned URL (the timestamp isn't expressible via the tool).\n\nThese resolve to the correct region host and project prefix (e.g.\n`https:\u002F\u002Fus.posthog.com\u002Fproject\u002F\u003Cid>\u002Fai-observability\u002Ftraces\u002F\u003Ctrace_id>`), so a user not already on the\ntarget project still lands in the right place.\n\n## Tips\n\n- **Reading is the job, not the last step.** Aggregates, error counts, and scores are clues for _which\n  traces to open_ — never a substitute. Read a first batch before reporting anything, and don't ask\n  permission to do it.\n- **Don't over-index on errors.** `$ai_is_error` is the loudest but least interesting signal; the\n  failures worth your time usually complete without one.\n- **The finding strategies are a menu for picking traces to read**, not a pipeline and not the answer.\n  Pick by context, combine freely, and don't force an order.\n- **One use case at a time.** Different trace types have different failure taxonomies — mixing them blurs\n  the result.\n- **Frequency over completeness.** The goal is the modes that happen most, not every conceivable failure.\n- **The output is a ranked list of named failure modes from traces you read** — that artifact is what\n  makes the next step (fix, prioritize, or eval) obvious.\n- **Hand back linked examples, then let the user steer.** Don't stop at a categorical table. Give one or\n  two resolvable trace links per mode unprompted, ask the user to eyeball a couple.\n",{"data":50,"body":51},{"name":4,"description":6},{"type":52,"children":53},"root",[54,62,76,112,129,150,157,287,347,353,372,378,410,416,435,536,572,578,597,618,630,636,655,667,672,678,697,703,753,799,812,818],{"type":55,"tag":56,"props":57,"children":58},"element","h1",{"id":4},[59],{"type":60,"value":61},"text","Exploring AI failures",{"type":55,"tag":63,"props":64,"children":65},"p",{},[66,68,74],{"type":60,"value":67},"The highest-value thing you can do with production AI traffic is look at where it fails and name the\npatterns. The catch: ",{"type":55,"tag":69,"props":70,"children":71},"strong",{},[72],{"type":60,"value":73},"most failures are silent.",{"type":60,"value":75}," The model returns a clean response — HTTP 200, no\nexception — that is wrong, off-topic, ignores an instruction, or misuses a tool. Those never raise an\nerror, and they're usually the failures worth caring about.",{"type":55,"tag":63,"props":77,"children":78},{},[79,81,87,89,94,96,101,103,110],{"type":60,"value":80},"So this skill is about finding failures (loud ",{"type":55,"tag":82,"props":83,"children":84},"em",{},[85],{"type":60,"value":86},"and",{"type":60,"value":88}," silent), ",{"type":55,"tag":69,"props":90,"children":91},{},[92],{"type":60,"value":93},"reading them",{"type":60,"value":95},", and grouping them into a\n",{"type":55,"tag":69,"props":97,"children":98},{},[99],{"type":60,"value":100},"ranked set of failure modes",{"type":60,"value":102}," you can act on: fix a prompt, file a bug, prioritize work, or turn the\ntop mode into an automatic eval (",{"type":55,"tag":104,"props":105,"children":107},"code",{"className":106},[],[108],{"type":60,"value":109},"creating-online-evaluations",{"type":60,"value":111},").",{"type":55,"tag":63,"props":113,"children":114},{},[115,120,122,127],{"type":55,"tag":69,"props":116,"children":117},{},[118],{"type":60,"value":119},"Everything below serves one irreducible activity: reading real traces.",{"type":60,"value":121}," The queries only tell you\n",{"type":55,"tag":82,"props":123,"children":124},{},[125],{"type":60,"value":126},"which",{"type":60,"value":128}," traces to open — they are never the answer. If you report a list of problems without having\nopened traces, you've described the loud minority (the things that throw errors) and missed the job.",{"type":55,"tag":63,"props":130,"children":131},{},[132,134,140,142,148],{"type":60,"value":133},"This is bottom-up: the failure modes emerge from real traces, not from a list of generic metrics decided\nin advance. For reading a single trace in depth, lean on ",{"type":55,"tag":104,"props":135,"children":137},{"className":136},[],[138],{"type":60,"value":139},"exploring-llm-traces",{"type":60,"value":141},"; for emergent grouping at\nhigh volume, ",{"type":55,"tag":104,"props":143,"children":145},{"className":144},[],[146],{"type":60,"value":147},"exploring-llm-clusters",{"type":60,"value":149},".",{"type":55,"tag":151,"props":152,"children":154},"h2",{"id":153},"tools",[155],{"type":60,"value":156},"Tools",{"type":55,"tag":158,"props":159,"children":160},"table",{},[161,180],{"type":55,"tag":162,"props":163,"children":164},"thead",{},[165],{"type":55,"tag":166,"props":167,"children":168},"tr",{},[169,175],{"type":55,"tag":170,"props":171,"children":172},"th",{},[173],{"type":60,"value":174},"Tool",{"type":55,"tag":170,"props":176,"children":177},{},[178],{"type":60,"value":179},"Purpose",{"type":55,"tag":181,"props":182,"children":183},"tbody",{},[184,202,219,236,253,270],{"type":55,"tag":166,"props":185,"children":186},{},[187,197],{"type":55,"tag":188,"props":189,"children":190},"td",{},[191],{"type":55,"tag":104,"props":192,"children":194},{"className":193},[],[195],{"type":60,"value":196},"posthog:query-llm-traces-list",{"type":55,"tag":188,"props":198,"children":199},{},[200],{"type":60,"value":201},"List candidate traces — filter by error, sort by a metric, scope by type",{"type":55,"tag":166,"props":203,"children":204},{},[205,214],{"type":55,"tag":188,"props":206,"children":207},{},[208],{"type":55,"tag":104,"props":209,"children":211},{"className":210},[],[212],{"type":60,"value":213},"posthog:query-llm-trace",{"type":55,"tag":188,"props":215,"children":216},{},[217],{"type":60,"value":218},"Read a trace in full to see what actually went wrong",{"type":55,"tag":166,"props":220,"children":221},{},[222,231],{"type":55,"tag":188,"props":223,"children":224},{},[225],{"type":55,"tag":104,"props":226,"children":228},{"className":227},[],[229],{"type":60,"value":230},"posthog:execute-sql",{"type":55,"tag":188,"props":232,"children":233},{},[234],{"type":60,"value":235},"Find metric outliers, discover the trace taxonomy, count failure modes",{"type":55,"tag":166,"props":237,"children":238},{},[239,248],{"type":55,"tag":188,"props":240,"children":241},{},[242],{"type":55,"tag":104,"props":243,"children":245},{"className":244},[],[246],{"type":60,"value":247},"posthog:llma-evaluation-list",{"type":55,"tag":188,"props":249,"children":250},{},[251],{"type":60,"value":252},"Find existing evals whose failures might reveal a new mode",{"type":55,"tag":166,"props":254,"children":255},{},[256,265],{"type":55,"tag":188,"props":257,"children":258},{},[259],{"type":55,"tag":104,"props":260,"children":262},{"className":261},[],[263],{"type":60,"value":264},"posthog:llma-evaluation-summary-create",{"type":55,"tag":188,"props":266,"children":267},{},[268],{"type":60,"value":269},"Summarize an existing eval's failures into patterns",{"type":55,"tag":166,"props":271,"children":272},{},[273,282],{"type":55,"tag":188,"props":274,"children":275},{},[276],{"type":55,"tag":104,"props":277,"children":279},{"className":278},[],[280],{"type":60,"value":281},"posthog:generate-app-url",{"type":55,"tag":188,"props":283,"children":284},{},[285],{"type":60,"value":286},"Build a region- and project-qualified deep link to a trace or list",{"type":55,"tag":63,"props":288,"children":289},{},[290,292,298,300,306,308,314,316,322,324,330,332,338,340,346],{"type":60,"value":291},"Detailed queries for each strategy below are in\n",{"type":55,"tag":293,"props":294,"children":296},"a",{"href":295},"references\u002Ffinding-traces.md",[297],{"type":60,"value":295},{"type":60,"value":299},". The full ",{"type":55,"tag":104,"props":301,"children":303},{"className":302},[],[304],{"type":60,"value":305},"$ai_*",{"type":60,"value":307}," event schema (and the\n",{"type":55,"tag":104,"props":309,"children":311},{"className":310},[],[312],{"type":60,"value":313},"events",{"type":60,"value":315}," vs ",{"type":55,"tag":104,"props":317,"children":319},{"className":318},[],[320],{"type":60,"value":321},"ai_events",{"type":60,"value":323}," split for heavy content like ",{"type":55,"tag":104,"props":325,"children":327},{"className":326},[],[328],{"type":60,"value":329},"$ai_input",{"type":60,"value":331},"\u002F",{"type":55,"tag":104,"props":333,"children":335},{"className":334},[],[336],{"type":60,"value":337},"$ai_output_choices",{"type":60,"value":339},") lives in\n",{"type":55,"tag":104,"props":341,"children":343},{"className":342},[],[344],{"type":60,"value":345},"exploring-llm-traces\u002Freferences\u002Fevents-and-properties.md",{"type":60,"value":149},{"type":55,"tag":151,"props":348,"children":350},{"id":349},"work-with-the-user",[351],{"type":60,"value":352},"Work with the user",{"type":55,"tag":63,"props":354,"children":355},{},[356,358,363,365,370],{"type":60,"value":357},"Collaborate on ",{"type":55,"tag":82,"props":359,"children":360},{},[361],{"type":60,"value":362},"scope and priorities",{"type":60,"value":364}," — not on whether to do the work. Narrow with the user up front:\nwhich feature or use case? have they already seen something bad? is there a signal to follow (a\nthumbs-down, a ticket, a metric that looks off)? Once it's scoped, ",{"type":55,"tag":69,"props":366,"children":367},{},[368],{"type":60,"value":369},"go read traces and come back with\ncoded failure modes",{"type":60,"value":371}," — don't stop to ask permission before the reading; that reading is the core\nactivity, not an optional follow-up to offer. When the user doesn't know what to look for, drive the loop\nbelow and explain the reasoning as you go; keep the teaching opt-in.",{"type":55,"tag":151,"props":373,"children":375},{"id":374},"step-1-scope-to-one-use-case",[376],{"type":60,"value":377},"Step 1 — Scope to one use case",{"type":55,"tag":63,"props":379,"children":380},{},[381,383,388,390,395,397,403,405,409],{"type":60,"value":382},"Apps have a ",{"type":55,"tag":82,"props":384,"children":385},{},[386],{"type":60,"value":387},"taxonomy",{"type":60,"value":389}," of trace types, and each fails differently — a support chat hallucinates policy, a\nsummarizer drops key points, an agent loops or misuses a tool. Evaluating or analyzing them together\naverages the signal away. ",{"type":55,"tag":69,"props":391,"children":392},{},[393],{"type":60,"value":394},"Pick one",{"type":60,"value":396},", then find its filter (a ",{"type":55,"tag":104,"props":398,"children":400},{"className":399},[],[401],{"type":60,"value":402},"$ai_trace_id",{"type":60,"value":404}," prefix, a feature\nproperty, a model). If the user isn't sure how their traffic splits, discover the taxonomy first (query\nin ",{"type":55,"tag":293,"props":406,"children":407},{"href":295},[408],{"type":60,"value":295},{"type":60,"value":111},{"type":55,"tag":151,"props":411,"children":413},{"id":412},"step-2-pick-which-traces-to-read",[414],{"type":60,"value":415},"Step 2 — Pick which traces to read",{"type":55,"tag":63,"props":417,"children":418},{},[419,421,426,428,433],{"type":60,"value":420},"These are ways to ",{"type":55,"tag":82,"props":422,"children":423},{},[424],{"type":60,"value":425},"select which traces to open",{"type":60,"value":427}," — not answers in themselves. The queryable ones (error\ncounts, metric aggregates) tell you ",{"type":55,"tag":82,"props":429,"children":430},{},[431],{"type":60,"value":432},"where to look",{"type":60,"value":434},"; they are never the output. Choose by the context and\nsignals you have, and combine them:",{"type":55,"tag":436,"props":437,"children":438},"ul",{},[439,465,475,485,495,520],{"type":55,"tag":440,"props":441,"children":442},"li",{},[443,456,458,463],{"type":55,"tag":69,"props":444,"children":445},{},[446,448,454],{"type":60,"value":447},"Code errors (",{"type":55,"tag":104,"props":449,"children":451},{"className":450},[],[452],{"type":60,"value":453},"$ai_is_error",{"type":60,"value":455},")",{"type":60,"value":457}," — the cheapest sweep and the ",{"type":55,"tag":82,"props":459,"children":460},{},[461],{"type":60,"value":462},"least",{"type":60,"value":464}," representative signal: it only\ncatches exceptions and API failures, not the silent quality failures that matter most. Use it to grab a\nfew traces to read, not as a tally of \"the problems.\" Slightly more useful for structured-output or\ntool-calling pipelines, where some failures do surface as parse\u002Fschema errors.",{"type":55,"tag":440,"props":466,"children":467},{},[468,473],{"type":55,"tag":69,"props":469,"children":470},{},[471],{"type":60,"value":472},"Metric outliers",{"type":60,"value":474}," — sort by output\u002Finput tokens, message length, cost, or latency and open the\nextremes. Runaway length, truncation, context bloat, and loops cluster at the tails.",{"type":55,"tag":440,"props":476,"children":477},{},[478,483],{"type":55,"tag":69,"props":479,"children":480},{},[481],{"type":60,"value":482},"One trace-type slice",{"type":60,"value":484}," — narrow to a single kind of request so the traces you read share a taxonomy.",{"type":55,"tag":440,"props":486,"children":487},{},[488,493],{"type":55,"tag":69,"props":489,"children":490},{},[491],{"type":60,"value":492},"Stratified sample",{"type":60,"value":494}," — when you have no specific signal (the common case), pull a mixed batch across\nslices and outcomes and read it. This is the default, not the fallback.",{"type":55,"tag":440,"props":496,"children":497},{},[498,503,505,511,513,519],{"type":55,"tag":69,"props":499,"children":500},{},[501],{"type":60,"value":502},"Existing-eval spikes",{"type":60,"value":504}," — when evals already run, a jump in an eval's failures points you at traces to\nread (",{"type":55,"tag":104,"props":506,"children":508},{"className":507},[],[509],{"type":60,"value":510},"llma-evaluation-list",{"type":60,"value":512}," + ",{"type":55,"tag":104,"props":514,"children":516},{"className":515},[],[517],{"type":60,"value":518},"llma-evaluation-summary-create",{"type":60,"value":111},{"type":55,"tag":440,"props":521,"children":522},{},[523,528,530,535],{"type":55,"tag":69,"props":524,"children":525},{},[526],{"type":60,"value":527},"Clustering",{"type":60,"value":529}," — at high volume, let groupings emerge to pick representative traces to read; see\n",{"type":55,"tag":104,"props":531,"children":533},{"className":532},[],[534],{"type":60,"value":147},{"type":60,"value":149},{"type":55,"tag":537,"props":538,"children":539},"blockquote",{},[540],{"type":55,"tag":63,"props":541,"children":542},{},[543,548,550,556,558,563,565,570],{"type":55,"tag":69,"props":544,"children":545},{},[546],{"type":60,"value":547},"The trap.",{"type":60,"value":549}," It's tempting to ",{"type":55,"tag":104,"props":551,"children":553},{"className":552},[],[554],{"type":60,"value":555},"GROUP BY",{"type":60,"value":557}," error messages, produce a ranked table, and stop. That table\nis the loud minority — failures that raise an exception. The failures that matter for most AI products\ncomplete with HTTP 200 and only appear when a human reads the trace. ",{"type":55,"tag":69,"props":559,"children":560},{},[561],{"type":60,"value":562},"A ranking built from error or\nmetric counts you never opened is not the deliverable",{"type":60,"value":564}," — it's a pointer to what to read next. If a\nquery for silent failures comes back empty or awkward, that's a signal to ",{"type":55,"tag":82,"props":566,"children":567},{},[568],{"type":60,"value":569},"read traces",{"type":60,"value":571},", not to give up\nand report the loud ones.",{"type":55,"tag":151,"props":573,"children":575},{"id":574},"step-3-read-a-batch-this-is-the-job",[576],{"type":60,"value":577},"Step 3 — Read a batch (this is the job)",{"type":55,"tag":63,"props":579,"children":580},{},[581,583,588,590,595],{"type":60,"value":582},"Open and actually read the traces you selected — plan on roughly 20–30 for a use case. This step is not\noptional, and nothing substitutes for it. You ",{"type":55,"tag":69,"props":584,"children":585},{},[586],{"type":60,"value":587},"cannot",{"type":60,"value":589}," find silent failures with ",{"type":55,"tag":104,"props":591,"children":593},{"className":592},[],[594],{"type":60,"value":555},{"type":60,"value":596}," or by\ngrepping outputs for \"refusal\" \u002F \"sorry\" language, because you don't yet know the patterns to search for —\nreading is how you discover them. A clever SQL proxy that returns nothing is not evidence the failures\naren't there; it means you have to read.",{"type":55,"tag":63,"props":598,"children":599},{},[600,602,608,610,616],{"type":60,"value":601},"For each trace, note in plain language what went wrong — and jot down the trace's earliest-event timestamp\nalongside the note (it's right there in the trace you just read, and in ",{"type":55,"tag":104,"props":603,"children":605},{"className":604},[],[606],{"type":60,"value":607},"query-llm-traces-list",{"type":60,"value":609},"'s\n",{"type":55,"tag":104,"props":611,"children":613},{"className":612},[],[614],{"type":60,"value":615},"createdAt",{"type":60,"value":617},"). That timestamp and the trace ID is all you need to build a resolvable deep link in Step 4,\nso capturing it now saves a second round-trip later.",{"type":55,"tag":63,"props":619,"children":620},{},[621,623,628],{"type":60,"value":622},"When a trace fails in a chain, record the ",{"type":55,"tag":82,"props":624,"children":625},{},[626],{"type":60,"value":627},"first",{"type":60,"value":629}," thing that broke — the root failure usually causes the\ndownstream symptoms, and fixing it clears them. Group the notes into a few named failure modes\n(\"ignores the date filter\", \"invents a policy\", \"drops the second question\"); a later pass can help\ncluster your notes, but review the groupings yourself. Keep reading until new traces stop turning up\nnew modes (tens of traces, not thousands — stop when it goes quiet).",{"type":55,"tag":151,"props":631,"children":633},{"id":632},"step-4-rank-link-and-hand-back-to-the-user",[634],{"type":60,"value":635},"Step 4 — Rank, link, and hand back to the user",{"type":55,"tag":63,"props":637,"children":638},{},[639,641,646,648,653],{"type":60,"value":640},"Rank the modes you found ",{"type":55,"tag":82,"props":642,"children":643},{},[644],{"type":60,"value":645},"by reading",{"type":60,"value":647},", roughly by how often they showed up in your sample — a handful\nusually dominate. Present a short, ranked list of named failure modes. For each mode, include ",{"type":55,"tag":69,"props":649,"children":650},{},[651],{"type":60,"value":652},"one or two\nexample trace deep links",{"type":60,"value":654}," on your own — don't wait to be asked, and don't make the user request them.",{"type":55,"tag":63,"props":656,"children":657},{},[658,660,665],{"type":60,"value":659},"You read these traces, but you can misread one — a trace that looks like a hallucination may be correct in\ncontext, and some of what you flag will be you misunderstanding the trace, not a real failure. So don't\npresent the list as settled fact. Give the user a couple of linked examples per mode, ask them to open the\nlinks, then ask ",{"type":55,"tag":69,"props":661,"children":662},{},[663],{"type":60,"value":664},"which mode they want to focus on",{"type":60,"value":666}," next.",{"type":55,"tag":63,"props":668,"children":669},{},[670],{"type":60,"value":671},"(A list assembled from error messages or metric counts you never read is the loud subset, not this — go\nback to Step 3.)",{"type":55,"tag":151,"props":673,"children":675},{"id":674},"when-theres-little-to-look-at",[676],{"type":60,"value":677},"When there's little to look at",{"type":55,"tag":63,"props":679,"children":680},{},[681,683,688,690,695],{"type":60,"value":682},"If the use case is new or low-volume and you can't find enough failures: widen the time window or loosen\nthe slice first; then ",{"type":55,"tag":69,"props":684,"children":685},{},[686],{"type":60,"value":687},"stress-test",{"type":60,"value":689}," with inputs that deliberately probe the constraints you care about\n(edge cases, long or ambiguous inputs, adversarial phrasing); or ",{"type":55,"tag":69,"props":691,"children":692},{},[693],{"type":60,"value":694},"generate a small synthetic set",{"type":60,"value":696}," across\nthe dimensions that matter (request type × user scenario), run it through the system, and read those\ntraces. Treat synthetic results as a bootstrap, not ground truth — they're unreliable for high-stakes or\nniche domains.",{"type":55,"tag":151,"props":698,"children":700},{"id":699},"constructing-ui-links",[701],{"type":60,"value":702},"Constructing UI links",{"type":55,"tag":63,"props":704,"children":705},{},[706,712,714,720,722,727,729,735,737,743,745,751],{"type":55,"tag":104,"props":707,"children":709},{"className":708},[],[710],{"type":60,"value":711},"query-llm-trace",{"type":60,"value":713}," does not return a ",{"type":55,"tag":104,"props":715,"children":717},{"className":716},[],[718],{"type":60,"value":719},"_posthogUrl",{"type":60,"value":721},", so build links with ",{"type":55,"tag":104,"props":723,"children":725},{"className":724},[],[726],{"type":60,"value":281},{"type":60,"value":728}," —\nnever hand-write the host or the ",{"type":55,"tag":104,"props":730,"children":732},{"className":731},[],[733],{"type":60,"value":734},"\u002Fproject\u002F\u003Cid>\u002F",{"type":60,"value":736}," prefix. The ",{"type":55,"tag":104,"props":738,"children":740},{"className":739},[],[741],{"type":60,"value":742},"url",{"type":60,"value":744}," must be a canonical catalog\ntemplate; pass concrete ids via ",{"type":55,"tag":104,"props":746,"children":748},{"className":747},[],[749],{"type":60,"value":750},"params",{"type":60,"value":752},", never inline them into the path.",{"type":55,"tag":436,"props":754,"children":755},{},[756,774],{"type":55,"tag":440,"props":757,"children":758},{},[759,764,766,772],{"type":55,"tag":69,"props":760,"children":761},{},[762],{"type":60,"value":763},"Traces list:",{"type":60,"value":765}," ",{"type":55,"tag":104,"props":767,"children":769},{"className":768},[],[770],{"type":60,"value":771},"generate-app-url {url: \"\u002Fai-observability\u002Ftraces\"}",{"type":60,"value":773}," (then filter to your use case)",{"type":55,"tag":440,"props":775,"children":776},{},[777,782,783,789,791,797],{"type":55,"tag":69,"props":778,"children":779},{},[780],{"type":60,"value":781},"Single trace:",{"type":60,"value":765},{"type":55,"tag":104,"props":784,"children":786},{"className":785},[],[787],{"type":60,"value":788},"generate-app-url {url: \"\u002Fai-observability\u002Ftraces\u002F{id}\", params: {id: \"\u003Ctrace_id>\"}}",{"type":60,"value":790},",\nthen append ",{"type":55,"tag":104,"props":792,"children":794},{"className":793},[],[795],{"type":60,"value":796},"?timestamp=\u003Curl_encoded_timestamp>",{"type":60,"value":798}," to the returned URL (the timestamp isn't expressible via the tool).",{"type":55,"tag":63,"props":800,"children":801},{},[802,804,810],{"type":60,"value":803},"These resolve to the correct region host and project prefix (e.g.\n",{"type":55,"tag":104,"props":805,"children":807},{"className":806},[],[808],{"type":60,"value":809},"https:\u002F\u002Fus.posthog.com\u002Fproject\u002F\u003Cid>\u002Fai-observability\u002Ftraces\u002F\u003Ctrace_id>",{"type":60,"value":811},"), so a user not already on the\ntarget project still lands in the right place.",{"type":55,"tag":151,"props":813,"children":815},{"id":814},"tips",[816],{"type":60,"value":817},"Tips",{"type":55,"tag":436,"props":819,"children":820},{},[821,838,854,864,874,884,894],{"type":55,"tag":440,"props":822,"children":823},{},[824,829,831,836],{"type":55,"tag":69,"props":825,"children":826},{},[827],{"type":60,"value":828},"Reading is the job, not the last step.",{"type":60,"value":830}," Aggregates, error counts, and scores are clues for ",{"type":55,"tag":82,"props":832,"children":833},{},[834],{"type":60,"value":835},"which\ntraces to open",{"type":60,"value":837}," — never a substitute. Read a first batch before reporting anything, and don't ask\npermission to do it.",{"type":55,"tag":440,"props":839,"children":840},{},[841,846,847,852],{"type":55,"tag":69,"props":842,"children":843},{},[844],{"type":60,"value":845},"Don't over-index on errors.",{"type":60,"value":765},{"type":55,"tag":104,"props":848,"children":850},{"className":849},[],[851],{"type":60,"value":453},{"type":60,"value":853}," is the loudest but least interesting signal; the\nfailures worth your time usually complete without one.",{"type":55,"tag":440,"props":855,"children":856},{},[857,862],{"type":55,"tag":69,"props":858,"children":859},{},[860],{"type":60,"value":861},"The finding strategies are a menu for picking traces to read",{"type":60,"value":863},", not a pipeline and not the answer.\nPick by context, combine freely, and don't force an order.",{"type":55,"tag":440,"props":865,"children":866},{},[867,872],{"type":55,"tag":69,"props":868,"children":869},{},[870],{"type":60,"value":871},"One use case at a time.",{"type":60,"value":873}," Different trace types have different failure taxonomies — mixing them blurs\nthe result.",{"type":55,"tag":440,"props":875,"children":876},{},[877,882],{"type":55,"tag":69,"props":878,"children":879},{},[880],{"type":60,"value":881},"Frequency over completeness.",{"type":60,"value":883}," The goal is the modes that happen most, not every conceivable failure.",{"type":55,"tag":440,"props":885,"children":886},{},[887,892],{"type":55,"tag":69,"props":888,"children":889},{},[890],{"type":60,"value":891},"The output is a ranked list of named failure modes from traces you read",{"type":60,"value":893}," — that artifact is what\nmakes the next step (fix, prioritize, or eval) obvious.",{"type":55,"tag":440,"props":895,"children":896},{},[897,902],{"type":55,"tag":69,"props":898,"children":899},{},[900],{"type":60,"value":901},"Hand back linked examples, then let the user steer.",{"type":60,"value":903}," Don't stop at a categorical table. Give one or\ntwo resolvable trace links per mode unprompted, ask the user to eyeball a couple.",{"items":905,"total":1003},[906,920,932,944,957,970,986],{"slug":907,"name":907,"fn":908,"description":909,"org":910,"tags":911,"stars":23,"repoUrl":24,"updatedAt":919},"analyzing-expensive-users","analyze expensive users in AI observability","Analyze the most expensive users in AI observability and explain why they cost so much. Use when the user asks about top spenders, expensive users, per-user LLM cost, user-level cost drivers, or patterns behind high AI observability spend.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[912,914,917,918],{"name":913,"slug":31,"type":15},"Analytics",{"name":915,"slug":916,"type":15},"Cost Optimization","cost-optimization",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-07-28T05:34:11.117757",{"slug":921,"name":921,"fn":922,"description":923,"org":924,"tags":925,"stars":23,"repoUrl":24,"updatedAt":931},"auditing-endpoints","audit PostHog project endpoints","Audit every endpoint in a PostHog project for staleness, failed materialisations, and unused materialised versions. Use when the user asks \"what endpoints can I clean up?\", \"are any of my endpoints broken?\", \"which materialised versions are still being called?\", or wants a one-shot cleanup pass over the Endpoints product. Produces a prioritised report grouped by issue type, with recommended actions but does not modify anything without explicit confirmation.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[926,927,930],{"name":913,"slug":31,"type":15},{"name":928,"slug":929,"type":15},"Audit","audit",{"name":9,"slug":8,"type":15},"2026-06-08T08:08:33.693989",{"slug":933,"name":933,"fn":934,"description":935,"org":936,"tags":937,"stars":23,"repoUrl":24,"updatedAt":943},"auditing-warehouse-source-health","audit PostHog data warehouse source health","Audit the health of a PostHog project's data warehouse sources and syncs — find every broken or degraded source connection, sync schema, and webhook channel. Use when the user asks \"why are my imports failing?\", \"what's broken with my sources?\", \"why is my warehouse data stale?\", or wants a one-shot triage of source\u002Fsync health before deciding where to dig in. Produces a prioritized report grouped by severity, with recommended next steps. For materialized-view health use `auditing-warehouse-view-health`; for a single failing sync use `diagnosing-failed-warehouse-syncs`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[938,939,941,942],{"name":928,"slug":929,"type":15},{"name":940,"slug":33,"type":15},"Data Warehouse",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-06-18T08:22:57.67984",{"slug":945,"name":945,"fn":946,"description":947,"org":948,"tags":949,"stars":23,"repoUrl":24,"updatedAt":956},"auditing-warehouse-view-health","audit PostHog materialized view health","Audit the health of a PostHog project's materialized views (saved queries) — find every failed materialization and flag unused or stale materialized views that cost storage and compute. Use when the user asks \"which of my views are broken?\", \"why is this materialized view failing?\", \"are any of my views wasting compute?\", or wants a one-shot triage of view health. For source\u002Fsync health use `auditing-warehouse-source-health`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[950,951,952,955],{"name":928,"slug":929,"type":15},{"name":940,"slug":33,"type":15},{"name":953,"slug":954,"type":15},"Performance","performance",{"name":9,"slug":8,"type":15},"2026-06-18T08:25:10.936787",{"slug":958,"name":958,"fn":959,"description":960,"org":961,"tags":962,"stars":23,"repoUrl":24,"updatedAt":969},"authoring-error-tracking-alerts","author PostHog error tracking alerts","Author error tracking alerts that fire when an issue is created, reopened, or starts spiking. Use when the user asks to set up error notifications, route exceptions to Slack\u002Fwebhook\u002FLinear, or evaluate which error events are worth alerting on. Covers trigger-event selection, integration choice, dedup against existing alerts, and shipping with the canonical message body shape.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[963,966,967,968],{"name":964,"slug":965,"type":15},"Alerting","alerting",{"name":21,"slug":22,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-06-18T08:24:40.318583",{"slug":971,"name":971,"fn":972,"description":973,"org":974,"tags":975,"stars":23,"repoUrl":24,"updatedAt":985},"authoring-log-alerts","author log alerts in PostHog","Author useful, low-noise log alerts on services in a PostHog project. Use when the user asks to set up alerts for their logs, suggest alerts they should add, or evaluate whether a service is worth monitoring. Covers service triage, baseline characterisation, threshold drafting, back-testing via simulate, and shipping with a notification destination.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[976,977,980,981,984],{"name":913,"slug":31,"type":15},{"name":978,"slug":979,"type":15},"Monitoring","monitoring",{"name":13,"slug":14,"type":15},{"name":982,"slug":983,"type":15},"Operations","operations",{"name":9,"slug":8,"type":15},"2026-07-18T05:10:54.430898",{"slug":987,"name":987,"fn":988,"description":989,"org":990,"tags":991,"stars":23,"repoUrl":24,"updatedAt":1002},"building-workflows","build and edit PostHog workflows","Build, edit, test, enable, and monitor PostHog workflows over MCP. Author the action\u002Fedge graph so it runs and opens cleanly in the visual editor, then change drafts surgically with patch operations. Use when asked to build, set up, automate, change, fix, or debug a workflow, campaign, broadcast, drip sequence, or event-triggered automation in the workflows product.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[992,995,998,999],{"name":993,"slug":994,"type":15},"Automation","automation",{"name":996,"slug":997,"type":15},"MCP","mcp",{"name":9,"slug":8,"type":15},{"name":1000,"slug":1001,"type":15},"Workflow Automation","workflow-automation","2026-07-28T05:34:12.167015",61,{"items":1005,"total":1122},[1006,1013,1019,1026,1033,1040,1048,1055,1069,1084,1094,1112],{"slug":907,"name":907,"fn":908,"description":909,"org":1007,"tags":1008,"stars":23,"repoUrl":24,"updatedAt":919},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1009,1010,1011,1012],{"name":913,"slug":31,"type":15},{"name":915,"slug":916,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":921,"name":921,"fn":922,"description":923,"org":1014,"tags":1015,"stars":23,"repoUrl":24,"updatedAt":931},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1016,1017,1018],{"name":913,"slug":31,"type":15},{"name":928,"slug":929,"type":15},{"name":9,"slug":8,"type":15},{"slug":933,"name":933,"fn":934,"description":935,"org":1020,"tags":1021,"stars":23,"repoUrl":24,"updatedAt":943},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1022,1023,1024,1025],{"name":928,"slug":929,"type":15},{"name":940,"slug":33,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":945,"name":945,"fn":946,"description":947,"org":1027,"tags":1028,"stars":23,"repoUrl":24,"updatedAt":956},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1029,1030,1031,1032],{"name":928,"slug":929,"type":15},{"name":940,"slug":33,"type":15},{"name":953,"slug":954,"type":15},{"name":9,"slug":8,"type":15},{"slug":958,"name":958,"fn":959,"description":960,"org":1034,"tags":1035,"stars":23,"repoUrl":24,"updatedAt":969},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1036,1037,1038,1039],{"name":964,"slug":965,"type":15},{"name":21,"slug":22,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":971,"name":971,"fn":972,"description":973,"org":1041,"tags":1042,"stars":23,"repoUrl":24,"updatedAt":985},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1043,1044,1045,1046,1047],{"name":913,"slug":31,"type":15},{"name":978,"slug":979,"type":15},{"name":13,"slug":14,"type":15},{"name":982,"slug":983,"type":15},{"name":9,"slug":8,"type":15},{"slug":987,"name":987,"fn":988,"description":989,"org":1049,"tags":1050,"stars":23,"repoUrl":24,"updatedAt":1002},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1051,1052,1053,1054],{"name":993,"slug":994,"type":15},{"name":996,"slug":997,"type":15},{"name":9,"slug":8,"type":15},{"name":1000,"slug":1001,"type":15},{"slug":1056,"name":1056,"fn":1057,"description":1058,"org":1059,"tags":1060,"stars":23,"repoUrl":24,"updatedAt":1068},"check-posthog-loading","inspect PostHog SDK loading across URLs","Inspect how the PostHog JavaScript SDK is loaded across a list of URLs. Use to confirm consistent installation across pages, find pages missing the snippet, detect mismatched API keys or hosts between pages, and verify the load method (head snippet vs deferred vs array.js).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1061,1062,1063,1066,1067],{"name":913,"slug":31,"type":15},{"name":21,"slug":22,"type":15},{"name":1064,"slug":1065,"type":15},"Frontend","frontend",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-05-07T05:56:19.828048",{"slug":1070,"name":1070,"fn":1071,"description":1072,"org":1073,"tags":1074,"stars":23,"repoUrl":24,"updatedAt":1083},"consuming-endpoints-from-client-code","integrate PostHog endpoints into client applications","Wire a PostHog endpoint into a client app or SDK. Covers fetching the OpenAPI spec, generating a typed client with openapi-generator or @hey-api\u002Fopenapi-ts, sending the right auth header, shaping the variables payload (HogQL code_name vs insight breakdown property), handling rate-limit and materialised-endpoint error responses. Use when the user says \"how do I call my endpoint\", \"generate a client for this\", or \"what auth header do I use\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1075,1078,1079,1080],{"name":1076,"slug":1077,"type":15},"API Development","api-development",{"name":1064,"slug":1065,"type":15},{"name":9,"slug":8,"type":15},{"name":1081,"slug":1082,"type":15},"SDK","sdk","2026-06-08T08:08:34.929454",{"slug":1085,"name":1085,"fn":1086,"description":1087,"org":1088,"tags":1089,"stars":23,"repoUrl":24,"updatedAt":1093},"copying-endpoints-across-projects","copy PostHog endpoints across projects","Copy a PostHog endpoint (a saved HogQL\u002Finsight query exposed as an API route) to another project in the same organization, or duplicate it under a new name in the same project. Use when the user wants to duplicate an endpoint, promote an endpoint from staging to production, replicate an endpoint's query\u002Fvariables\u002Ffreshness config in another workspace, or clone an endpoint to iterate on it. Unlike feature flags and experiments, endpoints have NO native cross-project copy tool — this skill covers the read-then-recreate flow (endpoint-get then endpoint-create), the active-project switching it requires, name-collision checks, and the safe defaults (land unmaterialised in the target, verify with endpoint-run). Does not cover editing endpoint versions (see managing-endpoint-versions) or authoring a brand-new endpoint from scratch (see creating-an-endpoint).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1090,1091,1092],{"name":1076,"slug":1077,"type":15},{"name":982,"slug":983,"type":15},{"name":9,"slug":8,"type":15},"2026-07-15T05:29:58.442727",{"slug":1095,"name":1095,"fn":1096,"description":1097,"org":1098,"tags":1099,"stars":23,"repoUrl":24,"updatedAt":1111},"creating-ai-subscription","schedule recurring AI-generated PostHog reports","Create a recurring AI-generated PostHog report — schedule a free-text prompt to run on a cron, with the LLM-synthesized markdown delivered to email or Slack on each tick. Use when the user wants a recurring AI summary of X on any cadence (daily, weekly, monthly, yearly) rather than a one-off report. (To attach an AI summary to an existing insight\u002Fdashboard subscription instead of a free-text prompt, see `managing-subscriptions` and its `summary_enabled` option.)\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1100,1101,1104,1105,1108],{"name":993,"slug":994,"type":15},{"name":1102,"slug":1103,"type":15},"Email","email",{"name":9,"slug":8,"type":15},{"name":1106,"slug":1107,"type":15},"Reporting","reporting",{"name":1109,"slug":1110,"type":15},"Slack","slack","2026-06-09T07:32:27.935712",{"slug":1113,"name":1113,"fn":1114,"description":1115,"org":1116,"tags":1117,"stars":23,"repoUrl":24,"updatedAt":1121},"creating-an-endpoint","create PostHog API endpoints","Create a PostHog endpoint with the right shape on the first try — covers query kind choice, name conventions, what to expose as variables (HogQL code_name vs insight breakdown), data_freshness_seconds, and whether to materialise on day one. Use when the user says \"create an endpoint\", \"expose this query as an API\", \"turn this insight into an endpoint\", or asks for help structuring a new endpoint. Steers away from common mistakes: materialising a query with cohort breakdowns or compare mode, inline-only variables on a materialised endpoint, unbounded date ranges, ambiguous names.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1118,1119,1120],{"name":913,"slug":31,"type":15},{"name":1076,"slug":1077,"type":15},{"name":9,"slug":8,"type":15},"2026-06-08T08:08:29.624498",231]