MCPInstall

exploring-llm-clusters

by posthog OfficialAI & Agents

Investigate AI observability clusters — understand usage patterns in AI/LLM traffic, compare cluster behavior, compute cost/latency metrics, and drill into individual traces within clusters.

Installs
228
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/posthog/ai-plugin --skill exploring-llm-clusters
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads exploring-llm-clusters automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Exploring LLM clusters

Use this skill when investigating AI observability clusters — understanding what patterns exist in your AI/LLM traffic, comparing cluster behavior, and drilling into individual clusters.

Tools

ToolPurpose
posthog:llma-clustering-job-listList clustering job configurations for the team
posthog:llma-clustering-job-getGet a specific clustering job by ID
posthog:execute-sqlQuery cluster run events and compute metrics
posthog:query-llm-traces-listFind traces belonging to a cluster
posthog:query-llm-traceInspect a specific trace in detail

How clustering works

PostHog clusters LLM traces, individual generations, or evaluation events by embedding similarity. A Temporal workflow runs periodically or on-demand, producing cluster events stored as $ai_trace_clusters (trace-level), $ai_generation_clusters (generation-level), or $ai_evaluation_clusters (evaluation-level).

Each cluster event contains:

  • $ai_clustering_run_id — unique run identifier (format: <team_id>_<level>_<YYYYMMDD>_<HHMMSS>[_<job_id>])
  • $ai_clustering_level — "trace", "generation", or "evaluation"
  • $ai_window_start / $ai_window_end — time window of the data that was analyzed
  • $ai_total_items_analyzed — number of traces, generations, or evaluations processed
  • $ai_clusters — JSON array of cluster objects
  • $ai_clustering_params — algorithm parameters used

The analyzed window closes when a run starts, and the cluster event lands once the run finishes. So the cluster event's own timestamp is always after $ai_window_end, by anything from seconds to hours. Use the window only to bound the traces, generations, and evaluations that were analyzed. To find the cluster event itself, filter on $ai_clustering_run_id with a plain recent-time bound.

Cluster object shape (inside $ai_clusters)

{
  "cluster_id": 0,
  "size": 42,
  "title": "User authentication flows",
  "description": "Traces involving login, signup, and token refresh operations",
  "traces": {
    "<trace_or_generation_id>": {
      "distance_to_centroid": 0.123,
      "rank": 0,
      "x": -2.34,
      "y": 1.56,
      "timestamp": "2026-03-28T10:00:00Z",
      "trace_id": "abc-123",
      "generation_id": "gen-456"
    }
  },
  "centroid_x": -2.1,
  "centroid_y": 1.4
}
  • cluster_id: -1 is the noise/outlier cluster (items that didn't fit any cluster)
  • Items in traces are keyed by trace ID (trace-level), generation event UUID (generation-level), or evaluation event UUID (evaluation-level)
  • rank orders items by proximity to centroid (0 = closest)
  • x, y are 2D coordinates for visualization (UMAP/PCA/t-SNE reduced)

Clustering jobs

Each team can have up to 10 clustering jobs. A job defines:

  • name — human-readable label
  • analysis_level — "trace", "generation", or "evaluation"
  • event_filters — property filters scoping which items are included
  • enabled — whether the job runs on schedule

Default jobs named "Default - traces", "Default - generations", and "Default - evaluations" are auto-created and disabled when a custom job is created for the same level.

Workflow: explore clusters

Step 1 — List recent clustering runs

posthog:execute-sql
SELECT
    toString(properties.$ai_clustering_run_id) AS run_id,
    toString(properties.$ai_clustering_level) AS level,
    toString(properties.$ai_clustering_job_id) AS job_id,
    toString(properties.$ai_clustering_job_name) AS job_name,
    toString(properties.$ai_window_start) AS window_start,
    toString(properties.$ai_window_end) AS window_end,
    toFloat64OrNull(toString(properties.$ai_total_items_analyzed)) AS total_items,
    timestamp
FROM events
WHERE event IN ('$ai_trace_clusters', '$ai_generation_clusters', '$ai_evaluation_clusters')
    AND timestamp >= now() - INTERVAL 14 DAY
ORDER BY timestamp DESC
LIMIT 10

Step 2 — Get clusters from a specific run

posthog:execute-sql
SELECT
    toString(properties.$ai_clustering_run_id) AS run_id,
    toString(properties.$ai_clustering_level) AS level,
    toString(properties.$ai_clustering_job_id) AS job_id,
    toString(properties.$ai_clustering_job_name) AS job_name,
    toString(properties.$ai_window_start) AS window_start,
    toString(properties.$ai_window_end) AS window_end,
    toFloat64OrNull(toString(properties.$ai_total_items_analyzed)) AS total_items,
    properties.$ai_clusters AS clusters,
    properties.$ai_clustering_params AS params,
    timestamp
FROM events
WHERE event IN ('$ai_trace_clusters', '$ai_generation_clusters', '$ai_evaluation_clusters')
    AND timestamp >= now() - INTERVAL 14 DAY
    AND toString(properties.$ai_clustering_run_id) = '<run_id>'
ORDER BY timestamp DESC
LIMIT 1

Keep the lookback bound wide enough to cover the timestamp Step 1 reported for the run. Never bound this query with $ai_window_start / $ai_window_end. The cluster event is emitted after the window closes, so those bounds return zero rows.

The clusters field is a JSON array. Parse it to see cluster titles, sizes, descriptions, optional metrics, and each cluster's traces map.

Important: The clusters JSON can be very large (thousands of trace, generation, or evaluation IDs with coordinates). When the result is too large for inline display, it auto-persists to a file. Use print_clusters.py from scripts/ to get a readable summary.

Step 3 — Compute metrics for clusters

For trace-level clusters, compute cost/latency/token metrics:

posthog:execute-sql
SELECT
    properties.$ai_trace_id as trace_id,
    sum(toFloat(properties.$ai_total_cost_usd)) as total_cost,
    max(toFloat(properties.$ai_latency)) as latency,
    sum(toInt(properties.$ai_input_tokens)) as input_tokens,
    sum(toInt(properties.$ai_output_tokens)) as output_tokens,
    countIf(properties.$ai_is_error = 'true') as error_count
FROM events
WHERE event IN ('$ai_generation', '$ai_embedding', '$ai_span')
    AND timestamp >= parseDateTimeBestEffort('<window_start>')
    AND timestamp <= parseDateTimeBestEffort('<window_end>')
    AND properties.$ai_trace_id IN ('<trace_id_1>', '<trace_id_2>', ...)
GROUP BY trace_id

For generation-level clusters, match by event UUID:

posthog:execute-sql
SELECT
    toString(uuid) as generation_id,
    toFloat(properties.$ai_total_cost_usd) as cost,
    toFloat(properties.$ai_latency) as latency,
    toInt(properties.$ai_input_tokens) as input_tokens,
    toInt(properties.$ai_output_tokens) as output_tokens,
    if(properties.$ai_is_error = 'true', 1, 0) as is_error
FROM events
WHERE event = '$ai_generation'
    AND timestamp >= parseDateTimeBestEffort('<window_start>')
    AND timestamp <= parseDateTimeBestEffort('<window_end>')
    AND uuid IN ('<gen_uuid_1>', '<gen_uuid_2>', ...)

For evaluation-level clusters, first check each cluster's metrics field from $ai_clusters (for example pass rate, N/A rate, dominant evaluator name, and average judge cost). When you need individual evaluation rows, match by event UUID:

posthog:execute-sql
SELECT
    toString(uuid) AS evaluation_id,
    toString(properties.$ai_trace_id) AS trace_id,
    toString(properties.$ai_target_event_id) AS generation_id,
    toString(properties.$ai_evaluation_name) AS evaluation_name,
    toString(properties.$ai_evaluation_result) AS evaluation_result,
    toString(properties.$ai_evaluation_reasoning) AS evaluation_reasoning,
    toFloatOrNull(toString(properties.$ai_total_cost_usd)) AS judge_cost,
    timestamp
FROM events
WHERE event = '$ai_evaluation'
    AND timestamp >= parseDateTimeBestEffort('<window_start>')
    AND timestamp <= parseDateTimeBestEffort('<window_end>')
    AND uuid IN ('<eval_uuid_1>', '<eval_uuid_2>', ...)

Step 4 — Drill into specific traces

Once you've identified interesting clusters, use the trace tools to inspect individual traces:

posthog:query-llm-trace
{
  "traceId": "<trace_id_from_cluster>",
  "dateRange": {"date_from": "<window_start>", "date_to": "<window_end>"}
}

When you need message content

Use events for cluster events, IDs, cost/latency/token metrics, and evaluation rows. Do not query events.properties.$ai_input, $ai_output, or $ai_output_choices when you need user messages or full model inputs/outputs — those heavy fields live on posthog.ai_events.

For a few representative examples, prefer query-llm-trace; it reads posthog.ai_events for you and returns the full event tree. For batch extraction, first get the trace IDs from the cluster, then query posthog.ai_events anchored on trace_id:

posthog:execute-sql
SELECT
    trace_id,
    timestamp,
    span_id,
    event,
    model,
    input,
    output_choices
FROM posthog.ai_events
WHERE trace_id IN ('<trace_id_1>', '<trace_id_2>', ...)
ORDER BY trace_id, timestamp

posthog.ai_events has a shorter retention window than events; older clusters may still have metadata and metrics but no message content. For the full $ai_* event schema, load the exploring-llm-traces skill.

Investigation patterns

"What kinds of LLM usage do we have?"

  1. List recent clustering runs (Step 1)
  2. Load the latest run's clusters (Step 2)
  3. Review cluster titles and descriptions — each represents a distinct usage pattern
  4. Compare cluster sizes to understand traffic distribution

"Which cluster is most expensive / slowest?"

  1. Load clusters from a run (Step 2)
  2. Extract trace IDs from each cluster
  3. Compute metrics per cluster (Step 3)
  4. Aggregate: avg(cost), avg(latency), sum(cost) per cluster
  5. Compare across clusters

"What's in this cluster?"

  1. Load the cluster's traces (from the traces field)
  2. Sort by rank (closest to centroid = most representative)
  3. Inspect the top 3-5 traces via query-llm-trace to understand the pattern
  4. Check the cluster title and description for the AI-generated summary

"Are there error-heavy clusters?"

  1. Compute metrics (Step 3) with error_count
  2. Calculate error rate per cluster: items_with_errors / total_items
  3. Focus on clusters with high error rates
  4. Drill into errored traces to find root causes

"How do clusters compare across runs?"

  1. List multiple runs (Step 1)
  2. Load clusters from each run
  3. Compare cluster titles — similar titles across runs indicate stable patterns
  4. Track cluster size changes to detect shifts in traffic patterns

Constructing UI links

  • Clusters overview: https://app.posthog.com/ai-observability/clusters
  • Specific run: https://app.posthog.com/ai-observability/clusters/<url_encoded_run_id>
  • Cluster detail: https://app.posthog.com/ai-observability/clusters/<url_encoded_run_id>/<cluster_id>

Always surface these links so the user can verify visually in the PostHog UI.

Tips

  • Always set a time range in SQL queries — cluster events without time bounds are slow
  • Bound a search for a cluster event by when it was emitted, not by the window it analyzed — a run's $ai_window_end is earlier than the event's own timestamp
  • Start with run listing to orient, then drill into specific clusters
  • Cluster titles and descriptions are AI-generated summaries — verify by inspecting traces
  • The noise cluster (cluster_id: -1) contains outliers that didn't fit any pattern
  • Use llma-clustering-job-list to understand what clustering configs are active
  • Trace IDs in clusters can be used directly with query-llm-trace for deep inspection
  • Message content lives on posthog.ai_events, not events.properties; use query-llm-trace unless you need custom batch SQL
  • For large clusters, inspect the top-ranked traces (closest to centroid) for representative examples

FAQ

What does the exploring-llm-clusters skill do?

Investigate AI observability clusters — understand usage patterns in AI/LLM traffic, compare cluster behavior, compute cost/latency metrics, and drill into individual traces within clusters.

How do I install exploring-llm-clusters?

Run npx skills add https://github.com/posthog/ai-plugin --skill exploring-llm-clusters in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/exploring-llm-clusters/ (personal) or .claude/skills/exploring-llm-clusters/ (project).

Which AI agents can use exploring-llm-clusters?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is exploring-llm-clusters safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains exploring-llm-clusters?

It is published by posthog in posthog/ai-plugin, and it is an official skill from the maker of the technology it covers. It has 228 recorded installs.

More from posthog/ai-plugin

View all →

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.

OfficialData & Databases593 installs

instrument-feature-flags

posthog/ai-plugin

Open the skill to read its SKILL.md instructions.

Official473 installs

Identify stale feature flags in a PostHog project and clean up the code that checks them. Use when the user wants to find, audit, or remove unused, fully rolled out, or abandoned feature flags, run a feature flag hygiene review or a weekly cleanup, reduce feature flag tech debt, or asks "which flags can I remove?". When the agent can read and edit a repository it performs the code cleanup itself: tested local changes, and one draft PR per flag when the user authorizes publishing. Agents without repository access generate a tailored cleanup prompt instead. Covers staleness detection, dependency checking, retained-path rules, and the code-first ordering. This skill does not archive or otherwise change a flag in PostHog.

OfficialCode Quality & Workflow397 installs

Audit PostHog experiments and feature flags for configuration issues, staleness, and best-practice violations. Read when the user asks to audit, health-check, or review experiments or feature flags, check flag hygiene, or verify experiment setup.

OfficialSecurity395 installs

querying-posthog-data

posthog/ai-plugin

Explains how to query PostHog data, defaulting to typed runners for supported product analytics. Read it before you write HogQL/SQL. Also read it before you call execute-sql against PostHog. Use it to find or aggregate PostHog entities. These entities include insights, dashboards, cohorts, feature flags, experiments, surveys, hog flows, warehouse data, and persons. Use it for trends, funnels, retention, lifecycle, paths, stickiness, web analytics, error tracking, logs, sessions, and LLM traces. Before you calculate a governed business or telemetry measure, check system.informationschema.metrics for an approved definition. Examples include MRR, activation, billable usage, active organizations, and failure rates. Use the approved definition before you derive a measure from raw events or use a typed domain tool. It also covers HogQL differences, system table schemas, functions, query examples, and schema discovery.

OfficialData & Databases384 installs

creating-experiments

posthog/ai-plugin

Guides agents through experiment creation: reading the project's setup with experiment-setup-context, defining the hypothesis, configuring rollout and bucketing, setting up analytics and running time, and reporting which choices are guesses. Delegates rollout decisions to configuring-experiment-rollout and metric setup to configuring-experiment-analytics. TRIGGER when: user asks to create a new experiment or A/B test, OR when you are about to call experiment-create. DO NOT TRIGGER when: user is updating an existing experiment, managing lifecycle, or only browsing experiments.

OfficialData & Databases368 installs

Popular ai & agents skills

View category →

google-agents-cli-publish

google/agents-cli

This skill should be used when the user wants to "publish an agent", "publish my ADK agent", "register an agent with Gemini", "publish to Gemini" (formerly Gemini Enterprise), or needs guidance on the agents-cli publish gemini command. Also use when the user wants to "manage agents in Agent Registry", "list/update/delete registered agents", or "register an MCP server". Covers ADK vs A2A registration modes, programmatic and interactive usage, flag reference, auto-detection from deployment metadata, Agent Registry fleet management, and troubleshooting. Part of the agents-cli skills suite. Do NOT use for deployment (use google-agents-cli-deploy).

AI & Agents513.9K installs

google-agents-cli-eval

google/agents-cli

This skill should be used when the user wants to "run an evaluation", "evaluate my agent", "evaluate my ADK agent", "write an eval dataset", "analyze eval failures", "compare eval results", "optimize agent", or needs guidance on the Gemini platform eval methodology and the Quality Flywheel. Covers eval metrics, dataset schema, LLM-as-judge scoring, and common failure causes. Applies to any agents-cli project, whatever framework the agent is written in. Do NOT use for agent API code patterns (ADK: use google-agents-cli-adk-code), deployment (use google-agents-cli-deploy), or project scaffolding (use google-agents-cli-scaffold).

AI & Agents513.5K installs

skill-creator

anthropics/skills

Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.

OfficialAI & Agents416.4K installs

codex-pet

prime-skills/runcomfy-agent-skills

Codex Pet generator on RunComfy. Build a Codex-compatible Codex Pet spritesheet.webp + pet.json from a single reference image, drop it into ${CODEXHOME:-$HOME/.codex}/pets/ / and Codex picks it up as a custom Codex Pet next to the 8 built-ins. This skill produces the exact Codex Pet atlas Codex expects (1536x1872 PNG/WebP, 8 cols x 9 rows, 192x208 cells, 9 animation states — idle, running-right, running-left, waving, jumping, failed, waiting, running, review). Calls OpenAI GPT Image 2 edit ONCE via the local RunComfy CLI as runcomfy run openai/gpt-image-2/edit to produce a canonical Codex Pet pose, then assembles all 9 animation rows programmatically with ImageMagick micro-transforms — no Codex Pro, no $imagegen, no OPENAIAPIKEY required, only RUNCOMFYTOKEN. Triggers on "codex pet", "create codex pet", "make codex pet", "hatch codex pet", "/hatch image", "desktop pet codex", "codex pets", "spritesheet.webp", or any explicit ask to build a custom pet for OpenAI Codex.

AI & Agents402.1K installs

full-output-enforcement

leonxlnx/taste-skill

Overrides default LLM truncation behavior. Enforces complete code generation, bans placeholder patterns, and handles token-limit splits cleanly. Apply to any task requiring exhaustive, unabridged output.

AI & Agents401K installs

executing-plans

obra/superpowers

Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available

AI & Agents245.7K installs